/* Global styles (extracted from the original design) */
*{box-sizing:border-box}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion: reduce){html{scroll-behavior:auto}}
body{margin:0}
::selection{background:#9e2b25;color:#f3efe7}
#styleDrawer .sd-sec{margin-bottom:24px}
#styleDrawer .sd-sec h3{font-family:'Inter',sans-serif;font-size:10.5px;font-weight:600;letter-spacing:.15em;text-transform:uppercase;color:#9b938a;margin:0 0 10px}
#styleDrawer #sd-origin{font-family:'Source Serif 4',serif;font-size:15.5px;font-weight:600;color:#14110f;margin:0;line-height:1.5}
#styleDrawer #sd-desc p{font-family:'Source Serif 4',serif;font-size:15px;line-height:1.64;color:#33302b;margin:0 0 12px}
#styleDrawer #sd-desc p.dsub{font-family:'Spectral',serif;font-weight:700;font-size:15px;color:#14110f;margin:18px 0 6px}
#styleDrawer #sd-desc ul{margin:6px 0 14px;padding-left:20px}
#styleDrawer #sd-desc li{font-family:'Source Serif 4',serif;font-size:14.5px;line-height:1.55;color:#33302b;margin:5px 0}
#styleDrawer .acc{border:1px solid #e4e0d8;border-radius:10px;overflow:hidden}
#styleDrawer .acc-item + .acc-item{border-top:1px solid #e4e0d8}
#styleDrawer .acc-h{width:100%;text-align:left;background:#faf8f4;border:none;cursor:pointer;padding:13px 15px;font-family:'Spectral',serif;font-size:14.5px;font-weight:600;color:#14110f;display:flex;justify-content:space-between;align-items:center;gap:10px}
#styleDrawer .acc-h:hover{background:#f2ede5}
#styleDrawer .acc-h .ar{color:#b6ada1;font-size:11px;transition:transform .18s;flex:0 0 auto}
#styleDrawer .acc-item.open .acc-h .ar{transform:rotate(90deg)}
#styleDrawer .acc-item.open .acc-h{color:var(--rc,#9e2b25)}
#styleDrawer .acc-b{display:none;padding:6px 16px 16px}
#styleDrawer .acc-item.open .acc-b{display:block}
#styleDrawer .acc-b p{font-family:'Source Serif 4',serif;font-size:14px;line-height:1.62;color:#33302b;margin:0 0 11px}
#styleDrawer .acc-b ul{margin:6px 0 12px;padding-left:20px}
#styleDrawer .acc-b li{font-family:'Source Serif 4',serif;font-size:14px;line-height:1.55;color:#33302b;margin:5px 0}
#styleDrawer .acc-b a{color:#9e2b25;word-break:break-word}
#styleDrawer .rel a{display:inline-flex;gap:6px;align-items:baseline;margin:0 6px 7px 0;font-family:'Inter',sans-serif;font-size:12.5px;background:#fff;border:1px solid #e4e0d8;border-radius:8px;padding:6px 11px;cursor:pointer;color:#14110f;text-decoration:none;transition:border-color .14s}
#styleDrawer .rel a:hover{border-color:#9e2b25}
#styleDrawer .rel a small{color:#9b938a}
#styleDrawer .src div{font-family:'Inter',sans-serif;font-size:12px;color:#5c554d;line-height:1.5;padding:7px 0;border-top:1px dashed #e4e0d8}
#styleDrawer .src div:first-child{border-top:none;padding-top:0}
#styleDrawer #sd-photo{font-family:'Inter',sans-serif;font-size:12px;color:#9b938a;font-style:italic;margin:0;line-height:1.5}
#styleFilterBar button[data-fg]:hover{filter:brightness(.96)}
#treeSvg .tnode{transition:opacity .22s ease}
#treeSvg .tnbg{transition:stroke .15s ease,stroke-width .15s ease}
#treeSvg .tedge{transition:opacity .22s ease,stroke .2s ease,stroke-width .2s ease}
#treeSvg .tnode:hover .tnbg{filter:drop-shadow(0 5px 13px rgba(20,17,15,.16))}
#styleSearch:focus{border-color:#9e2b25}
/* ===== RESPONSIVE / MOBILE ===== */
[data-mobile-toggle]{display:none}
@media (max-width:880px){
  [data-article-grid]{grid-template-columns:minmax(0,1fr)!important;gap:0!important}
  /* Decorative chapter glyphs bleed a few px past the article column's right edge
     — harmless in the wide desktop margin, but past the viewport on a narrow
     phone column, causing a sliver of horizontal page scroll. Clip the bleed at
     the column (clip, not hidden: no scroll container, vertical/ sticky intact;
     the tables/timelines keep their own inner overflow-x:auto scrollers). */
  [data-article-grid]{overflow-x:clip}
  [data-toc-rail]{display:none!important}
  #eraRibbon div:has(> [data-era]){flex-wrap:wrap!important}
  #eraRibbon [data-era]{flex:1 1 84px!important;min-width:84px!important}
  /* max-height only: the pane's height is measured to the map, so a floor here would re-open the gap */
  #treeScroll{max-height:calc(100dvh - 98px)!important}
  [data-tree-stage]{padding-bottom:44px!important}
  #treeHint [data-hint-full]{display:none!important}
  #treeHint [data-hint-short]{display:inline!important}
}
@media (max-width:720px){
  [data-desktop-menu]{display:none!important}
  [data-mobile-toggle]{display:inline-flex!important}
  [data-nav-inner]{padding:0 16px!important;gap:12px!important}
  [data-hero='home']{padding:74px 22px 66px!important}
  [data-hero='article']{padding:58px 22px 40px!important}
  [data-hero='styles']{padding:60px 22px 46px!important}
  #treeScroll{max-height:calc(100dvh - 84px)!important}
  [data-tree-stage]{max-width:100%!important;padding-left:16px!important;padding-right:16px!important;padding-bottom:16px!important}
}
@media (min-width:721px){
  [data-mobile-panel]{display:none!important}
  /* Two selectors, both !important: the plain one (1,1,1) out-weighs the base
     `#mobilePanel.oa-mobmenu{display:flex}` (1,1,0) for the menu-open case (e.g.
     resized from mobile with the menu still open), and the `[hidden]` one
     (1,2,1) beats the later `#mobilePanel.oa-mobmenu[hidden]{display:flex}`
     (1,2,0) for the normal closed case. Without both, the overlay leaks onto
     desktop as a fixed full-viewport node. */
  html #mobilePanel.oa-mobmenu,
  html #mobilePanel.oa-mobmenu[hidden]{display:none!important}
}
@media (max-width:480px){
  [data-hero='home']{padding:58px 20px 52px!important}
}
/* Phone-only: two volume widgets overflow a narrow article column horizontally.
   (1) the "term | definition" glossary rows use a fixed 230px first track, which
   can't shrink — stack them; (2) the volume-progress stepper has three
   min-width:120px buttons that can't fit one phone row — let them shrink. */
@media (max-width:560px){
  [data-article-grid] [style*="grid-template-columns:230px 1fr"]{grid-template-columns:1fr!important;gap:3px 0!important}
  .art-prog-btn{min-width:0!important}
  .art-prog{padding-left:15px!important;padding-right:15px!important}
}

/* --- view switching (replaces the React sc-if rendering) --- */
.dc-view{display:none}
.dc-view.active{display:block}
.dc-dropdown[hidden],[data-mobile-panel][hidden]{display:none!important}

/* ============================================================
   §mobmenu — the full-page mobile menu
   ------------------------------------------------------------
   script.js owns open/close by toggling #mobilePanel[hidden].
   The overlay never uses display:none for its own visibility
   (that would kill the transitions); instead [hidden] drives an
   opacity/visibility close state, and the id+!important below
   out-specifies the UA `[hidden]{display:none}` rule. The
   hamburger in the sticky bar sits ABOVE this overlay (nav is
   z-index 80; the overlay is 78) and morphs into an ✕.
   ============================================================ */
#mobilePanel.oa-mobmenu{
  position:fixed; inset:0; z-index:78;
  display:flex; flex-direction:column; justify-content:center;
  padding:calc(env(safe-area-inset-top) + 72px) 0 max(env(safe-area-inset-bottom), 28px);
  background:
    radial-gradient(120% 90% at 80% -10%, color-mix(in srgb, var(--color-accent) 7%, transparent), transparent 60%),
    var(--color-bg);
  opacity:1; visibility:visible;
  transition:opacity .5s var(--ease-io), visibility 0s;
  overflow-y:auto; overscroll-behavior:contain; -webkit-overflow-scrolling:touch;
}
#mobilePanel.oa-mobmenu[hidden]{
  display:flex!important;              /* keep in layout so the fade can run */
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .38s var(--ease-io), visibility 0s .38s;
}
html[data-theme="dark"] #mobilePanel.oa-mobmenu{
  background:
    radial-gradient(120% 90% at 80% -10%, color-mix(in srgb, var(--d-accent) 12%, transparent), transparent 60%),
    var(--d-bg);
}

