/* ============================================================================
   Emillis — company site
   Pure CSS, no build step, no external requests. Served by Caddy's file_server
   in production and by Vercel's static host for the bilingual draft.

   The page is a ledger with a ruled margin. An item's name sits left of the
   rule, its account sits right of the rule, and nothing hangs off the rule:
   no surfaces, no shadows, no badges, nothing crossing it. Section labels, the
   two connected systems, the two restaurants and the seven platform questions
   all use that one grammar. See DESIGN_PLAN.md.

   Colour has two jobs and six named roles, all opaque. Brass (--brass) is
   structure: the rule and the section labels. Jade (--jade) is emphasis and
   interaction: the one emphasised phrase in the headline, link hover, focus.
   Status values are not coloured at all — they are --muted, one size down from
   the prose, the way a note under a catalogue entry is set.
   ============================================================================ */

/* --- type ------------------------------------------------------------------
   One face carries both scripts, so a paragraph does not change identity when
   the reader switches language. Subset from Noto Sans KR 2.004 (SIL OFL 1.1)
   and renamed — see assets/fonts/OFL.txt and EMILLIS-TEXT-LICENSE.txt. Glyphs
   outside the subset fall back per-glyph to the system Korean face rather than
   to tofu, so a later copy edit degrades instead of breaking.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Emillis Text";
  src: url("/assets/fonts/emillis-text-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Emillis Text";
  src: url("/assets/fonts/emillis-text-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* --- tokens ----------------------------------------------------------------
   Six colour roles, each with a light value and a dark value. There is no
   surface token and no shadow token because there are no surfaces and no
   shadows; there is no on-jade token because nothing is set on top of jade.
   Every value is opaque: no signal colour is produced by alpha compositing, so
   what the palette says is what the reader sees.

   --brass is one role doing two jobs — the rule and the section labels — which
   is why its light value is the darker #7a5e1c: on the light record that is the
   only brass that clears 4.5:1 as text and 3:1 as a line at once. On any dark
   field the role takes its dark value, the same way --ink and --muted do.
   -------------------------------------------------------------------------- */

:root {
  /* Consumed by site.js, which reads it to decide which theme to switch to. */
  --is-dark: 0;

  --room:      #221b18;
  --stock:     #e8ede7;
  --ink:       #191e1b;
  --muted:     #4e5a53;
  --brass:     #7a5e1c;
  --jade:      #1b6350;

  --face: "Emillis Text", "Malgun Gothic", "Apple SD Gothic Neo", system-ui,
          -apple-system, "Segoe UI", Arial, sans-serif;
  --code: ui-monospace, SFMono-Regular, "Cascadia Code", Consolas, monospace;

  --page: 1180px;
  --gutter: clamp(1.25rem, 5vw, 3rem);
  --aside: 13rem;
  --rule: 2px;
  --rule-pad: clamp(1.1rem, 2.2vw, 1.9rem);
  --measure: 66ch;
}

/* Dark tokens are written twice on purpose: once for the system preference and
   once for an explicit choice, since the explicit one must win outside the
   media query too. Keep the two blocks in sync.

   --room does NOT change: the dining room is dark in both themes. The dark page
   ground is set below the room so the room still reads as a distinct field
   rather than dissolving into the page. --brass does change here, because the
   rule and the labels have to stay legible on whichever ground they are drawn
   on; its position and weight are identical everywhere, only the value moves. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --is-dark: 1;
    --stock:     #16120f;
    --ink:       #ede7e0;
    --muted:     #a99e95;
    --brass:     #c79a45;
    --jade:      #63c0a4;
  }
}

:root[data-theme="dark"] {
  --is-dark: 1;
  --stock:     #16120f;
  --ink:       #ede7e0;
  --muted:     #a99e95;
  --brass:     #c79a45;
  --jade:      #63c0a4;
}

/* --- base ----------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--stock);
  color: var(--ink);
  font-family: var(--face);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Two weights only — 400 and 700 — so hierarchy is carried by size, tracking
   and colour rather than by a ladder of synthesised weights. */
