/* ============================================================================
   觀相 · 관상소

   AN INSTRUMENT, NOT A DOCUMENT.
   The subject is old. The tool must not be. Tradition lives in the 감정서 and in the
   one logogram; everything the reader touches is a flat, precise, contemporary surface.

   CALIBRATION. The numbers below were measured off linear.app rather than guessed:
     h1        64px / weight 510 / letter-spacing -0.022em / line-height 1.0
     lead      15px, muted, never bigger
     header    73px, and ~200px of air beneath it before the headline
     primary   32px tall, 13px type       (a header control is small)
     container 1344px
   The lesson those numbers carry: a modern dark page is RESTRAINED TYPE plus a
   DOMINANT PRODUCT VISUAL. The instinct to set the headline at 800 and shrink the
   product is exactly backwards, and it is what makes a page read as an ad banner.
   Korean needs a touch more weight than Latin at the same optical density, so the
   display sits at 550 for Hangul and 500 for Latin.

   NO ORNAMENT. No glow, no gradient, no grain, no status pill with a green dot.
   1px borders and flat fills. That is the whole surface language.

   COLOUR. The interface is greyscale. The only colour on any page belongs to the
   sitter: the 오행 pigment, which appears on the plate, in the 감정서, and on the
   card. 오방색 solved in OKLCH (one L .64, one C ~.12, five hues), so five very
   different colours read as one family:
     木 靑 석록 #11A388 · 火 赤 진사 #D56651 · 土 黃 석황 #AE8523
     金 白 백동 #8DA1A9 · 水 黑 감청 #7186DB
   黑 cannot be an accent on ink, so 감청 stands in. 白 is not a hue, so 金 is
   near-neutral by doctrine. The four chromatic ones pass the categorical CVD checks
   together (worst adjacent ΔE 17.6), and 金 never carries identity by hue alone.

   인주 #B23A26 is the seal, and the only red. Errors, and the chop on the 감정서.
   ========================================================================== */

:root {
  --bg:        #08090A;
  --surface:   #0E1013;
  --surface-2: #16181C;
  --line:      #1F2125;   /* decorative separators. Deliberately quiet. */
  --line-2:    #17191C;

  /* Every INTERACTIVE edge lives here, and it is far lighter than a dark-UI border "feels" like it
     should be. On #08090A, WCAG 1.4.11 (3:1 for non-text) is not met until roughly #5D5D5D; the
     #2A2D33 that instinct reaches for is 1.5:1, which is to say invisible. Measured, not guessed. */
  --edge:      #61666E;   /* 3.45:1 on the page, 3.08:1 on --field */
  --edge-hover:#8A8F98;   /* 6.13:1 */
  --field:     #15181C;

  --fg:        #F5F6F7;
  --fg-2:      #8A8F98;   /* cool grey. a muted with a blue bias reads chosen, not defaulted */
  --fg-3:      #5C6068;

  --chop:      #C74C36;   /* 인주, lifted just enough to read on near-black */

  --sans:  "Pretendard Variable", Pretendard, -apple-system, "Apple SD Gothic Neo", system-ui, sans-serif;
  --hanja: "Noto Serif KR", "AppleMyungjo", "Batang", serif;

  --r:    10px;
  --r-lg: 14px;
  --page: 1280px;
  --ease: cubic-bezier(.16, 1, .3, 1);

  color-scheme: dark;
}

/* ── the paper (한지) ─────────────────────────────────────────────────────────
   Set on <html data-paper>, the same hook as data-elem. The house is a DOCUMENT now: the
   감정서 is issued on hanji (cinema.py), so the door it is issued from cannot be a black
   dashboard. DESIGN.md's "instrument, not a document" doctrine held while the report was a
   dark page; CINEMA-PLAN (2026-07-11) rebuilt the report on paper and the two surfaces have
   disagreed since. This closes it, and it is only a repaint: every rule below already speaks
   in vars, so the header, footer, buttons and fields all turn to ink without knowing.

   That earlier draft failed as "a museum catalogue from 1995" — what saves this one is the
   film's grammar (the seal, the vertical rail, 하오체), not the paper itself. Paper alone
   is the trap, not the cure.

   Pigments are cinema.py's, to the byte: --paper #E7D8B0, --ink #241B10, --jusa #A5301C.
   Two sheets of the same stock, so the door and the document match.

   CONTRAST, measured on #E7D8B0 (L .692), not eyeballed:
     ink     #241B10  12.0:1    fg
     soft    #5C4F3B   5.6:1    fg-2, and every interactive edge (1.4.11 wants 3:1)
     #665843           4.9:1    fg-3. cinema's --faint #8A7A5E is 2.95:1 and FAILS 1.4.3 at
                                12.5px, and .small carries the privacy disclosure. Do not
                                use --faint for type here; it is decoration only.
     jusa    #A5301C   4.9:1    errors, the chop
   ------------------------------------------------------------------------------------- */