/* the giant, barely-there character behind the links */
.oa-mobmenu-wm{
  position:absolute; right:-6vw; bottom:-4vh; z-index:0;
  font-family:'Noto Serif TC',serif; font-weight:900;
  font-size:min(74vw,520px); line-height:.8; letter-spacing:-.04em;
  color:var(--color-text); opacity:.035; pointer-events:none; user-select:none;
  white-space:nowrap;
  transform:translateY(24px); transition:transform 1s var(--ease-io) .06s, opacity 1s var(--ease-io) .06s;
}
html[data-theme="dark"] .oa-mobmenu-wm{ color:var(--d-text); opacity:.05; }
#mobilePanel.oa-mobmenu[hidden] .oa-mobmenu-wm{ transform:translateY(48px); opacity:0; }

.oa-mobmenu-sheet{
  position:relative; z-index:1;
  width:100%; max-width:520px; margin:0 auto;
  padding:0 30px; display:flex; flex-direction:column;
}
.oa-mobmenu-eyebrow{
  font-family:'Inter',sans-serif; font-size:11px; font-weight:600;
  letter-spacing:.22em; text-transform:uppercase;
  color:var(--color-muted); margin-bottom:26px;
  opacity:0; transform:translateY(12px);
  transition:opacity .5s var(--ease-io), transform .5s var(--ease-io);
}
html[data-theme="dark"] .oa-mobmenu-eyebrow{ color:var(--d-text-3); }