h1, h2 { margin: 0; font-weight: 700; text-wrap: balance; }
h1 {
  font-size: clamp(2.5rem, 1.5rem + 4.2vw, 4.1rem);
  letter-spacing: -0.035em;
  line-height: 1.03;
}
h2 {
  font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.25rem);
  letter-spacing: -0.025em;
  line-height: 1.1;
}
p { margin: 0; }

/* Underlines are full-strength currentColor, so a link's identifying mark has
   the same contrast as the link's text. The earlier 32% colour-mix composited
   to 1.60–2.57:1 and failed 1.4.11. */
a { color: inherit; text-decoration-color: currentColor; text-underline-offset: 0.22em; }
a:hover { text-decoration-color: var(--jade); }

img { max-width: 100%; height: auto; display: block; }
code { font-family: var(--code); font-size: 0.88em; color: var(--ink); }

:focus-visible { outline: 2px solid var(--jade); outline-offset: 3px; border-radius: 2px; }

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: var(--stock);
  padding: 0.6rem 1rem; z-index: 10;
}
.skip:focus { left: 0.5rem; top: 0.5rem; }

/* --- bilingual sample -----------------------------------------------------
   Both languages ship in the HTML; the inactive one is hidden by CSS keyed off
   <html data-lang>. i18n.js sets that attribute synchronously in <head>, so it
   is already correct when the body first paints — no flash of the wrong
   language, and no text substitution to watch for.

   The default arm is `:not([data-lang="ko"])`, so with JavaScript disabled —
   when nothing ever sets the attribute — the page is simply English.
   -------------------------------------------------------------------------- */

:root:not([data-lang="ko"]) [data-l="ko"] { display: none; }
:root[data-lang="ko"] [data-l="en"] { display: none; }

/* Korean sets looser leading and holds words together at line ends; the glyphs
   are taller than Latin at the same size and Hangul should not break mid-word.
   Tracking that suits Latin small caps is much too airy for Hangul, so the
   uppercase labels close up. */
:root[data-lang="ko"] { word-break: keep-all; }
:root[data-lang="ko"] body { line-height: 1.72; }
:root[data-lang="ko"] .lede { line-height: 1.6; }
:root[data-lang="ko"] h1,
:root[data-lang="ko"] h2 { letter-spacing: -0.015em; line-height: 1.18; }
:root[data-lang="ko"] .brand__kind,
:root[data-lang="ko"] .facts dt { letter-spacing: 0.02em; }

/* --- shell ---------------------------------------------------------------- */

/* One container width everywhere, so the rule sits at the same x in the room
   block and in the record below it. */
.masthead, .hero, .band, .foot__inner, .legal {
  width: min(var(--page), 100% - 2 * var(--gutter));
  margin-inline: auto;
}

/* --- the room -------------------------------------------------------------
   Masthead, hero and footer share one dark field. Semantic tokens are
   re-pointed here rather than overridden per element, so everything inside
   reads correctly in both themes without a second set of rules.

   The masthead and the hero are two adjacent full-bleed blocks rather than one,
   because <main id="main"> has to start before the hero: the skip link and the
   main landmark must not skip past the page's only value proposition.

   The record and the room alternate down the page: what connects and what can be
   exchanged are set on the record ground, while the restaurants themselves and
   the invitation to talk are set in the room. That is a section-level ground
   change, not a card — the rule runs straight through it and the two tracks keep
   their alignment.
   -------------------------------------------------------------------------- */

.room {
  --ink: #ede7e0;
  --muted: #a99e95;
  --brass: #c79a45;
  --jade: #63c0a4;
  background: var(--room);
  color: var(--ink);
}

.masthead {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 4vw, 2.5rem);
  padding-block: 1.6rem 1.4rem;
}

.brand { text-decoration: none; display: grid; gap: 0.2rem; margin-right: auto; }
.brand__name { font-size: 1.24rem; font-weight: 700; letter-spacing: -0.03em; }
.brand__kind { font-size: 0.72rem; letter-spacing: 0.05em; color: var(--muted); }