[data-paper] {
  --bg:        #E7D8B0;
  --surface:   #DECBA0;
  --surface-2: #D6C193;
  --line:      rgba(36, 27, 16, .22);
  --line-2:    rgba(36, 27, 16, .14);

  --edge:      #5C4F3B;   /* 5.6:1 on paper, 6.3:1 on --field */
  --edge-hover:#241B10;
  --field:     #EFE4C4;   /* a lighter sheet laid on the sheet, never a dark well */

  --fg:        #241B10;
  --fg-2:      #5C4F3B;
  --fg-3:      #665843;

  --chop:      #A5301C;   /* 주사 */

  color-scheme: light;
}
/* The ground: ONE sheet, viewport-fixed so it never tiles or seams however long the page runs.
   `background-attachment: fixed` is the obvious way to write this and it is a trap — iOS Safari
   has never implemented it properly and either drops it or repaints the whole sheet every frame.
   cinema.py sidesteps it with a fixed, z-indexed layer; this is that layer as a pseudo-element,
   so no page has to carry a spare <div> to hold its own floor. It hangs off <html> rather than
   <body> on purpose: body is `display:flex`, and a fixed pseudo-element there is one `position`
   typo away from becoming a flex item and shoving the header down. */
[data-paper]::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: url('/static/hanji.jpg') center / cover no-repeat;
}
/* The document speaks in 명조 THROUGHOUT: display, colophon, footnote and field label alike.
   The first cut set only the headings in serif and left Pretendard on the chrome and the small
   print, reasoning that a serif slows a reader down at 12px. On a sheet of hanji that read as a
   web page wearing a costume, and the user named it on sight ("갑자기 너무 모던해"). A 감정서's
   footnote is printed by the same press as its title; the seam is the tell. Pretendard stays only
   inside the fields the visitor types into, where the glyphs must be unmistakable.
   ponytail: this is Noto Serif KR (already loaded, subsetted) where cinema.py uses Nanum Myeongjo.
   A deliberate split: NM ships as two 3MB TTFs that cinema.py base64-inlines because an issued page
   must be self-contained. 6MB in front of a landing page's first paint, to match a font the visitor
   meets minutes later, is the wrong trade. Both are 명조. Subset NM here if they ever read apart.
   The tight tracking is not a preference: letter-spacing on Hangul scatters the syllables. */
[data-paper] :where(h1, h2) { font-family: var(--hanja); font-weight: 700; letter-spacing: -.01em; }
[data-paper] :where(.ftr, .small, .lead, .mark .n) { font-family: var(--hanja); }
/* Smaller than the dark sheet's h1 (clamp(34px,4.4vw,60px)), and that is not timidity. Those
   numbers were measured off Linear for Pretendard 550; 명조 700 carries far more ink at the same
   size, so 60px here lands as a poster where 60px there landed as a headline. The calibration
   the old sheet teaches is a RATIO, not a pixel: restrained type, dominant product. Setting the
   display huge and shrinking the artifact is the move that reads as an ad banner. */