.oa-mobmenu-nav{ display:flex; flex-direction:column; gap:2px; }
.oa-mobmenu-link{
  position:relative; display:flex; align-items:center; gap:16px;
  width:100%; text-align:left; background:none; border:none; cursor:pointer;
  padding:10px 0; margin:0;
  font-family:'Spectral',serif; font-weight:600; color:var(--color-text);
  opacity:0; transform:translateY(20px);
  transition:opacity .55s var(--ease-io), transform .55s var(--ease-io), color .25s ease;
}
html[data-theme="dark"] .oa-mobmenu-link{ color:var(--d-text); }
.oa-mobmenu-i{
  font-family:'Inter',sans-serif; font-size:12px; font-weight:600;
  letter-spacing:.08em; color:var(--color-accent);
  min-width:24px; flex:0 0 auto;
}
html[data-theme="dark"] .oa-mobmenu-i{ color:var(--d-accent); }
.oa-mobmenu-w{ flex:1 1 auto; font-size:clamp(28px,9vw,40px); line-height:1.05; }
.oa-mobmenu-arr{
  font-family:'Inter',sans-serif; font-size:20px; color:var(--color-muted);
  align-self:center; transform:translateX(-6px); opacity:0;
  transition:transform .3s var(--ease-io), opacity .3s var(--ease-io), color .25s ease;
}
html[data-theme="dark"] .oa-mobmenu-arr{ color:var(--d-text-3); }
.oa-mobmenu-link:hover,.oa-mobmenu-link:focus-visible{ color:var(--color-accent); outline:none; }
html[data-theme="dark"] .oa-mobmenu-link:hover,
html[data-theme="dark"] .oa-mobmenu-link:focus-visible{ color:var(--d-accent); }
.oa-mobmenu-link:hover .oa-mobmenu-arr,
.oa-mobmenu-link:focus-visible .oa-mobmenu-arr{ transform:translateX(0); opacity:1; color:inherit; }