.nav { display: flex; gap: clamp(0.9rem, 2.4vw, 1.75rem); font-size: 0.9rem; }
.nav a { text-decoration: none; color: var(--muted); }
.nav a:hover { color: var(--ink); }

/* currentColor at full strength: a control's boundary now has the same contrast
   as its label (6.08:1 light, 6.47:1 in the room, 7.11:1 dark). */
.themer, .langer {
  display: inline-flex;
  align-items: center;
  border: 1px solid currentColor;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}
.themer:hover, .langer:hover { color: var(--ink); }
.themer[hidden], .langer[hidden] { display: none; }

.themer { gap: 0.5rem; font-size: 0.78rem; padding: 0.4rem 0.85rem 0.4rem 0.65rem; }
.themer__dot {
  width: 0.6rem; height: 0.6rem; border-radius: 50%;
  border: 1px solid currentColor;
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
}

/* 0.45rem block padding keeps the control at or above the 24px minimum touch
   target even on the narrowest layout. */
.langer { gap: 0.3rem; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.06em; padding: 0.45rem 0.75rem; }
.langer__seg.is-on { color: var(--ink); }
.langer__sep { opacity: 0.45; font-weight: 400; }

/* Narrow: brand and the two controls share the top row, nav drops beneath. */
@media (max-width: 700px) {
  .masthead { flex-wrap: wrap; row-gap: 0.9rem; }
  .nav { order: 3; flex: 1 1 100%; flex-wrap: wrap; }
  .themer__label { display: none; }
  .themer { padding: 0.4rem; }
}

/* --- the rule -------------------------------------------------------------
   One brass line, drawn as a pseudo-element on every section so that adjacent
   sections make it continuous from the top of the hero to the bottom of the
   last band. It is the boundary between the two tracks and it carries nothing:
   no rivets marking segments, no tabs crossing it, no surfaces resting on it.
   -------------------------------------------------------------------------- */

.hero, .band {
  position: relative;
  display: grid;
  grid-template-columns: var(--aside) minmax(0, 1fr);
}

.hero::before, .band::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--aside);
  width: var(--rule);
  background: var(--brass);
}

/* .band comes first so that .band--last's padding-bottom is not cancelled by a
   later declaration of the same specificity. */
.band { padding-block: clamp(2.25rem, 4.6vw, 3.5rem); }
.band--last { padding-bottom: clamp(2.75rem, 5.4vw, 4rem); }
.hero { padding-block: clamp(2.25rem, 5.4vw, 4rem) clamp(2.5rem, 6vw, 4.5rem); }

.hero__aside, .band__aside {
  grid-column: 1;
  padding-right: 1.25rem;
  text-align: right;
}

.hero__body, .band__body {
  grid-column: 2;
  padding-left: calc(var(--rule) + var(--rule-pad));
}
/* A paragraph that follows a register block needs the register's own rhythm
   above it, not a paragraph's. */
.register + .band__body,
.venues + .band__body,
.qa + .band__body { margin-top: clamp(1.25rem, 2.6vw, 1.75rem); }

.eyebrow, .label {
  margin: 0;
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--muted);
  line-height: 1.35;
  text-wrap: balance;
}
.label { color: var(--brass); }

.prose {
  max-width: var(--measure);
  color: var(--muted);
  margin-top: 1.25rem;
}
.prose a { color: var(--ink); }

/* --- hero ----------------------------------------------------------------- */

.hero h1 { max-width: 17ch; }
.hero h1 em { font-style: normal; color: var(--jade); }

.lede {
  max-width: var(--measure);
  margin-top: clamp(1.5rem, 3vw, 2rem);
  font-size: clamp(1.06rem, 1rem + 0.42vw, 1.26rem);
  line-height: 1.55;
  color: var(--muted);
}

.facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem clamp(2rem, 5.5vw, 4rem);
  margin: clamp(2.25rem, 5vw, 3rem) 0 0;
}
.facts dt {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.facts dd { margin: 0.35rem 0 0; font-size: 1rem; }
.facts--wide { margin-top: clamp(1.75rem, 4vw, 2.5rem); }

/* --- the register --------------------------------------------------------
   Every entry on the page — the two connected systems, the two restaurants,
   the seven platform questions — is one row of the same register: name left of
   the rule, account right of it. Each entry repeats the band's own column
   template rather than inheriting it, which keeps the two tracks aligned
   without subgrid.
   -------------------------------------------------------------------------- */

.register, .venues, .qa {
  grid-column: 1 / -1;
  display: grid;
  margin: clamp(1.4rem, 3vw, 1.9rem) 0 0;
  padding: 0;
  list-style: none;
}
.register { row-gap: clamp(1.25rem, 2.6vw, 1.75rem); }
.venues { row-gap: clamp(1.1rem, 2.4vw, 1.6rem); }
.qa { row-gap: clamp(1.15rem, 2.4vw, 1.75rem); }

/* auto/1fr rows: the account spans both rows, and the 1fr row absorbs its
   height so the first row stays exactly as tall as the name — which keeps the
   status note directly under the name it annotates instead of drifting down
   beside the middle of the paragraph. */
.entry {
  display: grid;
  grid-template-columns: var(--aside) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
}
.entry__name {
  grid-column: 1;
  grid-row: 1;
  margin: 0;
  padding-right: 1.25rem;
  text-align: right;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
/* The status value: one size down from the prose, in the same secondary voice,
   under the name it belongs to. No fill, no border, no dot, no accent colour —
   a note under a catalogue entry, not a badge. */
.entry__state {
  grid-column: 1;
  grid-row: 2;
  margin: 0.3rem 0 0;
  padding-right: 1.25rem;
  text-align: right;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}
.entry__what {
  grid-column: 2;
  grid-row: 1 / span 2;
  margin: 0;
  padding-left: calc(var(--rule) + var(--rule-pad));
  max-width: calc(var(--measure) + var(--rule) + var(--rule-pad));
  color: var(--muted);
}

/* The platform questions are the same shape, so the wrapper divs a dl needs
   can simply hand their dt/dd straight to the grid. */
.qa { grid-template-columns: var(--aside) minmax(0, 1fr); }
.qa > div { display: contents; }
.qa dt {
  grid-column: 1;
  padding-right: 1.25rem;
  text-align: right;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.qa dd {
  grid-column: 2;
  margin: 0;
  padding-left: calc(var(--rule) + var(--rule-pad));
  max-width: calc(var(--measure) + var(--rule) + var(--rule-pad));
  color: var(--muted);
}
.qa dd strong { color: var(--ink); font-weight: 700; }
.qa dd a { color: var(--ink); }

/* --- footer --------------------------------------------------------------
   The closeout: the same room field that opens the page, so the record sits
   between the two and needs no rule to be separated from either.
   -------------------------------------------------------------------------- */

/* class="foot room": the field and its token re-points come from .room, so the
   closeout cannot drift from the rest of the dark fields. */
.foot { color: var(--muted); }
.foot__inner {
  padding-block: 2.25rem 2.75rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  align-items: baseline;
  justify-content: space-between;
  font-size: 0.82rem;
}
/* Smallest lines on the page, but still ordinary body text as far as WCAG is
   concerned: --muted on --room reads 6.47:1. */
.foot__legal { letter-spacing: 0.01em; }
.foot__credit { flex-basis: 100%; letter-spacing: 0.04em; }
.foot__links { display: flex; flex-wrap: wrap; gap: 0.4rem 1.5rem; }
.foot__links a { text-decoration: none; }
.foot__links a:hover { color: var(--ink); text-decoration: underline; text-decoration-color: var(--jade); }

/* --- legal pages ---------------------------------------------------------- */

/* 11rem is the width the effective date needs to sit on one line. */
.legal-page { --page: 60rem; --aside: 11rem; }
.legal {
  position: relative;
  display: grid;
  grid-template-columns: var(--aside) minmax(0, 1fr);
  padding-block: clamp(2.5rem, 6vw, 4rem) clamp(3rem, 7vw, 5rem);
}
.legal::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: var(--aside);
  width: var(--rule);
  background: var(--brass);
}
.legal__aside { padding-right: 1.25rem; text-align: right; }
.legal__date { font-size: 0.88rem; font-weight: 700; color: var(--brass); }
.legal__body { padding-left: calc(var(--rule) + var(--rule-pad)); max-width: 68ch; }
.legal__body h1 { font-size: clamp(2rem, 1.5rem + 2vw, 2.75rem); }
.legal__body h2 { font-size: 1.1rem; letter-spacing: -0.01em; margin-top: 2.5rem; }
.legal__body p { margin-top: 0.9rem; color: var(--muted); }
.legal__body p a { color: var(--ink); }
.legal__body ul { margin-top: 0.9rem; padding-left: 1.15rem; color: var(--muted); }
.legal__body li { margin-top: 0.45rem; }
.legal__body > p:first-of-type { margin-top: 1.5rem; }
.legal__body strong { font-weight: 700; color: var(--ink); }

/* Set in the primary ink rather than on a surface: the emphasis is the colour
   step up from the --muted prose around it, so the page keeps its no-surface
   rule. */
.callout {
  margin-top: 1.5rem;
  font-size: 1.02rem;
  color: var(--ink);
}

/* --- narrow --------------------------------------------------------------
   The rule moves to the left edge of the shell and keeps running: names,
   status notes, questions and prose all shift to its right. The one thing that
   changes is that the margin track's content stacks above its own account
   instead of sitting across the rule from it.
   -------------------------------------------------------------------------- */

@media (max-width: 880px) {
  :root { --aside: 0px; }

  .hero, .band, .entry, .qa, .legal { grid-template-columns: minmax(0, 1fr); }
  .entry { grid-template-rows: auto; }

  /* Everything that was placed in the second track has to be told to come back
     to the first one, or it lands in an implicit column of its own and the two
     tracks overlap. */
  .hero__aside, .hero__body, .band__aside, .band__body,
  .entry__name, .entry__state, .entry__what,
  .qa dt, .qa dd { grid-column: 1; }

  .hero__aside, .band__aside, .legal__aside {
    padding-right: 0;
    padding-left: calc(var(--rule) + var(--rule-pad));
    text-align: left;
    margin-bottom: 1rem;
  }

  /* Rows are explicit here for the same reason they are explicit on the wide
     layout: the status value sits after the description in the markup — where
     the baseline put it — and is placed under its own name by the grid. */
  .entry__name, .entry__state, .entry__what {
    grid-column: 1;
    text-align: left;
    padding-right: 0;
    padding-left: calc(var(--rule) + var(--rule-pad));
  }
  .entry__name { grid-row: 1; }
  .entry__state { grid-row: 2; margin-top: 0.15rem; }
  .entry__what { grid-row: 3; margin-top: 0.55rem; }

  .qa dt {
    padding-right: 0;
    padding-left: calc(var(--rule) + var(--rule-pad));
    text-align: left;
    margin-top: 1.5rem;
  }
  .qa dd { margin-top: 0.35rem; }
  .qa { row-gap: 0; }

  /* .legal-page sets --aside on <body>, which wins over the :root value above,
     so the legal layout needs the same collapse spelled out for itself. */
  .legal-page { --aside: 0px; }
  .legal__aside { margin-bottom: 0.75rem; }
}

/* --- motion --------------------------------------------------------------
   One quiet entrance for the hero's own lines, and nothing else on the page
   moves. The rule is not animated: drawing it downward on load read as a
   connection initialising, which is exactly the impression this round removes.
   Written inside a no-preference query so that a reduced-motion reader — and
   any browser that does not understand the query — simply gets the page.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .hero__aside > *, .hero__body > * {
    animation: rise 520ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }
  .hero__aside > * { animation-delay: 60ms; }
  .hero__body > *:nth-child(1) { animation-delay: 100ms; }
  .hero__body > *:nth-child(2) { animation-delay: 170ms; }
  .hero__body > *:nth-child(3) { animation-delay: 240ms; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