[data-paper] h1 { font-size: clamp(27px, 3.3vw, 45px); line-height: 1.45; }
/* the sitter's element. Set on <html data-elem="木"> once a face has been read. */
[data-elem="木"] { --el: #11A388; --el-lift: #83CBB8; }
[data-elem="火"] { --el: #D56651; --el-lift: #F1A494; }
[data-elem="土"] { --el: #AE8523; --el-lift: #D3B77F; }
[data-elem="金"] { --el: #8DA1A9; --el-lift: #AFBDC4; }
[data-elem="水"] { --el: #7186DB; --el-lift: #A7B8F2; }

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  display: flex; flex-direction: column;      /* the footer sits at the bottom of a short page */
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* Korean breaks at word boundaries only. `anywhere` collapses min-content width and
     crushes grid columns to one glyph, a bug this repo has already shipped once. */
  word-break: keep-all;
  overflow-wrap: break-word;
  /* `clip`, never `hidden`: `overflow-x:hidden` silently forces overflow-y:auto and
     creates a nested scroll container that kills momentum scrolling on Mac. */
  overflow-x: clip;
}
html[lang="en"] body { word-break: normal; }

::selection { background: var(--fg); color: var(--bg); }
main { flex: 1 0 auto; }
a { color: inherit; text-decoration: none; }

:where(a, button, input, label, [tabindex]):focus-visible {
  outline: 2px solid var(--fg-2); outline-offset: 2px; border-radius: 4px;
}

/* ── type ─────────────────────────────────────────────────────────────────── */

h1, h2, h3 { margin: 0; font-weight: 550; letter-spacing: -.035em; text-wrap: balance; }
h1 { font-size: clamp(34px, 4.4vw, 60px); line-height: 1.06; }
h2 { font-size: clamp(22px, 2.4vw, 30px); line-height: 1.2; letter-spacing: -.03em; }
h3 { font-size: 16px; line-height: 1.5; letter-spacing: -.02em; }
/* Latin carries this weight more heavily than Hangul at the same size */
html[lang="en"] :where(h1, h2) { font-weight: 500; letter-spacing: -.025em; }

.hanja { font-family: var(--hanja); font-weight: 400; }

.lead  { font-size: 16px; line-height: 1.65; color: var(--fg-2); }
.small { font-size: 12.5px; line-height: 1.7; color: var(--fg-3); }
.num   { font-variant-numeric: tabular-nums; }

b, strong { font-weight: 600; color: var(--fg); }

/* ── layout ───────────────────────────────────────────────────────────────── */

.page { width: min(var(--page), 100%); margin-inline: auto; padding-inline: clamp(20px, 4vw, 40px); }

/* ── header ───────────────────────────────────────────────────────────────── */

.hdr .in { display: flex; align-items: center; justify-content: space-between; height: 68px; gap: 20px; }
.mark { display: inline-flex; align-items: center; gap: 9px; font-size: 14px; font-weight: 600; letter-spacing: -.015em; }
.mark .g { font-family: var(--hanja); font-size: 17px; font-weight: 400; letter-spacing: .08em; }
.mark .n { color: var(--fg-2); font-weight: 500; }

/* a language switcher is a two-cell segmented control, not a dropdown */
.lang { display: inline-flex; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: 8px; }
.lang a { min-width: 34px; padding: 4px 8px; border-radius: 5px; text-align: center;
  font-size: 12px; font-weight: 500; color: var(--fg-3); transition: color .14s var(--ease); }
.lang a:hover { color: var(--fg-2); }
.lang a[aria-current="true"] { background: var(--surface-2); color: var(--fg); }

/* ── controls ─────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 46px; padding-inline: 22px; border: 0; border-radius: 8px;
  background: var(--fg); color: var(--bg);
  font-family: inherit; font-size: 14.5px; font-weight: 600; letter-spacing: -.01em;
  cursor: pointer; transition: opacity .14s var(--ease);
}
.btn:hover:not(:disabled) { opacity: .88; }
.btn:disabled { opacity: .34; cursor: default; }
.btn.block { width: 100%; }
.btn.ghost { background: transparent; color: var(--fg); border: 1px solid var(--line); height: 40px; font-size: 13.5px; }
.btn.ghost:hover { border-color: var(--fg-3); opacity: 1; }
/* a header control is small: 32px, 13px type. Anything bigger shouts. */
.btn.sm { height: 32px; padding-inline: 13px; font-size: 13px; border-radius: 999px; }

.link { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 500; color: var(--fg-2); }
.link:hover { color: var(--fg); }
.link svg { transition: transform .18s var(--ease); }
.link:hover svg { transform: translateX(3px); }

/* ── one reveal, and nothing else ─────────────────────────────────────────── */

@keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.rise { animation: rise .55s var(--ease) both; }
@media (prefers-reduced-motion: reduce) {
  .rise { animation: none; }
  * { transition-duration: .01ms !important; scroll-behavior: auto !important; }
}

/* ── footer ───────────────────────────────────────────────────────────────── */

.ftr { border-top: 1px solid var(--line-2); margin-top: clamp(56px, 7vw, 88px); padding-block: 26px 30px; }
.ftr .top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 24px; }
.ftr .mark { font-size: 15px; }
.ftr .mark .g { font-size: 19px; }
.ftr nav { display: flex; gap: 16px; font-size: 13.5px; }
.ftr nav a { color: var(--fg-2); }
.ftr nav a:hover { color: var(--fg); }
.ftr .bottom { margin-top: 20px; display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 8px 24px; font-size: 12px; color: var(--fg-3);
  font-variant-numeric: tabular-nums; }
.ftr .bottom a:hover { color: var(--fg); }
/* a required value that is not set must be loud, never quietly someone else's */
.ftr .unset { color: var(--chop); }