/* theme.js appends .theme-toggle-row into the sheet; give it room and stagger */
.oa-mobmenu-sheet .theme-toggle-row{
  margin-top:22px; padding:14px 0 0; border-top:none;
  font-family:'Inter',sans-serif;
  opacity:0; transform:translateY(20px);
  transition:opacity .55s var(--ease-io), transform .55s var(--ease-io);
}

/* the open state — items settle in, staggered */
#mobilePanel.oa-mobmenu:not([hidden]) .oa-mobmenu-wm{ transform:translateY(0); }
#mobilePanel.oa-mobmenu:not([hidden]) .oa-mobmenu-eyebrow,
#mobilePanel.oa-mobmenu:not([hidden]) .oa-mobmenu-link,
#mobilePanel.oa-mobmenu:not([hidden]) .theme-toggle-row{ opacity:1; transform:translateY(0); }
#mobilePanel.oa-mobmenu:not([hidden]) .oa-mobmenu-eyebrow{ transition-delay:.06s; }
#mobilePanel.oa-mobmenu:not([hidden]) .oa-mobmenu-link:nth-child(1){ transition-delay:.12s; }
#mobilePanel.oa-mobmenu:not([hidden]) .oa-mobmenu-link:nth-child(2){ transition-delay:.19s; }
#mobilePanel.oa-mobmenu:not([hidden]) .oa-mobmenu-link:nth-child(3){ transition-delay:.26s; }
#mobilePanel.oa-mobmenu:not([hidden]) .theme-toggle-row{ transition-delay:.33s; }

/* the hamburger → ✕ morph, driven by the panel's open state */
[data-mobile-toggle] span{ transition:transform .34s var(--ease-io), opacity .2s ease; }
body:has(#mobilePanel.oa-mobmenu:not([hidden])) [data-mobile-toggle]{ border-color:var(--color-accent); }
body:has(#mobilePanel.oa-mobmenu:not([hidden])) [data-mobile-toggle] span:nth-child(1){ transform:translateY(6px) rotate(45deg); }
body:has(#mobilePanel.oa-mobmenu:not([hidden])) [data-mobile-toggle] span:nth-child(2){ opacity:0; }
body:has(#mobilePanel.oa-mobmenu:not([hidden])) [data-mobile-toggle] span:nth-child(3){ transform:translateY(-6px) rotate(-45deg); }

@media (prefers-reduced-motion: reduce){
  #mobilePanel.oa-mobmenu,
  #mobilePanel.oa-mobmenu *{ transition:none!important; }
  .oa-mobmenu-wm,.oa-mobmenu-eyebrow,.oa-mobmenu-link,
  .oa-mobmenu-sheet .theme-toggle-row{ opacity:1; transform:none; }
}

/* ============================================================
   THE HEAD — the mounting of a hanging scroll
   ============================================================
   Two moving parts, both driven by html[data-scrolled] (set in script.js):

   1. The head condenses as soon as the reader leaves the top. The Chinese
      byline 歐陽文庫 does not merely fade — it collapses its own height, so
      the wordmark settles into the centre of a shorter bar instead of
      leaving a hole where the byline was. The mark shrinks with it.
   2. The mark is a struck medallion: two faces on a shared 3-D plane with a
      real edge between them, so a click turns it on its vertical axis like a
      pendant on a cord rather than spinning it flat like a sticker.

   The mobile drawer and #treeScroll still subtract a fixed 66px/98px/84px
   rather than --oa-nav-h. That is on purpose: both are max-height CAPS, so
   against the condensed 56px bar they simply come out ~10px conservative —
   whereas feeding them a value that changes on scroll would animate the height
   of the styles map while the reader is scrolling it. */
:root{
  --oa-nav-h:66px;          /* bar height at rest */
  --oa-mark-h:47px;         /* medallion height at rest */
  /* Thickness and perspective are kept as ratios of the mark, not fixed px, so
     the medallion reads the same when the head condenses and it drops to 38px.
     6.4x height was picked by eye against the real mark: shorter and the tile
     keystones, longer and the turn flattens into a sticker. */
  --oa-mark-t:calc(var(--oa-mark-h) * .034);   /* half the thickness */
  --oa-mark-persp:calc(var(--oa-mark-h) * 6.4);
  --oa-mark-edge:#9c2c17;   /* the mark's own deep tone — set per colour in script.js */
  --oa-mark-edge-lit:#ea6a44;
  --oa-ease:cubic-bezier(.32,.72,0,1);
  /* The turn is deliberately symmetric: it reaches 90° — edge-on — at exactly
     half its duration, which is what lets the cast shadow below pinch in step
     with it off a plain 50% keyframe. Reach for an asymmetric curve here and
     the two drift apart. */
  --oa-turn-ease:cubic-bezier(.65,0,.35,1);
  --oa-turn-dur:.8s;
}
html[data-scrolled]{--oa-nav-h:56px;--oa-mark-h:38px}

[data-nav-inner]{height:var(--oa-nav-h);transition:height .34s var(--oa-ease)}
[data-site-header]{transition:box-shadow .35s var(--oa-ease)}
html[data-scrolled] [data-site-header]{box-shadow:0 14px 30px -26px rgba(20,17,15,.75)}

#brandLogoSub{
  display:block;overflow:hidden;pointer-events:none;
  max-height:2rem;opacity:1;margin-top:3px;
  transition:max-height .34s var(--oa-ease),opacity .22s ease,margin-top .34s var(--oa-ease);
}
html[data-scrolled] #brandLogoSub{max-height:0;opacity:0;margin-top:0}

/* --- the medallion ----------------------------------------------------- */
.oa-medallion{
  position:relative;display:block;flex:0 0 auto;
  height:var(--oa-mark-h);
  width:calc(var(--oa-mark-h) * 340 / 520);   /* the logo's own proportion */
  perspective:var(--oa-mark-persp);
  transition:height .34s var(--oa-ease),width .34s var(--oa-ease);
}
/* the contact shadow: the pendant sits above the paper rather than on it */
.oa-medallion::before{
  content:"";position:absolute;z-index:-1;
  left:6%;right:6%;bottom:-2px;height:6px;
  background:radial-gradient(50% 50% at 50% 50%,rgba(20,17,15,.34),transparent 70%);
}
/* Two turns compose here, each with its own weight: the tilt is the quick lean
   toward the reader on hover, the inner is the slow half-turn on click. */
.oa-medallion-tilt{
  position:absolute;inset:0;
  transform-style:preserve-3d;
  transition:transform .24s cubic-bezier(.3,.6,.3,1);
}
.oa-medallion-inner{
  position:absolute;inset:0;
  transform-style:preserve-3d;
  transform:rotateY(var(--oa-turn,0deg));
  transition:transform var(--oa-turn-dur) var(--oa-turn-ease);
}
.oa-face{
  position:absolute;inset:0;
  border-radius:calc(var(--oa-mark-h) * 48 / 520);  /* the SVG's own corner, to scale */
  backface-visibility:hidden;
  overflow:hidden;
}
.oa-face img{display:block;width:100%;height:100%}
/* the struck bevel. An inset shadow on the <img> itself would paint under the
   image, so the rim rides on top as its own layer. */
.oa-face::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  box-shadow:
    inset 0 .7px .7px rgba(255,255,255,.5),
    inset 0 -.7px .7px rgba(20,17,15,.4),
    inset 0 0 0 .5px rgba(20,17,15,.22);
}
.oa-face-front{transform:translateZ(var(--oa-mark-t))}
.oa-face-back{transform:rotateY(180deg) translateZ(var(--oa-mark-t))}
/* The two rims of metal between the faces. Only the left and right edges are
   ever seen in a turn about the vertical axis — top and bottom stay edge-on to
   the eye — so only those two are built. */
.oa-edge{
  top:4%;bottom:4%;position:absolute;
  width:calc(var(--oa-mark-t) * 2);
  border-radius:1px;
  /* struck metal, never a gap: every stop stays opaque and in the mark's own
     hue, lit at the top where the tile's gradient is lit and deepening down */
  background:linear-gradient(180deg,
    var(--oa-mark-edge-lit),
    var(--oa-mark-edge) 58%,
    color-mix(in srgb,var(--oa-mark-edge) 58%,#14110f));
  /* At rest the mark is face-on and both rims sit edge-on to the eye, so they
     should vanish. They very nearly do — but sub-pixel rounding lets the left
     rim land a hair past the border and paint a permanent hairline there,
     while the right rim rounds inward and stays hidden. The rims only earn
     their keep while the mark actually turns (the click half-turn and the
     hover lean), so they are held invisible at rest and revealed for exactly
     those two states below. This changes nothing about their geometry — only
     when they are painted — so the turn and the lean look identical. */
  opacity:0;
  transition:opacity .2s var(--oa-turn-ease);
}
.oa-edge-l{left:0;transform:translateX(calc(var(--oa-mark-t) * -1)) rotateY(90deg)}
.oa-edge-r{right:0;transform:translateX(var(--oa-mark-t)) rotateY(90deg)}
/* revealed only while the mark is off its resting face: the click half-turn
   (script.js flags .oa-turning for the duration) and the hover/focus lean */
.oa-medallion.oa-turning .oa-edge,
#brandLogoBtn:hover .oa-edge,
#brandLogoBtn:focus-visible .oa-edge{opacity:1}

/* hover: the medallion leans a little toward the reader, as if picked up */
#brandLogoBtn:hover .oa-medallion-tilt,
#brandLogoBtn:focus-visible .oa-medallion-tilt{transform:rotateY(-15deg)}

/* Click: a half-turn onto the other face. script.js re-strikes that face
   before the turn starts, while it is still facing away — so the colour is
   never seen changing, only its result. The turn angle itself is --oa-turn,
   which script.js winds on by 180° per click. */

/* the cast shadow pinches as the medallion goes edge-on and there is almost
   nothing left to cast */
@keyframes oaMedallionCast{
  0%,100%{transform:scaleX(1);opacity:1}
  50%{transform:scaleX(.28);opacity:.45}
}
.oa-medallion.oa-turning::before{animation:oaMedallionCast var(--oa-turn-dur) var(--oa-turn-ease)}

@media (prefers-reduced-motion: reduce){
  /* the head still condenses and the mark still turns to its next colour — it
     just arrives instead of travelling */
  [data-nav-inner],[data-site-header],#brandLogoSub,
  .oa-medallion,.oa-medallion-tilt,.oa-medallion-inner{transition:none}
  .oa-medallion.oa-turning::before{animation:none}
  #brandLogoBtn:hover .oa-medallion-tilt,
  #brandLogoBtn:focus-visible .oa-medallion-tilt{transform:none}
  /* with the lean disabled there is no gap for the rims to fill, so hover must
     not reveal them — otherwise the resting hairline would return on hover */
  #brandLogoBtn:hover .oa-edge,
  #brandLogoBtn:focus-visible .oa-edge{opacity:0}
}

/* Language download dropdown (article PDF, multi-language) */
.dl-lang{position:relative;display:inline-block;font-family:'Inter',sans-serif}
.dl-lang > summary,.dl-lang summary{cursor:pointer;list-style:none;color:#9e2b25;font-weight:600;font-size:13px;display:inline-flex;align-items:center;gap:6px}
.dl-lang > summary::-webkit-details-marker{display:none}
.dl-lang > summary::marker{content:""}
.dl-lang > summary::after{content:"";width:6px;height:6px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(45deg);margin-top:-3px;transition:transform .16s}
.dl-lang[open] > summary::after{transform:rotate(225deg);margin-top:2px}
.dl-menu{position:absolute;left:0;top:100%;margin-top:8px;z-index:30;background:#fff;border:1px solid #e4e0d8;border-radius:9px;box-shadow:0 8px 26px rgba(60,50,40,.15);padding:5px;display:flex;flex-direction:column;min-width:158px}
.dl-menu a{padding:8px 13px;border-radius:6px;color:#4b4540;text-decoration:none;font-size:13px;white-space:nowrap;display:flex;justify-content:space-between;gap:16px;align-items:center}
.dl-menu a:hover{background:#f6f5f2;color:#9e2b25}
.dl-menu a .lg{color:#9b938a;font-size:11px}
html[data-theme="dark"] .dl-menu{background:#241f19;border-color:#3a332c}
html[data-theme="dark"] .dl-menu a{color:#cfc7ba}
html[data-theme="dark"] .dl-menu a:hover{background:#2f2921;color:#e08a84}
