/* GalaxyDresser web app — GENERATED by tools/web/sync-design.mjs from design/tokens.css + design/components/base.css
 * + design/components/app.css. Do not edit here: edit design/ and run the script (design/README.md 「web/에 적용」). */

/* ===== design/tokens.css ===== */
/* GalaxyDresser — "Silver Night" design tokens (v3)
 * Near-black night, silver type and graphite surfaces, ONE electric-blue accent.
 * Restrained and precise: no paper, no cream, no grain. The atelier survives only as line —
 * the hanger mark, hang tags, a stitched seam, a measuring tape.
 * Every text/background pair and every control boundary is measured by tools/check-contrast.py;
 * tools/shoot.py also measures the text actually rendered on each page against the pixels behind it.
 *
 * Rules
 *  - Blue (--accent) is the thread: seams being sewn, tag strings, the current page, the brand's tail —
 *    and ONE primary button per page (.btn--primary). Markers, numbers, chips and notes are silver.
 *  - Text is silver on night or graphite: --fg / --fg-2 / --fg-3. Nothing else carries body text.
 *  - Control boundaries (inputs, toggles, ghost buttons, chips, search) use --ctl (3:1 or more).
 *    --rule / --rule-2 are decorative seams and dividers only.
 *  - There is one context. No surface flips the colours, so a component looks the same wherever it sits.
 */
:root {
  color-scheme: dark;

  /* ── Night (backgrounds) — neutral, no blue or violet cast ─────── */
  --night-0: #050506;          /* deepest: admin rail, footer */
  --night-1: #0A0B0D;          /* page */
  --night-2: #111316;          /* quiet card */
  --night-3: #181A1F;          /* raised / hover */
  --night-4: #1F2228;          /* selected row */

  /* ── Silver (type and line on night) ──────────────────────────── */
  --silver: #F2F4F7;           /* 17.9:1 on night-1 */
  --silver-2: #C4C9D2;         /* 11.8:1 secondary */
  --silver-3: #9AA1AD;         /* 7.6:1 muted; still 5.8:1 on surface-3 */
  --line: rgb(242 244 247 / .12);    /* decorative divider */
  --line-2: rgb(242 244 247 / .24);  /* decorative seam */
  --line-3: rgb(242 244 247 / .5);   /* control boundary: 4.9:1 on night-1, 4.7:1 on night-4 (≥3) */
  --light: 214 220 230;        /* rgb triplet: the soft silver light (hero beams, haze) */

  /* ── Graphite surfaces (tags, sheets, forms) — not paper ──────── */
  --surface: #15171B;          /* a raised surface */
  --surface-2: #1B1E23;        /* inset on a surface: field, memo strip, summary */
  --surface-3: #22262C;        /* toggle track, pressed */
  --surface-edge: #3E434D;     /* the 1px edge of a surface (decorative) */
  --surface-sheen: rgb(255 255 255 / .035);   /* top light on a surface */

  /* ── Blue (the one accent) ────────────────────────────────────── */
  --blue: #3D8BFF;             /* 5.9:1 on night-1, 5.0:1 on surface-2 */
  --blue-hi: #66A3FF;          /* hover */
  --blue-deep: #1F4E99;        /* the back strand of a tag string (decorative) */
  --on-blue: #03060D;          /* text on a blue button: 6.1:1 (white would be 3.3:1) */
  --blue-soft: rgb(61 139 255 / .14);

  /* ── Status (semantic, not accent; app and admin only) ────────── */
  --ok: #7FD3A9;
  --warn: #E8C27A;
  --info: #A8BEDF;             /* silver-blue, kept apart from the accent */
  --no: #FF8A80;

  /* ── Semantic (what components use) ───────────────────────────── */
  --bg: var(--night-1);
  --fg: var(--silver);
  --fg-2: var(--silver-2);
  --fg-3: var(--silver-3);
  --rule: var(--line);
  --rule-2: var(--line-2);
  --ctl: var(--line-3);
  --ctl-hover: var(--silver-2);
  --accent: var(--blue);
  --accent-hi: var(--blue-hi);
  --on-accent: var(--on-blue);
  --focus: #9CC4FF;            /* 11.0:1 on night-1, 9.4:1 on surface-2 */
  --focus-halo: rgb(10 11 13 / .9);
  --field-bg: rgb(242 244 247 / .045);

  /* ── Type ─────────────────────────────────────────────────────── */
  /* Font draft K (2026-10-10): one sans family for text and headings, a space-age Latin face for the wordmark.
     GD Sans    = Pretendard 400–800: body, labels, buttons; headings 700 (--fw-display), the hero's big line 800
                  (--fw-hero), prices and big numbers 700 (--fw-num), quotes 500. h3 and card/panel titles stay 700.
     GD Sans JP = Pretendard JP 400–800: the same roles on Japanese pages (:lang(ja) below). Second in the other
                  stacks, so Japanese in user data (a BOOTH prefab name, a ticket) still gets Japanese forms; kanji
                  outside its subset go to the Japanese system gothics next (Hiragino, Yu Gothic UI), not to Malgun
                  in the middle of a word. Those have no Hangul, so Hangul beyond GD Sans still reaches the Korean
                  ones; only Hanja in Korean text (rare) takes Japanese forms.
     GD Logo    = Xolonium 400, ASCII: the wordmark (.brand-word) only.
     GD Mono    = Cascadia Mono, Latin and digits only. A label written in Korean is set in GD Sans
                  (see .label:lang(ko) in components/base.css), never tracked, never under 12px.
     --font-display is the heading stack: the same family as the body, kept as its own token. */
  --font-body: "GD Sans", "GD Sans JP", "Hiragino Sans", "Yu Gothic UI", "Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans KR", "Meiryo", sans-serif;
  --font-display: "GD Sans", "GD Sans JP", "Hiragino Sans", "Yu Gothic UI", "Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans KR", "Meiryo", sans-serif;
  --font-logo: "GD Logo", "GD Sans", "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  --font-mono: "GD Mono", "Cascadia Mono", "SFMono-Regular", Consolas, "GD Sans", "GD Sans JP", "Malgun Gothic", monospace;
  --fw-display: 700;          /* h1, h2, .display */
  --fw-hero: 800;              /* the home hero's big line */
  --fw-num: 700;               /* prices, step numbers, KPI and usage figures, the support contacts */
  --fw-quote: 500;             /* a quoted clause in the policies */
  --fw-logo: 400;              /* Xolonium has one weight */

  --fs-hero: clamp(3.9rem, 1.2rem + 7.4vw, 8rem);           /* the one huge line */
  --fs-hero-sm: clamp(1.7rem, 1.05rem + 2.5vw, 3.15rem);     /* the lines around it */
  --fs-h1: clamp(2.5rem, 1.75rem + 2.6vw, 4rem);
  --fs-h2: clamp(2.05rem, 1.5rem + 1.9vw, 3.25rem);
  --fs-h3: 1.1875rem;          /* Sans 700 */
  --fs-lead: clamp(1.0625rem, 1rem + .3vw, 1.25rem);
  --fs-body: 1rem;
  --fs-prose: 1.0625rem;       /* long-form reading (terms, privacy) */
  --fs-small: .875rem;
  --fs-ko-min: .8125rem;       /* 13px: the smallest Korean text (12px only in dense admin tables) */
  --fs-label: .75rem;          /* 12px mono, Latin/digits only */
  --fs-micro: .6875rem;        /* 11px mono, digits/codes only */

  --lh-display: 1.06;
  --lh-head: 1.18;
  --lh-body: 1.72;
  --lh-prose: 1.86;
  --measure: 40rem;            /* long-form line length (~38 Hangul syllables) */
  --track-latin: .12em;        /* uppercase mono labels; Hangul is never tracked */
  --track-head: -.03em;        /* headings */
  --track-hero: -.05em;        /* the hero's big line */
  --track-logo: 0;             /* the wordmark */

  /* ── Space, shape, depth ──────────────────────────────────────── */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px; --s-10: 136px;
  /* Section rhythm: pick by the weight of what follows, not one size for all */
  --sec-s: clamp(56px, 7vw, 96px);
  --sec-m: clamp(72px, 9vw, 128px);
  --sec-l: clamp(88px, 11vw, 160px);
  --col: 1200px;
  --gutter: clamp(16px, 4vw, 40px);
  --r-xs: 2px;                 /* crisp corners */
  --r-sm: 4px;
  --r-md: 8px;
  --r-pill: 999px;
  --shadow-surface: inset 0 1px 0 var(--surface-sheen), 0 18px 40px -20px rgb(0 0 0 / .8), 0 2px 6px rgb(0 0 0 / .35);
  --shadow-lift: 0 30px 60px -24px rgb(0 0 0 / .85), 0 6px 14px rgb(0 0 0 / .45);

  /* ── Stitch & tape ────────────────────────────────────────────── */
  --stitch-len: 7px;           /* one stitch */
  --stitch-gap: 5px;           /* one gap */
  --stitch-w: 1.5px;
  --stitch-inset: 7px;
  --tape-unit: 48px;           /* one "cm" on a measuring tape */

  /* ── Motion ───────────────────────────────────────────────────── */
  /* One orchestrated load on the two marketing pages, finished by ~1.2 s. App screens: none. */
  --ease-out: cubic-bezier(.16, .84, .24, 1);
  --spring: linear(0, .32 6%, .78 13%, 1.09 21%, 1.16 27%, 1.08 36%, .97 47%, .96 56%, 1.01 68%, 1);
  --t-fast: 140ms;
  --t-mid: 320ms;
  --t-reveal: 560ms;
  --t-stitch: 700ms;
  --t-sway: 1400ms;
  --stagger: 60ms;
  --sway: 1.1deg;              /* hover nudge of a hanging tag, around its eyelet */

  /* ── Layers ───────────────────────────────────────────────────── */
  /* The Paddle checkout overlay is appended to <body> as a fixed iframe with a very high z-index.
     Keep every layer of ours well under it, and never put transform/filter/contain on html/body. */
  --z-sky: -1;
  --z-raised: 2;
  --z-sticky: 10;
  --z-header: 20;
  --z-popover: 40;
  --z-ceiling: 100;            /* nothing in this system goes above this */
}

@media (prefers-reduced-motion: reduce) {
  :root { --t-fast: 0ms; --t-mid: 0ms; --t-reveal: 0ms; --t-stitch: 0ms; --t-sway: 0ms; --stagger: 0ms; }
}

/* Japanese (the site's /ja/ and the app in Japanese): everything but the wordmark is GD Sans JP (Pretendard JP) — Latin,
   digits, punctuation (full-width 「」、。, with the halt base.css's text-spacing-trim needs), kana, kanji and the
   Hangul those pages show (한국어 in the switch, the business line). GD Sans after it only for Hangul in user data.
   Kanji outside our copy fall to the system Japanese gothic. The plugin's loopback page has no web fonts and gets the
   system Japanese ones. */
:lang(ja) {
  --font-body: "GD Sans JP", "GD Sans", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Meiryo", sans-serif;
  --font-display: "GD Sans JP", "GD Sans", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Meiryo", sans-serif;
  --font-logo: "GD Logo", "GD Sans JP", "Hiragino Sans", "Yu Gothic UI", sans-serif;
  --font-mono: "GD Mono", "Cascadia Mono", "SFMono-Regular", Consolas, "GD Sans JP", "GD Sans", monospace;
}

/* ===== design/components/base.css ===== */
/* GalaxyDresser — "Silver Night" · base.css
 * Shared by every page: reset, type, sky, motion primitives, seams, labels, buttons, brand,
 * header, surfaces, chips, footer. Load order: fonts/fonts.css → tokens.css → base.css → site|app|admin.css
 * CSP-safe: no inline styles needed, no scripts. Images: data: and 'self' (img/stars.svg).
 * Paddle-safe: decoration sits behind content (z-index -1) and html/body never get
 * transform / filter / backdrop-filter / contain / will-change.
 */

/* ───────────────────────── Base ───────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html {
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: 88px;
  font-synthesis: none;              /* GD Logo has one weight (400) and GD Sans stops at 800: never fake a bold */
}
body {
  margin: 0;
  min-height: 100vh;
  color: var(--fg);
  background: transparent;           /* html paints the night; the sky sits between them */
  font: 400 var(--fs-body)/var(--lh-body) var(--font-body);
  font-kerning: normal;
  word-break: keep-all;              /* Korean: break between words, not syllables */
  overflow-wrap: break-word;         /* …but never overflow on long IDs */
  line-break: strict;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
/* Korean: 「」 are narrow in GD Sans (Pretendard draws them 0.34 em wide), so "옷장에서 「…」" is one space wide, not two;
   halt does the same for 『』（）in GD Sans JP (a Japanese word inside Korean text) and in fallback fonts that have it.
   Copy rule: a normal space before 「 and none inside the brackets. Hangul is not affected by halt. */
body:lang(ko) { font-feature-settings: "halt"; }
/* Japanese: brackets stay full-width. text-spacing-trim, through the halt that subset-fonts.py adds to GD Sans JP (Pretendard
   JP has none), trims a bracket that starts a line and the blank between adjacent ones (」、 ）（ → 1.5 em). */
:lang(ja) body, body:lang(ja) { word-break: normal; font-feature-settings: normal; text-spacing-trim: trim-start; }
:lang(ja) :is(p, li, h1, h2, h3, .lead) { word-break: auto-phrase; }   /* Chrome 119+: no break inside a phrase (VRChatア|バター); normal elsewhere */
:where(:not(:lang(ja))) > :where(:lang(ja)) { font-family: var(--font-body); }   /* a Japanese word in Korean or English text */

img, svg { display: block; max-width: 100%; }
svg { overflow: visible; }
a { color: inherit; text-underline-offset: .22em; text-decoration-thickness: 1px; }
a:hover { text-decoration-color: var(--accent); }
p { margin: 0 0 1em; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4 { margin: 0; text-wrap: balance; }
/* Display = the heading style: GD Sans 700, large, tight (font draft K). h1/h2, and big figures through --fw-num. */
h1, h2, .display {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  line-height: var(--lh-head);
  letter-spacing: var(--track-head);
}
h1 { font-size: var(--fs-h1); line-height: var(--lh-display); }
h2 { font-size: var(--fs-h2); }
/* h3 and below, and every card/panel title, are Sans 700. */
h3, h4, .title-sans {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--fs-h3);
  line-height: 1.4;
  letter-spacing: -.01em;
}
strong, b { font-weight: 700; }
code, kbd, samp { font-family: var(--font-mono); font-size: .92em; }
button, input, select, textarea { font: inherit; color: inherit; }
::selection { background: var(--accent); color: var(--on-accent); }

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px var(--focus-halo);
  border-radius: var(--r-sm);
}

[hidden] { display: none !important; }
/* A value still marked TODO in site/business.json or config.json (tools/site/apply-business.mjs). */
[data-todo] { color: var(--warn); text-decoration: underline dashed rgb(232 194 122 / .6); text-underline-offset: 4px; }

.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; left: var(--s-4); top: -60px; z-index: var(--z-ceiling);
  padding: 10px 16px; background: var(--silver); color: var(--night-1);
  font-weight: 700; border-radius: var(--r-sm); text-decoration: none;
}
.skip:focus-visible { top: var(--s-3); }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.wrap { width: min(100% - 2 * var(--gutter), var(--col)); margin-inline: auto; }
.num, .tabular { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }       /* phone numbers, and words glued to a bracket: 아바타(소체)용 */

/* ───────────────────────── Sky ─────────────────────────
 * Dark and quiet everywhere: a neutral night gradient, one faint silver haze, and one non-repeating
 * star field (img/stars.svg) dimmed over the content column. No grain. The one strong light lives in
 * the home hero (.beams in site.css). Fixed, z-index -1, pointer-events none: never above Paddle.
 */
.sky {
  position: fixed; inset: 0; z-index: var(--z-sky); pointer-events: none; overflow: hidden;
  background:
    radial-gradient(60% 44% at 84% -8%, rgb(var(--light) / .085), transparent 70%),
    radial-gradient(80% 50% at 50% 120%, rgb(var(--light) / .045), transparent 70%),
    linear-gradient(180deg, #0D0E11 0%, var(--night-1) 40%, #070709 100%);
}
.sky::before {            /* stars: one 1600×1200 field, sparse and dimmed where the text column is */
  content: ""; position: absolute; inset: 0;
  background: url("img/stars.svg") 50% 0 / 1600px 1200px repeat;
  --col-fade: linear-gradient(90deg, #000 0, #000 calc(50% - 700px), rgb(0 0 0 / .3) calc(50% - 560px),
                              rgb(0 0 0 / .3) calc(50% + 560px), #000 calc(50% + 700px), #000 100%);
  -webkit-mask-image: var(--col-fade);
          mask-image: var(--col-fade);
  opacity: .9;
}
.sky--quiet { background: linear-gradient(180deg, #0C0D10, var(--night-1)); }
.sky--quiet::before { opacity: .35; }

/* Drafting grid: faint 12px / 60px silver lines, faded at the edges. Put on any section. */
.cut-grid { position: relative; isolation: isolate; }
.cut-grid::before {
  content: ""; position: absolute; inset: -40px 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(rgb(242 244 247 / .045) 1px, transparent 1px),
    linear-gradient(90deg, rgb(242 244 247 / .045) 1px, transparent 1px),
    linear-gradient(rgb(242 244 247 / .018) 1px, transparent 1px),
    linear-gradient(90deg, rgb(242 244 247 / .018) 1px, transparent 1px);
  background-size: 60px 60px, 60px 60px, 12px 12px, 12px 12px;
  background-position: center;
  -webkit-mask-image: radial-gradient(70% 70% at 50% 45%, #000 30%, transparent 85%);
          mask-image: radial-gradient(70% 70% at 50% 45%, #000 30%, transparent 85%);
}

/* ───────────────────────── Motion primitives ─────────────────────────
 * Marketing pages only, once, done by ~1.2 s. Headings and lead copy are never hidden at load (LCP).
 * App and admin screens use none of these.
 */
@keyframes rise { from { opacity: 0; transform: translate3d(0, 12px, 0); } to { opacity: 1; transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes draw { to { stroke-dashoffset: 0; } }

.rv { animation: rise var(--t-reveal) var(--ease-out) both; animation-delay: calc(var(--d, 0) * var(--stagger)); }
.rv-fade { animation-name: fade; }
.d1 { --d: 1; } .d2 { --d: 2; } .d3 { --d: 3; } .d4 { --d: 4; } .d5 { --d: 5; }
.d6 { --d: 6; } .d7 { --d: 7; } .d8 { --d: 8; } .d9 { --d: 9; } .d10 { --d: 10; }

/* SVG thread that sews itself in: a dashed path revealed by a solid mask path (pathLength="1"). */
.sew-mask { fill: none; stroke: #fff; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: draw var(--t-stitch) var(--ease-out) forwards; animation-delay: calc(var(--d, 2) * var(--stagger) + 120ms); }
.stitch-path { fill: none; stroke: var(--accent); stroke-width: 1.6; stroke-linecap: round;
  stroke-dasharray: var(--stitch-len) var(--stitch-gap); }
.stitch-path--silver { stroke: var(--line-3); }

@media (prefers-reduced-motion: reduce) {
  .rv, .sew-mask { animation: none !important; }
  .sew-mask { stroke-dashoffset: 0; }
  * { transition-duration: 0ms !important; scroll-behavior: auto !important; }
}

/* ───────────────────────── Seams ─────────────────────────
 * A seam is a dashed line in silver (decorative) or blue (the thread). Never a solid border pretending.
 * A seam thinner than 2px (--stitch-w, 1.5px) is drawn as a border cut into stitches by a mask, never as a
 * 1.5px-tall box: border widths snap to whole device pixels, a box does not, so a row of 1.5px boxes rendered
 * some seams one pixel tall and some two (on a 1x screen the blue eyebrow thread looked grey on one page).
 */
.stitch-h {        /* a horizontal seam as a divider */
  height: 0; border: 0; margin: 0; border-top: var(--stitch-w) solid var(--stitch-color, var(--rule-2));
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap)));
          mask: repeating-linear-gradient(90deg, #000 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap)));
}
.stitched { position: relative; }
.stitched::after {      /* a seam just inside the edge of a surface */
  --c: var(--stitch-color, var(--rule));
  content: ""; position: absolute; inset: var(--stitch-inset); pointer-events: none; border-radius: 1px;
  background:
    repeating-linear-gradient(90deg,  var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) left top / 100% 1px no-repeat,
    repeating-linear-gradient(180deg, var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) right top / 1px 100% no-repeat,
    repeating-linear-gradient(270deg, var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) right bottom / 100% 1px no-repeat,
    repeating-linear-gradient(0deg,   var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) left bottom / 1px 100% no-repeat;
}
.basted {          /* a dashed outline instead of an edge: something not sewn yet ("coming soon") */
  --c: var(--rule-2);
  background:
    repeating-linear-gradient(90deg,  var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) left top / 100% 1px no-repeat,
    repeating-linear-gradient(180deg, var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) right top / 1px 100% no-repeat,
    repeating-linear-gradient(270deg, var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) right bottom / 100% 1px no-repeat,
    repeating-linear-gradient(0deg,   var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) left bottom / 1px 100% no-repeat;
}

/* ───────────────────────── Labels & small type ─────────────────────────
 * .label is mono, uppercase, tracked — for Latin and digits only (mark it lang="en").
 * The same class in Korean (the page default) becomes GD Sans 13px, untracked, sentence case.
 */
.label {
  font: 500 var(--fs-label)/1.4 var(--font-mono);
  letter-spacing: var(--track-latin);
  text-transform: uppercase;
  color: var(--fg-3);
}
.label:lang(ko), .label:lang(ja) {
  font: 500 var(--fs-ko-min)/1.45 var(--font-body);
  letter-spacing: 0;
  text-transform: none;
}
.latin {           /* a Latin run inside Korean text that should look like a label */
  font: 500 var(--fs-label)/1 var(--font-mono); letter-spacing: var(--track-latin); text-transform: uppercase;
}
.eyebrow {
  display: flex; align-items: center; gap: 12px; margin: 0 0 var(--s-4);
  font: 500 .9375rem/1.4 var(--font-body); color: var(--fg-2);
}
.eyebrow::before {   /* a short run of thread */
  content: ""; flex: 0 0 34px; height: 0; border-top: var(--stitch-w) solid var(--accent);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 6px, transparent 6px 10px);
          mask: repeating-linear-gradient(90deg, #000 0 6px, transparent 6px 10px);
}
.eyebrow:lang(en) { font: 500 var(--fs-label)/1.4 var(--font-mono); letter-spacing: var(--track-latin); text-transform: uppercase; }
.eyebrow b { font: 500 var(--fs-label)/1 var(--font-mono); letter-spacing: var(--track-latin); text-transform: uppercase; color: var(--fg); }
.lead { font-size: var(--fs-lead); line-height: 1.7; color: var(--fg-2); max-width: 36em; }
.muted { color: var(--fg-3); }
.small { font-size: var(--fs-small); }
.accent { color: var(--accent); }

/* ───────────────────────── Buttons ─────────────────────────
 * One blue (.btn--primary) per page: its main action. Then silver-filled (.btn--silver) for a strong
 * secondary action, and the ghost .btn for everything else.
 */
.btn {
  --btn-bg: transparent; --btn-fg: var(--fg); --btn-bd: var(--ctl);
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  min-height: 46px; padding: 0 1.3em;
  font: 600 .9375rem/1.1 var(--font-body); text-decoration: none; white-space: nowrap;
  color: var(--btn-fg); background: var(--btn-bg); border: 1px solid var(--btn-bd); border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--t-fast) ease, border-color var(--t-fast) ease, transform var(--t-fast) ease, color var(--t-fast) ease;
}
.btn:hover { --btn-bd: var(--ctl-hover); background-color: rgb(242 244 247 / .06); }
.btn:active { transform: translateY(1px); }
.btn svg { width: 1.05em; height: 1.05em; flex: none; }
.btn--primary { --btn-bg: var(--accent); --btn-fg: var(--on-accent); --btn-bd: transparent; --btn-stitch: rgb(3 6 13 / .3); }
.btn--primary:hover { --btn-bd: transparent; background-color: var(--accent-hi); }
.btn--silver { --btn-bg: var(--silver); --btn-fg: var(--night-1); --btn-bd: transparent; --btn-stitch: rgb(10 11 13 / .26); }
.btn--silver:hover { --btn-bd: transparent; background-color: #FFFFFF; }
.btn--primary::after,
.btn--silver::after {          /* a woven-label seam inside the filled buttons */
  content: ""; position: absolute; inset: 4px; border-radius: 2px; pointer-events: none;
  background:
    repeating-linear-gradient(90deg, var(--btn-stitch) 0 5px, transparent 5px 9px) left top / 100% 1px no-repeat,
    repeating-linear-gradient(90deg, var(--btn-stitch) 0 5px, transparent 5px 9px) left bottom / 100% 1px no-repeat;
}
.btn--danger { --btn-fg: var(--no); --btn-bd: rgb(255 138 128 / .7); }
.btn--sm { min-height: 38px; padding: 0 1em; font-size: .875rem; }
.btn--lg { min-height: 54px; padding: 0 1.6em; font-size: 1rem; }
.btn--block { width: 100%; }
.btn--quiet { --btn-bd: transparent; padding-inline: .7em; text-decoration: underline; text-decoration-color: var(--rule-2); text-underline-offset: .3em; }
.btn--quiet:hover { --btn-bd: transparent; text-decoration-color: var(--fg); }
.link-arrow { display: inline-flex; align-items: center; gap: .4em; font-weight: 600; color: var(--fg); text-decoration: none; }
.link-arrow svg { width: 1em; height: 1em; transition: translate var(--t-fast) ease; }
.link-arrow:hover svg { translate: 3px 0; }

/* ───────────────────────── Brand ─────────────────────────
 * #gd-mark: the hanger mark (viewBox 32) — a hanger drawn as a constellation: silver lines, five stars,
 * the hook an arc of stars ending in the blue needle-point. Wordmark: GD Logo (Xolonium 400); a blue seam under
 * "Dresser" continues the tail of the y.
 */
.brand { display: inline-flex; align-items: center; gap: 10px; color: var(--silver); text-decoration: none; }
.brand-mark { width: 32px; height: 32px; flex: none; }
.brand-word { font: var(--fw-logo) 1.4375rem/1 var(--font-logo); letter-spacing: var(--track-logo); white-space: nowrap; }
.brand-word .tail { position: relative; }
.brand-word .tail::after {
  content: ""; position: absolute; left: -.14em; right: .02em; bottom: .1em; border-top: 1.5px solid var(--accent);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 4px, transparent 4px 7px);
          mask: repeating-linear-gradient(90deg, #000 0 4px, transparent 4px 7px);
}
.mark-line { fill: none; stroke: rgb(242 244 247 / .8); stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.mark-star { fill: var(--silver); }
.mark-accent { fill: var(--accent); }

/* ───────────────────────── Header ───────────────────────── */
.site-top {
  position: sticky; top: 0; z-index: var(--z-header);
  background: linear-gradient(180deg, rgb(10 11 13 / .94), rgb(10 11 13 / .84));
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.site-top::after {        /* the header's bottom seam */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: repeating-linear-gradient(90deg, var(--line-2) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap)));
}
.top-inner { display: flex; align-items: center; gap: var(--s-6); min-height: 72px; }
.top-nav { display: flex; gap: var(--s-1); margin-right: auto; }
.top-nav a {
  position: relative; padding: 10px 12px; color: var(--silver-2); text-decoration: none; font-size: .9375rem; font-weight: 500;
}
.top-nav a:hover { color: var(--silver); }
.top-nav a[aria-current="page"] { color: var(--silver); }
.top-nav a[aria-current="page"]::after {   /* current page: a short run of thread */
  content: ""; position: absolute; left: 12px; right: 12px; bottom: 4px; border-top: 1.5px solid var(--accent);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 5px, transparent 5px 8px);
          mask: repeating-linear-gradient(90deg, #000 0 5px, transparent 5px 8px);
}
.top-actions { display: flex; align-items: center; gap: var(--s-3); }
.lang { font: 500 var(--fs-label)/1 var(--font-mono); letter-spacing: var(--track-latin); text-transform: uppercase; color: var(--silver-2); text-decoration: none; padding: 12px 6px; }
.lang:lang(ko) { font: 500 .875rem/1 var(--font-body); letter-spacing: 0; text-transform: none; }
.lang:hover { color: var(--silver); }

/* Optional menu button for app screens that need one (a <details>, no script). */
.menu { display: none; position: relative; }
.menu > summary {
  list-style: none; display: grid; place-items: center; width: 44px; height: 44px; cursor: pointer;
  border: 1px solid var(--ctl); border-radius: var(--r-sm);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary svg { width: 20px; height: 20px; }
.menu-panel {
  position: absolute; right: 0; top: calc(100% + 10px); z-index: var(--z-popover); min-width: 220px;
  display: grid; padding: var(--s-2); background: var(--night-3); border: 1px solid var(--line-2); border-radius: var(--r-md);
  box-shadow: var(--shadow-lift);
}
.menu-panel a { padding: 12px 14px; text-decoration: none; color: var(--silver); border-radius: var(--r-sm); }
.menu-panel a:hover { background: var(--night-4); }

/* App header variant (signed-in) */
.app-top .top-inner { min-height: 64px; }
.user-chip { display: inline-flex; align-items: center; gap: 10px; padding: 4px 12px 4px 4px; border: 1px solid var(--ctl); border-radius: var(--r-pill); text-decoration: none; color: var(--silver); font-size: .875rem; font-weight: 500; }
.avatar { display: grid; place-items: center; width: 30px; height: 30px; flex: none; border-radius: 50%; background: var(--silver); color: var(--night-1); font: 700 .8125rem/1 var(--font-body); }
.avatar--staff { background: var(--night-4); color: var(--silver); border: 1px solid var(--line-2); }
.avatar--staff svg { width: 20px; height: 20px; }

/* ───────────────────────── Measuring tape & ruler ─────────────────────────
 * Graphite strip, silver ticks, mono numbers. Decorative only (aria-hidden).
 */
.tape {
  position: relative; height: 28px; overflow: hidden;
  background: linear-gradient(180deg, #1C1F25, var(--surface));
  border-block: 1px solid var(--surface-edge);
  box-shadow: 0 10px 24px -14px rgb(0 0 0 / .8);
}
.tape svg { position: absolute; left: 0; top: 0; width: 2400px; height: 28px; max-width: none; }
.tape-band { overflow: clip; padding-block: 14px; }
.tape--tilt { rotate: -1.2deg; margin-inline: -2%; }
.tape-tick { stroke: var(--silver-3); stroke-width: 1; }
.tape-num { font: 600 9.5px var(--font-mono); fill: var(--silver-2); }
.ruler {        /* a hairline ruler, a quiet divider */
  height: 12px; border-top: 1px solid var(--rule);
  background:
    repeating-linear-gradient(90deg, var(--line-2) 0 1px, transparent 1px var(--tape-unit)) top left / 100% 10px no-repeat,
    repeating-linear-gradient(90deg, var(--line) 0 1px, transparent 1px calc(var(--tape-unit) / 8)) top left / 100% 5px no-repeat;
}

/* ───────────────────────── Surfaces ─────────────────────────
 * .surface: graphite, a 1px edge, a sheen on top, a soft drop. Add .stitched for the seam inside the
 * edge. .card-night is the quieter panel (no sheen, no drop) for lists and app panels.
 */
.surface {
  background: var(--surface) linear-gradient(180deg, var(--surface-sheen), transparent 45%);
  border: 1px solid var(--surface-edge);
  border-radius: var(--r-xs);
  box-shadow: var(--shadow-surface);
}
.surface-2 { background: var(--surface-2); border-radius: var(--r-sm); }
.card-night { background: var(--night-2); border: 1px solid var(--line); border-radius: var(--r-md); }

/* ───────────────────────── Chips (status) ─────────────────────────
 * Korean text: GD Sans 13px. Latin codes (lang="en"): mono 11px uppercase.
 */
.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 1px 9px; border: 1px solid currentColor; border-radius: var(--r-xs);
  font: 600 var(--fs-ko-min)/1.55 var(--font-body); white-space: nowrap;
}
.chip:lang(en) { font: 600 var(--fs-micro)/1.7 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; }
.chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.chip--ok { color: var(--ok); }
.chip--warn { color: var(--warn); }
.chip--no { color: var(--no); }
.chip--info { color: var(--info); }
.chip--mute { color: var(--silver-3); }

/* ───────────────────────── Footer ───────────────────────── */
.site-foot { position: relative; margin-top: var(--s-8); padding: var(--s-7) 0 var(--s-6); background: rgb(5 5 6 / .88); }
.site-foot::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: repeating-linear-gradient(90deg, var(--line-2) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))); }
.foot-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s-5); align-items: center; margin-bottom: var(--s-5); }
.foot-nav { display: flex; flex-wrap: wrap; gap: 4px 18px; font-size: .875rem; }
.foot-nav a { color: var(--silver-2); text-decoration: none; padding: 6px 0; }
.foot-nav a:hover { color: var(--silver); text-decoration: underline; text-decoration-color: var(--accent); }
.foot-nav a[aria-current="page"] { color: var(--silver); }
.foot-nav strong { color: var(--silver); }
.foot-legal { font-size: .8125rem; line-height: 1.75; color: var(--silver-3); max-width: 62rem; }
.foot-legal p { margin: 0 0 .5em; }
.foot-legal a { color: var(--silver-2); }

/* ───────────────────────── Shared responsive ───────────────────────── */
@media (max-width: 760px) {
  .top-inner { flex-wrap: wrap; gap: 0 var(--s-3); min-height: 0; padding-top: 10px; }
  .top-inner:not(:has(.top-nav)) { min-height: 60px; padding-top: 0; }   /* brand only (404): no second row */
  .top-inner > .brand { margin-right: auto; }
  .top-actions { order: 2; }
  .top-nav { order: 3; flex: 1 0 100%; margin: 2px 0 0 -12px; overflow-x: auto; scrollbar-width: none; }
  .top-nav::-webkit-scrollbar { display: none; }
  .top-nav a { white-space: nowrap; padding-block: 12px; }
  .top-nav a:focus-visible { outline-offset: -4px; box-shadow: none; }   /* the row scrolls, so a ring outside the link was cut off */
  .app-top .top-nav, .top-actions .hide-sm { display: none; }
  .app-top .menu { display: block; }
  .app-top .top-inner { flex-wrap: nowrap; padding-top: 0; min-height: 60px; }
  .user-chip .name { display: none; }
  .user-chip { padding: 3px; }
}
@media (max-width: 400px) {      /* brand and actions stay on one row down to 360px */
  .top-inner { column-gap: var(--s-2); }
  .brand { gap: 8px; }
  .brand-word { font-size: 1.25rem; }
  .brand-mark { width: 28px; height: 28px; }
  .top-actions { gap: 6px; }
  .top-actions .lang { padding-inline: 4px; }
  .top-actions .btn--sm { padding-inline: .8em; }
}

/* ===== design/components/app.css ===== */
/* GalaxyDresser — "Silver Night" · app.css
 * Signed-in web app (account, support tickets, wardrobe, pay): page head, forms on a graphite surface,
 * usage tape, claim-ticket list, conversation — and, from 「The web app as web/ builds it」 on, the pages web/ really has
 * (upload, prefab picker, conversion steps, wardrobe, state cards, dialogs, sign-in, footer, the Steam app window).
 * Needs tokens.css + base.css; tools/web/sync-design.mjs joins the three into web/app.css. No load animation on app
 * screens: people move between them all the time, so nothing re-enters on every navigation.
 */

.app-main { padding-block: clamp(28px, 4vw, 56px) var(--s-8); }
.page-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: var(--s-4); margin-bottom: clamp(24px, 4vw, 44px); }
.page-head h1 { font-size: clamp(2.3rem, 1.6rem + 2vw, 3.4rem); }
.page-head .lead { margin: var(--s-3) 0 0; font-size: 1rem; }
.page-head .btn { flex: none; }

/* ───────────────────────── Account: index + form surface ───────────────────────── */
.acct { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: clamp(24px, 4vw, 56px); align-items: start; }
.toc { position: sticky; top: 96px; display: grid; gap: 2px; }
.toc a { display: grid; grid-template-columns: 34px 1fr; padding: 10px 12px; color: var(--silver-2); text-decoration: none; border-radius: var(--r-sm); font-size: .9375rem; }
.toc a span { font: 500 var(--fs-label)/1.9 var(--font-mono); color: var(--silver-3); }
.toc a:hover { background: var(--night-3); color: var(--silver); }
.toc a[aria-current="true"] { background: var(--night-3); color: var(--silver); box-shadow: inset 2px 0 0 var(--accent); }

.form-card { position: relative; padding: clamp(24px, 4vw, 52px); padding-top: clamp(52px, 5vw, 64px); }
.form-card-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--s-3); padding-bottom: var(--s-5); margin-bottom: var(--s-2); border-bottom: 2px solid var(--silver); }
.form-card-head h2 { font: 700 1.5rem/1.3 var(--font-body); letter-spacing: -.015em; }
.fsec { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: var(--s-5) clamp(20px, 3vw, 44px); padding: var(--s-6) 0; border-bottom: 1px dashed var(--line-2); }
.fsec:last-of-type { border-bottom: 0; }
.fsec-head .num { font: 500 var(--fs-label)/1 var(--font-mono); color: var(--silver-3); letter-spacing: .08em; }
.fsec-head h3 { margin-top: 6px; }
.fsec-head p { font-size: .875rem; color: var(--silver-3); margin: 6px 0 0; line-height: 1.6; }
.fsec-body { display: grid; gap: var(--s-5); }
.frow { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-5); }

/* Fields. Korean field labels are GD Sans 13px; control boundaries use --ctl (3:1 or more). */
.field { display: grid; gap: 4px; align-content: start; }
.field > label, .field > .flabel, fieldset > legend { font: 600 var(--fs-ko-min)/1.4 var(--font-body); color: var(--fg-2); padding: 0; }
.field .opt { font-weight: 500; color: var(--fg-3); }
.input {
  width: 100%; min-height: 44px; padding: 10px 2px 8px; border: 0; border-bottom: 1.5px solid var(--ctl); border-radius: 0;
  background: transparent; color: var(--fg); font-size: 1.0625rem; font-weight: 500;
  transition: border-color var(--t-fast) ease, background-color var(--t-fast) ease;
}
.input:hover { border-bottom-color: var(--ctl-hover); }
.input:focus-visible { outline: none; box-shadow: none; border-radius: 0; border-bottom: 2.5px solid var(--accent); background: linear-gradient(0deg, var(--blue-soft), transparent 70%); }
.input[readonly] { color: var(--fg-2); border-bottom-style: dashed; }
.input::placeholder { color: var(--fg-3); opacity: 1; }
.hint { font-size: var(--fs-ko-min); color: var(--fg-3); line-height: 1.55; }
.hint.err { color: var(--no); font-weight: 600; }
textarea.input { min-height: 120px; resize: vertical; line-height: 1.7; }
.input--box { padding: 12px 14px; border: 1.5px solid var(--ctl); border-radius: var(--r-sm); background: var(--field-bg); }
.input--box:focus-visible { border: 1.5px solid var(--accent); box-shadow: 0 0 0 3px var(--blue-soft); border-radius: var(--r-sm); }
.id-line { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; padding: 14px 16px; background: var(--surface-2); border-radius: var(--r-sm); }
.id-line .who { font-weight: 700; }
.id-line code { color: var(--silver-2); letter-spacing: .04em; }

fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.choices { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.choice { position: relative; }
.choice input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.choice span {
  display: inline-flex; align-items: center; min-height: 42px; padding: 0 16px; border: 1.5px solid var(--ctl); border-radius: var(--r-sm);
  font-weight: 600; font-size: .9375rem; color: var(--fg-2); position: relative;
}
.choice input:checked + span { background: var(--silver); color: var(--night-1); border-color: var(--silver); }
.choice input:checked + span::after { content: ""; position: absolute; inset: 3px; border: 1px dashed rgb(21 23 27 / .35); border-radius: 2px; }
.choice input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 3px; }

/* Toggle: the knob is a four-hole sewing button. Off = graphite track with a --ctl edge (3:1+);
   on = silver track. Not blue: the blue on this screen is the save button. */
.switch { display: grid; grid-template-columns: 1fr auto; gap: var(--s-4); align-items: center; padding: 14px 0; border-bottom: 1px solid var(--rule); cursor: pointer; }
.switch:last-child { border-bottom: 0; }
.switch b { display: block; font-weight: 600; }
.switch small { display: block; color: var(--fg-3); font-size: var(--fs-ko-min); margin-top: 2px; }
.switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.track { position: relative; width: 54px; height: 30px; border-radius: 15px; background: var(--surface-3); border: 1.5px solid var(--ctl); transition: background-color var(--t-mid) ease, border-color var(--t-mid) ease; }
.track::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 23px; height: 23px; border-radius: 50%;
  background:
    radial-gradient(circle at 38% 38%, var(--night-4) 0 1.4px, transparent 1.8px),
    radial-gradient(circle at 62% 38%, var(--night-4) 0 1.4px, transparent 1.8px),
    radial-gradient(circle at 38% 62%, var(--night-4) 0 1.4px, transparent 1.8px),
    radial-gradient(circle at 62% 62%, var(--night-4) 0 1.4px, transparent 1.8px),
    radial-gradient(circle, #E6E9EE 58%, #9AA1AD 62%, #E6E9EE 70%);
  box-shadow: 0 1px 3px rgb(0 0 0 / .35);
  transition: translate var(--t-mid) var(--ease-out);
}
.switch input:checked + .track { background: var(--silver-2); border-color: var(--silver-2); }
.switch input:checked + .track::after {
  background:
    radial-gradient(circle at 38% 38%, var(--silver-3) 0 1.4px, transparent 1.8px),
    radial-gradient(circle at 62% 38%, var(--silver-3) 0 1.4px, transparent 1.8px),
    radial-gradient(circle at 38% 62%, var(--silver-3) 0 1.4px, transparent 1.8px),
    radial-gradient(circle at 62% 62%, var(--silver-3) 0 1.4px, transparent 1.8px),
    radial-gradient(circle, var(--night-3) 58%, var(--night-1) 62%, var(--night-3) 70%);
}
.switch input:checked + .track::after { translate: 24px 0; }
.switch input:focus-visible + .track { outline: 2px solid var(--focus); outline-offset: 3px; }

.plan-line { display: grid; grid-template-columns: repeat(3, minmax(0, auto)); justify-content: start; gap: 12px clamp(20px, 3vw, 40px); margin: 0; padding: 16px 18px; background: var(--surface-2); border-radius: var(--r-sm); }
.plan-line dt { font: 500 var(--fs-ko-min)/1.6 var(--font-body); color: var(--silver-3); }
.plan-line dd { margin: 2px 0 0; font-weight: 700; color: var(--silver); }
.plan-line dd .muted { display: block; font-weight: 500; }

/* Usage as a measuring tape (graphite, silver ticks). The fill is an SVG <rect> whose width attribute (0–100) the view sets with
   setAttribute — CSP-safe, no inline style, one element for any value. The tape carries role="meter". */
.meter { display: grid; gap: 10px; }
.meter-top { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s-3); }
.meter-val { font: var(--fw-num) 2.6rem/1 var(--font-display); letter-spacing: -.03em; color: var(--silver); }
.meter-val small { font: 500 .9375rem var(--font-body); color: var(--silver-3); letter-spacing: 0; margin-left: 6px; }
.meter-tape {
  position: relative; height: 42px; border-radius: 2px; border: 1px solid var(--surface-edge);
  background:
    repeating-linear-gradient(90deg, var(--silver) 0 1px, transparent 1px 10%) left top / calc(100% + 1px) 11px no-repeat,
    repeating-linear-gradient(90deg, var(--silver) 0 1px, transparent 1px 10%) left bottom / calc(100% + 1px) 11px no-repeat,
    repeating-linear-gradient(90deg, var(--silver-2) 0 1px, transparent 1px 5%) left top / 100% 7px no-repeat,
    repeating-linear-gradient(90deg, var(--silver-2) 0 1px, transparent 1px 5%) left bottom / 100% 7px no-repeat,
    repeating-linear-gradient(90deg, var(--silver-3) 0 1px, transparent 1px 1%) left top / 100% 4px no-repeat,
    repeating-linear-gradient(90deg, var(--silver-3) 0 1px, transparent 1px 1%) left bottom / 100% 4px no-repeat,
    linear-gradient(180deg, #1C1F25, var(--surface));
}
.meter-svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.meter-fill { fill: var(--blue-soft); }
.meter-end { stroke: var(--accent); stroke-width: 2.4; stroke-dasharray: 11 20 11; }   /* top and bottom bands only: never across the numbers */
.meter-nums { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(10, 1fr); align-items: center; pointer-events: none; }
.meter-nums span { padding-left: 5px; font: 600 var(--fs-micro)/1 var(--font-mono); color: var(--silver-2); }
.meter-nums span:nth-child(6) { color: var(--silver); font-weight: 700; }      /* 50: the half-way mark */

.devices li { display: grid; grid-template-columns: 40px 1fr auto; gap: 14px; align-items: center; padding: 14px 0; border-bottom: 1px solid var(--rule); }
.devices li:last-child { border-bottom: 0; }
.dev-ico { width: 40px; height: 40px; display: grid; place-items: center; border: 1px solid var(--rule-2); border-radius: var(--r-sm); }
.dev-ico svg { width: 22px; height: 22px; }
.devices b { display: block; font-weight: 600; }
.devices small { color: var(--fg-3); font-size: var(--fs-ko-min); }

/* Save bar: present only while the form has unsaved changes (the view sets data-dirty on the form).
   It sticks to the bottom of the viewport while the card scrolls; z-index stays far below Paddle. */
.save-bar { display: none; }
.form-card[data-dirty] .save-bar {
  position: sticky; bottom: 0; z-index: var(--z-sticky);
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: var(--s-3);
  margin: var(--s-2) calc(-1 * clamp(24px, 4vw, 52px)) calc(-1 * clamp(24px, 4vw, 52px));
  padding: var(--s-4) clamp(24px, 4vw, 52px);
  background: var(--surface); border-top: 2px solid var(--silver); box-shadow: 0 -12px 24px -18px rgb(0 0 0 / .45);
}
.save-bar .hint { margin: 0; font-weight: 600; color: var(--silver-2); }
.danger { margin-top: var(--s-6); display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--s-4); padding: var(--s-5); border: 1px dashed rgb(255 138 128 / .7); border-radius: var(--r-md); }
.danger h2 { font: 700 1.125rem/1.4 var(--font-body); letter-spacing: 0; }
.danger p { color: var(--silver-2); margin: 4px 0 0; font-size: .9375rem; }

/* ───────────────────────── Support: claim tickets + conversation ───────────────────────── */
.support { display: grid; grid-template-columns: minmax(300px, 380px) minmax(0, 1fr); gap: clamp(20px, 3vw, 40px); align-items: start; }
.filters { display: flex; gap: 6px; margin-bottom: var(--s-4); flex-wrap: wrap; }
.filters a { padding: 7px 13px; border: 1px solid var(--ctl); border-radius: var(--r-pill); font-size: var(--fs-ko-min); font-weight: 600; color: var(--silver-2); text-decoration: none; }
.filters a:hover { border-color: var(--silver-2); color: var(--silver); }
.filters a[aria-current="true"] { background: var(--silver); color: var(--night-1); border-color: var(--silver); }
.filters a span { font-family: var(--font-mono); margin-left: 5px; }
.stubs { display: grid; gap: 12px; }
.stub {
  --perf: 82px;
  position: relative; display: grid; grid-template-columns: var(--perf) 1fr; min-height: 104px; text-decoration: none; color: var(--silver);
  background: var(--night-2);
  -webkit-mask: radial-gradient(circle 8px at var(--perf) 0, #0000 96%, #000 100%) top / 100% 51% no-repeat,
                radial-gradient(circle 8px at var(--perf) 100%, #0000 96%, #000 100%) bottom / 100% 51% no-repeat;
          mask: radial-gradient(circle 8px at var(--perf) 0, #0000 96%, #000 100%) top / 100% 51% no-repeat,
                radial-gradient(circle 8px at var(--perf) 100%, #0000 96%, #000 100%) bottom / 100% 51% no-repeat;
  transition: background-color var(--t-fast) ease;
}
.stub:hover { background: var(--night-3); }
.stub-no { display: grid; align-content: center; justify-items: center; gap: 2px; padding: 10px 6px;
  background: radial-gradient(circle, var(--night-1) 0 2px, transparent 2.5px) right center / 4px 10px repeat-y; }
.stub-no .label { font-size: var(--fs-micro); }
.stub-no b { font: var(--fw-num) 1.5rem/1 var(--font-display); letter-spacing: -.02em; }
.stub-body { padding: 14px 16px 14px 18px; display: grid; gap: 8px; align-content: center; }
.stub-body h3 { font-size: .9688rem; line-height: 1.45; letter-spacing: 0; }
.stub-meta { display: flex; flex-wrap: wrap; gap: 6px 12px; align-items: center; font-size: var(--fs-ko-min); color: var(--silver-3); }
.stub[aria-current="true"] { background: var(--surface); color: var(--silver); box-shadow: inset 2px 0 0 var(--accent); }
.stub[aria-current="true"] .stub-no { background-image: radial-gradient(circle, var(--night-1) 0 2px, transparent 2.5px); }
.stub[aria-current="true"] .label, .stub[aria-current="true"] .stub-meta { color: var(--silver-3); }
.stub[aria-current="true"] .chip--info { color: var(--info); }
.stub[aria-current="true"] .chip--mute { color: var(--silver-3); }
.back-link { display: none; align-items: center; gap: 6px; margin-bottom: var(--s-4); padding: 6px 0; font-size: .9375rem; font-weight: 600; color: var(--silver-2); text-decoration: none; }
.back-link svg { width: 16px; height: 16px; }

.thread-panel { padding: clamp(20px, 3vw, 36px); }
.thread-head { display: grid; gap: 10px; padding-bottom: var(--s-5); border-bottom: 1px solid var(--line-2); margin-bottom: var(--s-6); }
.thread-head h2 { font: 700 clamp(1.3rem, 1.15rem + .6vw, 1.625rem)/1.35 var(--font-body); letter-spacing: -.015em; }
.thread-meta { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; font-size: var(--fs-ko-min); color: var(--silver-3); }
.thread-meta b { color: var(--silver-2); font-weight: 600; }
.thread-meta code { color: var(--silver-2); font-size: .8125rem; }

/* Conversation: the blue basting thread runs down the side. The reply from support is a raised
   graphite surface (the thing to read); the customer's own messages are quiet night cards. */
.msgs { position: relative; display: grid; gap: var(--s-5); padding-left: 34px; }
.msgs::before {
  content: ""; position: absolute; left: 11px; top: 8px; bottom: 8px; width: 1.6px;
  background: repeating-linear-gradient(180deg, var(--accent) 0 7px, transparent 7px 12px);
  opacity: .75;
}
.msg { position: relative; padding: 16px 20px; border-radius: var(--r-sm); }
.msg::before { content: ""; position: absolute; left: -29px; top: 22px; width: 12px; height: 12px; border-radius: 50%; background: var(--night-1); border: 2px solid var(--silver-3); }
.msg--user { background: var(--night-3); border: 1px solid var(--line); }
.msg--staff { padding: 20px 24px 20px 30px; }
.msg--staff::before { background: var(--accent); border-color: var(--accent); }
.msg--staff::after {      /* a basted margin, as on a pattern-maker's note */
  content: ""; position: absolute; left: 14px; top: 14px; bottom: 14px; width: 1.4px;
  background: repeating-linear-gradient(180deg, var(--line-2) 0 5px, transparent 5px 9px);
}
.msg-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 8px; }
.msg-head b { font-weight: 700; }
.msg-head time { margin-left: auto; font: 500 var(--fs-label)/1 var(--font-mono); letter-spacing: .04em; color: var(--fg-3); }
.msg p { margin: 0 0 .6em; font-size: .9688rem; }
.msg p:last-child { margin-bottom: 0; }
.msg--user p { color: var(--silver-2); }
.msg--staff p { color: var(--silver); }
.msg .avatar { width: 28px; height: 28px; font-size: .8125rem; }
.attach { display: inline-flex; align-items: center; gap: 10px; margin-top: 8px; padding: 8px 12px; border: 1px dashed var(--rule-2); border-radius: var(--r-sm); font: 500 .8125rem/1.3 var(--font-mono); color: var(--fg-2); text-decoration: none; }
.attach svg { width: 16px; height: 16px; }
.event { position: relative; font-size: var(--fs-ko-min); color: var(--silver-3); padding-left: 2px; }
.event::before { content: ""; position: absolute; left: -26px; top: .55em; width: 6px; height: 6px; background: var(--silver-3); border-radius: 50%; }
.event code { color: var(--silver-2); }

/* Composer: two layers only (a graphite slip on the night panel). The textarea is ruled with one
   --ctl rule at the bottom as its boundary. Send is the strong action; closing the ticket is quiet. */
.composer { margin-top: var(--s-6); padding: 18px 20px 14px; }
.composer > label { display: block; margin-bottom: 4px; font: 600 var(--fs-ko-min)/1.4 var(--font-body); color: var(--silver-2); }
.composer textarea {
  display: block; width: 100%; min-height: 128px; resize: vertical; padding: 4px 2px 6px; border: 0; border-bottom: 1.5px solid var(--ctl); border-radius: 0;
  background: repeating-linear-gradient(180deg, transparent 0 calc(1.75em - 1px), var(--line) calc(1.75em - 1px) 1.75em) local;
  line-height: 1.75; font-size: .9688rem; color: var(--silver);
}
.composer textarea::placeholder { color: var(--silver-3); opacity: 1; }
.composer textarea:focus-visible { outline: none; box-shadow: none; border-radius: 0; border-bottom: 2.5px solid var(--accent); }
.composer-bar { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-3); align-items: center; margin-top: 12px; }
.composer-bar .hint { margin: 0 auto 0 0; }
.composer-bar .send { min-width: 128px; }

/* ───────────────────────── Responsive ───────────────────────── */
@media (max-width: 960px) {
  .acct { grid-template-columns: minmax(0, 1fr); }
  .toc { position: static; display: flex; overflow-x: auto; gap: 6px; padding-bottom: 4px; scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 48px), transparent);
            mask-image: linear-gradient(90deg, #000 calc(100% - 48px), transparent); }
  .toc::-webkit-scrollbar { display: none; }
  .toc a { grid-template-columns: auto auto; gap: 6px; white-space: nowrap; border: 1px solid var(--ctl); }
  .toc a:last-child { margin-right: 40px; }
  .fsec { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
  .support { grid-template-columns: minmax(0, 1fr); }
  /* two steps on a phone: tickets.html shows the list, tickets.html?id=… the conversation */
  .support[data-view="detail"] .support-list { display: none; }
  .support[data-view="list"] .thread-panel { display: none; }
  .back-link { display: inline-flex; }
}
@media (max-width: 760px) {
  .frow { grid-template-columns: minmax(0, 1fr); }
  .plan-line { grid-template-columns: minmax(0, 1fr); }
  .danger { padding: var(--s-4); }
  .form-card[data-dirty] .save-bar { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
  .save-bar .hint { grid-column: 1 / -1; }
  .save-bar .btn { width: 100%; }
  .page-head { align-items: start; }
}
@media (max-width: 520px) {
  .stub { --perf: 70px; }
  .msgs { padding-left: 24px; }
  .msgs::before { left: 6px; }
  .msg::before { left: -24px; }
  .event::before { left: -21px; }
  .msg { padding: 14px 16px; }
  .msg--staff { padding: 16px 16px 16px 26px; }
  .msg--staff::after { left: 11px; }
  .composer-bar .send { flex: 1 0 100%; order: 3; }
}

/* ═════════════════════════ The web app as web/ builds it ═════════════════════════
 * The pages under web/ and the markup their views make (web/views/*.js): frame, header, upload, prefab picker,
 * conversion steps, wardrobe table, state cards, dialogs, sign-in, Warudo link, footer, the draft policy pages and
 * the Steam app's own window. tools/web/sync-design.mjs writes tokens.css + base.css + this file into web/app.css —
 * one file, because the plugin's loopback page (local.html) can fetch only that one stylesheet.
 * Calm: nothing animates in. The only motion is a busy spinner; state changes are instant or a 140 ms colour fade.
 * Every web page has <body class="app">; the rules that reset the page rhythm are scoped to it so the mockups keep theirs.
 */

/* ───────────────────────── Frame ───────────────────────── */
body.app { display: flex; flex-direction: column; }      /* the footer sits at the bottom of a short page */
html:has(> body.app) { scrollbar-gutter: stable; }       /* a long upload list bringing the scrollbar does not shift the page */
body.app > main { flex: 1 0 auto; }
body.app :is(p, figure, dl, dd) { margin: 0; }            /* views space their blocks with gap, not margins */
.flow { display: flex; flex-direction: column; gap: var(--s-6); }
.wrap--narrow { width: min(100% - 2 * var(--gutter), 880px); }
.wrap--slim { width: min(100% - 2 * var(--gutter), 560px); }
.stack { display: flex; flex-direction: column; gap: var(--s-5); min-width: 0; }
.row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; }
.row:has(> [hidden]):not(:has(> :not([hidden]))) { display: none; }   /* every button in it hidden: no empty gap */
.spacer { flex: 1 1 0; }
.end { align-self: flex-end; }
.small { color: var(--fg-3); }
.fine { font-size: var(--fs-ko-min); line-height: 1.75; color: var(--fg-3); }
.fine a:not(.btn), .small a:not(.btn) { color: var(--fg-2); text-decoration-color: var(--line-3); }
.fine a:not(.btn):hover, .small a:not(.btn):hover { color: var(--fg); text-decoration-color: var(--accent); }

/* Page head: eyebrow, the display title, a lead. */
.head { display: grid; gap: var(--s-3); }
.head h1 { font-size: clamp(2.2rem, 1.55rem + 2vw, 3.25rem); }
.head .eyebrow { margin: 0; }
.head .eyebrow:empty { display: none; }
.head .lead { margin: 0; max-width: 44em; }

/* Card and panel titles are Sans 700 at their own size (base.css gives every h2 the large display size). */
:is(.panel, .box, .card, .plan, .dlg, .product, .admin-section) h2,
.drop-title, .box-title, .plan-title, .dlg-title {
  font: 700 1.25rem/1.4 var(--font-body); letter-spacing: -.012em;
}
.section-head > h2 { font-size: clamp(1.75rem, 1.4rem + 1.2vw, 2.4rem); }
.panel .section-head > h2 { font: 700 1.25rem/1.4 var(--font-body); letter-spacing: -.012em; }

/* A waiting line: a thin ring turning. Under reduced motion it turns slowly (it still says "busy"). */
.loading { display: inline-flex; align-items: center; gap: 12px; color: var(--fg-2); font-size: .9375rem; }
.loading::before {
  content: ""; flex: none; width: 16px; height: 16px; border-radius: 50%;
  border: 1.5px solid var(--line-2); border-top-color: var(--silver); animation: gd-spin 1s linear infinite;
}
@keyframes gd-spin { to { rotate: 360deg; } }

/* ───────────────────────── Buttons: the states the app needs ───────────────────────── */
.btn:is(:disabled, [aria-disabled="true"]),
.btn:is(:disabled, [aria-disabled="true"]):hover {
  --btn-bg: transparent; --btn-fg: var(--silver-3); --btn-bd: var(--line-2);
  background-color: var(--btn-bg); cursor: not-allowed; transform: none;
}
.btn:is(.btn--primary, .btn--silver):is(:disabled, [aria-disabled="true"]) { --btn-bg: var(--surface-3); --btn-bd: transparent; }
.btn:is(.btn--primary, .btn--silver):is(:disabled, [aria-disabled="true"])::after { display: none; }
.btn[aria-busy="true"]::after {             /* busy: a small ring in place of the woven seam */
  content: ""; position: static; inset: auto; width: 15px; height: 15px; flex: none; border-radius: 50%; background: none;
  border: 2px solid currentColor; border-right-color: transparent; animation: gd-spin .8s linear infinite;
}
.btn-dl::before {                            /* download glyph (currentColor) */
  content: ""; width: 15px; height: 15px; flex: none; background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2.5v7.5M4.8 7l3.2 3.2L11.2 7M3 13h10' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2.5v7.5M4.8 7l3.2 3.2L11.2 7M3 13h10' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
@media (pointer: coarse) { .btn--sm { min-height: 44px; } }

/* ───────────────────────── Form controls ─────────────────────────
 * Silver, never blue (the blue on a screen is its main button). Boundaries are --ctl (3:1 or more).
 */
input[type="checkbox"], input[type="radio"] {
  -webkit-appearance: none; appearance: none; margin: 0; flex: none; width: 22px; height: 22px; cursor: pointer;
  border: 1.5px solid var(--ctl); background: var(--field-bg) center / 15px 15px no-repeat;
  transition: border-color var(--t-fast) ease, background-color var(--t-fast) ease;
}
input[type="checkbox"], input[type="checkbox"]:focus-visible { border-radius: 3px; }
input[type="radio"], input[type="radio"]:focus-visible { border-radius: 50%; }
input:is([type="checkbox"], [type="radio"]):hover { border-color: var(--ctl-hover); }
input[type="checkbox"]:checked {
  border-color: var(--silver); background-color: var(--silver);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.4 8.6l3 3 6.2-6.7' fill='none' stroke='%230A0B0D' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
input[type="radio"]:checked { border-color: var(--silver); background-image: radial-gradient(circle, var(--silver) 0 5px, transparent 5.6px); }
input:is([type="checkbox"], [type="radio"]):disabled { cursor: not-allowed; border-style: dashed; border-color: var(--line-2); background-color: transparent; }

select {
  -webkit-appearance: none; appearance: none; min-height: 44px; max-width: 100%; padding: 0 38px 0 12px; cursor: pointer;
  border: 1.5px solid var(--ctl); border-radius: var(--r-sm); color: var(--fg); font-size: .9375rem; font-weight: 500;
  background: var(--field-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 6l4 4 4-4' fill='none' stroke='%23C4C9D2' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") right 12px center / 14px 14px no-repeat;
  transition: border-color var(--t-fast) ease;
}
select:hover { border-color: var(--ctl-hover); }
select:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--blue-soft); border-radius: var(--r-sm); }
select option { background: var(--night-3); color: var(--silver); }

/* Text fields web/ makes (no .input class) are boxed like .input--box: they sit on night cards and graphite alike. */
.field { min-width: 0; }
.field :is(input:not(.input):not([type="checkbox"]):not([type="radio"]), textarea:not(.input)) {
  width: 100%; min-height: 46px; padding: 11px 14px; border: 1.5px solid var(--ctl); border-radius: var(--r-sm);
  background: var(--field-bg); color: var(--fg); font-size: 1rem; font-weight: 500;
  transition: border-color var(--t-fast) ease, box-shadow var(--t-fast) ease;
}
.field textarea:not(.input) { min-height: 150px; resize: vertical; line-height: 1.7; }
.field :is(input:not(.input), textarea:not(.input)):hover { border-color: var(--ctl-hover); }
.field :is(input:not(.input):not([type="checkbox"]):not([type="radio"]), textarea:not(.input)):focus-visible {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--blue-soft); border-radius: var(--r-sm);
}
.field ::placeholder { color: var(--fg-3); opacity: 1; }
.field .small { font-size: var(--fs-ko-min); line-height: 1.6; }
/* One line under a form that says what went wrong (role="alert"). */
.form-msg {
  width: 100%; padding: 10px 14px; border: 1px solid rgb(255 138 128 / .5); border-radius: var(--r-sm);
  background: rgb(255 138 128 / .06); color: var(--no); font-size: .875rem; font-weight: 600; line-height: 1.6;
}
.check { display: flex; align-items: flex-start; gap: 12px; cursor: pointer; font-size: .9688rem; line-height: 1.65; }
.check input { margin-top: 1px; }

/* ───────────────────────── Header (views/header.js draws it into header#top) ─────────────────────────
 * One row on wide screens: mark · Warudo chip · page links … free count · 구독하기 · answers · avatar.
 * Below 960px: row 1 mark … 구독하기 · avatar; row 2 Warudo chip · page links · free count · answers.
 * Below 480px: row 1 mark … avatar (or the Steam login); 구독하기 / 결제 수단 바꾸기 move to row 2.
 */
.app-bar .top-inner { position: relative; flex-wrap: wrap; gap: 8px var(--s-4); min-height: 68px; padding-block: 10px; }
.app-bar .brand { margin-right: var(--s-2); }
.app-bar .top-nav { margin: 0; }
.app-bar .top-nav a { white-space: nowrap; }
.brand-mark:not(svg) {            /* the hanger mark as an image, for markup made by script (h() cannot make SVG) */
  display: block; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 14V10.6C16 8.8 19.4 8.2 19.4 5.8C19.4 3.6 17.7 2.3 15.8 2.3C14.2 2.3 13 3.3 13 4.7M16 14L3.2 24.6H28.8Z' fill='none' stroke='%23F2F4F7' stroke-opacity='.8' stroke-width='1.5' stroke-linejoin='round' stroke-linecap='round'/%3E%3Cg fill='%23F2F4F7'%3E%3Ccircle cx='3.2' cy='24.6' r='2.1'/%3E%3Ccircle cx='28.8' cy='24.6' r='2.1'/%3E%3Ccircle cx='19.4' cy='5.8' r='1.25'/%3E%3Ccircle cx='15.8' cy='2.3' r='1.15'/%3E%3Cpath d='M16 10.3c.5 2.3 1.4 3.2 3.7 3.7-2.3.5-3.2 1.4-3.7 3.7-.5-2.3-1.4-3.2-3.7-3.7 2.3-.5 3.2-1.4 3.7-3.7z'/%3E%3C/g%3E%3Ccircle cx='13' cy='4.7' r='1.6' fill='%233D8BFF'/%3E%3C/svg%3E") center / contain no-repeat;
}
.quota {                          /* a status, not a control: no edge */
  display: inline-flex; align-items: center; gap: 8px; min-height: 32px;
  font-size: .875rem; font-weight: 500; color: var(--fg-2); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.quota::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--silver-3); }
a.chip { text-decoration: none; }
/* The language switch (views/header.js; the loopback page's in views/local.js): 한국어 / English / 日本語, each name in
   itself, the current one silver with a short run of thread — as on the public site. Below 1200px the names become
   KO / EN / JA (the names stay for screen readers: a full header needs the room); below 960px the switch joins row 2,
   and below 480px a signed-in header keeps it on row 1 beside the avatar (row 2 is full there). */
.lang-switch { display: inline-flex; align-items: center; }
.lang-switch :is(a, button) {
  position: relative; padding: 10px 6px; border: 0; background: none; cursor: pointer;
  font: 500 .8125rem/1 var(--font-body); letter-spacing: 0; color: var(--silver-2); text-decoration: none; white-space: nowrap;
}
.lang-switch :is(a, button) + :is(a, button)::before {
  content: ""; position: absolute; left: 0; top: 50%; height: 12px; translate: 0 -50%; border-left: 1px solid var(--line-2);
}
.lang-switch :is(a, button):hover, .lang-switch [aria-current] { color: var(--silver); }
.lang-switch [aria-current]::after {
  content: ""; position: absolute; left: 6px; right: 6px; bottom: 4px; border-top: 1.5px solid var(--accent);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 5px, transparent 5px 8px);
          mask: repeating-linear-gradient(90deg, #000 0 5px, transparent 5px 8px);
}
.lang-code { display: none; font: 500 var(--fs-label)/1 var(--font-mono); letter-spacing: var(--track-latin); }
@media (max-width: 1199px) {
  .lang-switch .lang-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .lang-switch .lang-code { display: inline; }
}
a.chip:hover { text-decoration: underline; text-underline-offset: .2em; }

/* The account menu: a <details>; E2E and app.js rely on details.account and its summary. */
.account { position: static; }
.account > summary {
  list-style: none; cursor: pointer; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  background: var(--silver); color: var(--night-1); font: 700 .9375rem/1 var(--font-body);
  box-shadow: 0 0 0 1px var(--line-2), 0 0 0 4px var(--night-1);
}
.account > summary::-webkit-details-marker { display: none; }
.account > summary:hover { background: #FFFFFF; }
.account[open] > summary { box-shadow: 0 0 0 1px var(--silver-2), 0 0 0 4px var(--night-1); }
.account-menu {
  position: absolute; right: 0; top: calc(100% - 2px); z-index: var(--z-popover);
  display: grid; gap: 2px; min-width: 248px; max-width: calc(100vw - 2 * var(--gutter)); padding: var(--s-2);
  background: var(--night-3); border: 1px solid var(--line-2); border-radius: var(--r-md); box-shadow: var(--shadow-lift);
}
.account-menu .who { padding: 8px 12px 0; font-weight: 700; color: var(--fg); }
.account-menu .sid { padding: 0 12px 10px; margin-bottom: 4px; border-bottom: 1px dashed var(--line-2); font: 500 var(--fs-label)/1.6 var(--font-mono); color: var(--fg-3); }
.account-menu .btn {
  --btn-bd: transparent; justify-content: flex-start; width: 100%; min-height: 42px; padding: 0 12px; font-weight: 500;
}
.account-menu .btn:hover { --btn-bd: transparent; background-color: var(--night-4); }
.account-menu .btn .chip { margin-left: auto; }

/* ───────────────────────── State cards (views/cards.js: section.state.<tone>) ─────────────────────────
 * A quiet night card; the tone is a 2px bar at its left edge and the colour of the title (a dot before it).
 */
.states { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 420px), 1fr)); align-items: start; gap: var(--s-4); }
.states:empty { display: none; }
.state {
  --tone: var(--info);
  position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 10px; min-width: 0;
  padding: 20px 22px 20px 24px; background: var(--night-2); border: 1px solid var(--line); border-radius: var(--r-md);
}
.state::before { content: ""; position: absolute; left: -1px; top: 18px; bottom: 18px; width: 2px; background: var(--tone); }
.state.ok { --tone: var(--ok); }
.state.warn { --tone: var(--warn); border-color: rgb(232 194 122 / .3); }
.state.err { --tone: var(--no); border-color: rgb(255 138 128 / .35); }
.state-title { display: flex; align-items: center; gap: 10px; font: 700 1rem/1.45 var(--font-body); letter-spacing: 0; color: var(--fg); }
.state-title::before { content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--tone); }
.state.warn .state-title { color: var(--warn); }
.state.err .state-title { color: var(--no); }
.state.ok .state-title { color: var(--ok); }
.state-body { font-size: .9688rem; line-height: 1.7; color: var(--fg); }
.state .small { font-size: .875rem; line-height: 1.65; }
.state > .btn, .state .row { margin-top: 4px; }
.state details { font-size: .875rem; }
.state details > p { margin-top: 10px; }
:is(.state, .prefab, .notes) ul { margin-top: 8px; display: grid; gap: 4px; color: var(--fg-3); font-size: var(--fs-ko-min); }
:is(.state, .prefab, .notes) li { position: relative; padding-left: 18px; }
:is(.state, .prefab, .notes) li::before {      /* two stitches as the marker */
  content: ""; position: absolute; left: 1px; top: .78em; width: 9px; height: 0; border-top: 1.5px solid var(--silver-3);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 6px);
          mask: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 6px);
}
/* Disclosure toggles (자세히 / 빠진 파일 보기): small ghost pills with a chevron. */
:is(.state, .prefab) details > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; min-height: 34px; padding: 0 12px;
  border: 1px solid var(--ctl); border-radius: var(--r-sm); color: var(--fg-2); font-size: var(--fs-ko-min); font-weight: 600;
  transition: border-color var(--t-fast) ease, background-color var(--t-fast) ease;
}
:is(.state, .prefab) details > summary:hover { border-color: var(--ctl-hover); background-color: rgb(242 244 247 / .05); }
:is(.state, .prefab) details > summary::-webkit-details-marker { display: none; }
:is(.state, .prefab) details > summary::before {
  content: ""; width: 6px; height: 6px; flex: none; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; rotate: 45deg; transition: rotate var(--t-fast) ease, margin var(--t-fast) ease;
}
:is(.state, .prefab) details[open] > summary::before { rotate: -135deg; margin-top: 3px; }
@media (pointer: coarse) { :is(.state, .prefab) details > summary { min-height: 40px; } }

/* ───────────────────────── Panels (sign-in, Warudo link, account, support) ───────────────────────── */
.panel {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-4); min-width: 0;
  padding: clamp(22px, 3vw, 32px); background: var(--night-2); border: 1px solid var(--line); border-radius: var(--r-md);
}
.panel > .muted { color: var(--fg-2); }
/* The sign-in panel is the page's one thing to do while signed out: a graphite surface with its seam. */
.login-panel {
  background: var(--surface) linear-gradient(180deg, var(--surface-sheen), transparent 45%);
  border-color: var(--surface-edge); border-radius: var(--r-xs); box-shadow: var(--shadow-surface);
  padding: clamp(26px, 3.4vw, 40px);
}
.login-area, .login-start, .login-wait { width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.login-wait { padding: 18px 20px; background: var(--surface-2); border-radius: var(--r-sm); }
.panel:not(.login-panel) .login-wait { background: var(--night-3); }
.login-wait .state-title { font-size: 1rem; }
.login-wait.info .state-title::before { background: var(--info); }
.login-wait.ok .state-title, .login-wait.ok .login-status { color: var(--ok); }
.login-wait.ok .state-title::before { background: var(--ok); }
.login-wait.warn .state-title, .login-wait.warn .login-status { color: var(--warn); }
.login-wait.warn .state-title::before { background: var(--warn); }
.login-wait.err .state-title, .login-wait.err .login-status { color: var(--no); }
.login-wait.err .state-title::before { background: var(--no); }
.login-code-box { display: grid; gap: 6px; }
.login-code {
  font: 600 2.5rem/1.1 var(--font-mono); letter-spacing: .12em; color: var(--silver);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.login-status { font-size: .9688rem; line-height: 1.65; color: var(--fg); }
.login-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.login-fallback { color: var(--fg); text-decoration-color: var(--line-3); }
.login-fallback:hover { text-decoration-color: var(--accent); }
.devlogin {
  width: 100%; display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px;
  margin-top: 4px; padding-top: var(--s-4); border-top: 1px dashed var(--line-2);
}
.devlogin .field { flex: 1 1 220px; }

/* Warudo link (views/link.js): the code in mono capitals, the facts, the warning, one primary button. */
.link-confirm { gap: var(--s-4); }
.link-code {
  font: 600 clamp(2.2rem, 1.6rem + 2.4vw, 3.25rem)/1.1 var(--font-mono); letter-spacing: .1em; color: var(--silver);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.facts {
  display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 20px; width: 100%;
  padding: 16px 18px; background: var(--surface-2); border-radius: var(--r-sm); font-size: .9375rem; line-height: 1.6;
}
.facts dt { color: var(--fg-3); font-weight: 500; }
.facts dd { min-width: 0; color: var(--fg); overflow-wrap: anywhere; }
.link-warn {
  width: 100%; display: flex; align-items: flex-start; gap: 12px; padding: 14px 16px;
  border: 1px solid rgb(232 194 122 / .55); border-radius: var(--r-sm); background: rgb(232 194 122 / .06);
  color: var(--warn); font-weight: 600; line-height: 1.6;
}
.link-warn::before {
  content: "!"; flex: none; display: grid; place-items: center; width: 22px; height: 22px; margin-top: 1px; border-radius: 50%;
  background: var(--warn); color: var(--night-1); font: 700 .8125rem/1 var(--font-body);
}

/* ───────────────────────── Upload (index.html, local.html) ───────────────────────── */
/* The drop zone is basted (.basted in the markup): a dashed outline, not sewn yet. Dragging over it turns
   the outline into the blue thread. */
.drop {
  --c: rgb(242 244 247 / .36);
  display: flex; flex-direction: column; align-items: center; gap: var(--s-4); text-align: center;
  padding: clamp(40px, 7vw, 76px) var(--s-5); background-color: var(--night-2); border-radius: var(--r-xs);
  transition: background-color var(--t-fast) ease;
}
.drop.over { --c: var(--accent); background-color: var(--blue-soft); }
.drop-icon {
  display: grid; place-items: center; width: 64px; height: 64px; color: var(--silver);
  background: var(--surface) linear-gradient(180deg, var(--surface-sheen), transparent 60%);
  border: 1px solid var(--surface-edge); border-radius: var(--r-sm); box-shadow: var(--shadow-surface);
}
.drop-icon svg { width: 26px; height: 26px; }
.drop .small { font-size: var(--fs-ko-min); }
.box {
  display: flex; flex-direction: column; gap: var(--s-4); min-width: 0;
  padding: clamp(18px, 2.4vw, 24px); background: var(--night-2); border: 1px solid var(--line); border-radius: var(--r-md);
}
.box-title { font-size: 1.0625rem; }
.files { display: grid; gap: 10px; }
.file {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 260px) 168px; gap: 8px 16px; align-items: center;
  padding: 14px 16px; background: var(--night-3); border: 1px solid var(--line); border-radius: var(--r-sm); font-size: .9375rem;
}
.file:has(.file-info.err) { border-color: rgb(255 138 128 / .5); }
.file-name { min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
.file-info { font-size: var(--fs-ko-min); color: var(--fg-3); font-variant-numeric: tabular-nums; }
.file-info.err { color: var(--no); }
.file-info.ok { color: var(--ok); }
.file-act { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 8px; }
/* Progress: a graphite groove with a --ctl edge; the fill is the blue thread while it moves. */
.bar { position: relative; height: 8px; overflow: hidden; background: var(--surface-3); border: 1px solid var(--ctl); border-radius: var(--r-pill); }
.bar-fill { height: 100%; width: 0; background: var(--silver-2); transition: width .25s ease; }
.bar.live .bar-fill { background: var(--accent); }
.bar.done .bar-fill { background: var(--ok); }
.bar.err .bar-fill { background: var(--no); }

/* ───────────────────────── Prefab picker (pick.html, local.html) ─────────────────────────
 * Each prefab is a graphite tag. The thumbnail is a night swatch with a drafting grid and a soft light (five
 * placements, .tint-0…4); choosing one sews a silver seam inside its edge.
 */
.product { display: flex; flex-direction: column; gap: var(--s-4); }
.product h2 { font-size: 1.1875rem; }
.product h2 .small { margin-left: 10px; font-size: .875rem; font-weight: 500; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(176px, 1fr)); gap: var(--s-4); }
.prefab {
  position: relative; display: flex; flex-direction: column; gap: 12px; min-width: 0; padding: 12px;
  background: var(--surface) linear-gradient(180deg, var(--surface-sheen), transparent 45%);
  border: 1px solid var(--surface-edge); border-radius: var(--r-xs); box-shadow: var(--shadow-surface);
  transition: border-color var(--t-fast) ease;
}
.prefab:not(.off):hover { border-color: var(--silver-3); }
.prefab.warned:not(.on) { border-color: rgb(232 194 122 / .5); }
.prefab.on, .prefab.on:hover, label.prefab:has(> .pick-row input:checked) { border-color: var(--silver-2); }
.prefab.on::after, label.prefab:has(> .pick-row input:checked)::after {   /* chosen: a seam just inside the edge (local.html: the checked radio) */
  --c: var(--silver-3);
  content: ""; position: absolute; inset: 5px; pointer-events: none;
  background:
    repeating-linear-gradient(90deg,  var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) left top / 100% 1px no-repeat,
    repeating-linear-gradient(180deg, var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) right top / 1px 100% no-repeat,
    repeating-linear-gradient(270deg, var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) right bottom / 100% 1px no-repeat,
    repeating-linear-gradient(0deg,   var(--c) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap))) left bottom / 1px 100% no-repeat;
}
.prefab.off { background: var(--night-2); box-shadow: none; border-style: dashed; border-color: var(--line-2); }
.prefab > label, label.prefab { display: flex; flex-direction: column; gap: 12px; cursor: pointer; }
.prefab.off > label, label.prefab.off { cursor: not-allowed; }
.prefab.off :is(.thumb, .pick-name) { opacity: .6; }
.thumb {
  position: relative; overflow: hidden; height: 156px; padding: 12px;
  display: flex; flex-direction: column; align-items: center; justify-content: safe center; gap: 4px; text-align: center;
  color: var(--fg-2); font-size: var(--fs-ko-min); border: 1px solid var(--line); border-radius: 2px;
  background: radial-gradient(90% 70% at 18% 0%, rgb(var(--light) / .1), transparent 70%), var(--night-1);
}
.thumb::before {                    /* drafting grid, faded toward the edges */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: linear-gradient(rgb(242 244 247 / .05) 1px, transparent 1px), linear-gradient(90deg, rgb(242 244 247 / .05) 1px, transparent 1px);
  background-size: 24px 24px; background-position: center;
  -webkit-mask-image: radial-gradient(75% 75% at 50% 50%, #000 20%, transparent 90%);
          mask-image: radial-gradient(75% 75% at 50% 50%, #000 20%, transparent 90%);
}
.tint-1 { background: radial-gradient(90% 70% at 85% 0%, rgb(var(--light) / .1), transparent 70%), var(--night-1); }
.tint-2 { background: radial-gradient(80% 70% at 50% 110%, rgb(var(--light) / .09), transparent 70%), var(--night-1); }
.tint-3 { background: radial-gradient(70% 90% at 0% 60%, rgb(var(--light) / .09), transparent 70%), var(--night-1); }
.tint-4 { background: radial-gradient(70% 90% at 100% 40%, rgb(var(--light) / .09), transparent 70%), var(--night-1); }
.thumb > * { position: relative; max-width: 100%; }
.thumb > span:not(.thumb-name) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }   /* the folder: one line */
.thumb-name {                       /* long BOOTH names: two lines at most. Sans: names are anyone's text (kana too) */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  font: 600 1.375rem/1.25 var(--font-body); letter-spacing: -.015em; color: var(--silver);
}
/* The box, then the name over the whole remaining width; the mesh count goes under the name (beside it, a six-across
   card left long BOOTH names four or five lines tall). */
.pick-row { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 2px 10px; min-width: 0; }
.pick-row > input { margin-top: 1px; }
.pick-name { min-width: 0; font-weight: 700; font-size: .9688rem; line-height: 1.4; overflow-wrap: anywhere; }
.pick-meta { grid-column: 2; font-size: var(--fs-ko-min); color: var(--fg-3); white-space: nowrap; font-variant-numeric: tabular-nums; }
.tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tags:empty { display: none; }
.tag {                              /* web/views' small labels on a prefab (not the price tags of the site) */
  display: inline-flex; align-items: center; gap: 6px; padding: 1px 8px; border: 1px solid var(--line-2); border-radius: var(--r-xs);
  font: 600 var(--fs-ko-min)/1.55 var(--font-body); color: var(--fg-2);
}
.tag.ok { color: var(--ok); border-color: currentColor; }
.tag.warn { color: var(--warn); border-color: currentColor; }
.tag.busy { color: var(--info); border-color: currentColor; }
.tag.busy::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.off-text { font-size: var(--fs-ko-min); line-height: 1.6; color: var(--fg-2); }
.prefab details { font-size: var(--fs-ko-min); color: var(--fg-3); }
.prefab details > summary { min-height: 30px; color: var(--warn); border-color: rgb(232 194 122 / .65); }
.prefab details > summary:hover { border-color: var(--warn); }
label.prefab .small { font-size: var(--fs-ko-min); }

.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); }
.selectbox {
  display: inline-flex; align-items: center; gap: 4px; min-height: 46px; padding-left: 14px;
  border: 1.5px solid var(--ctl); border-radius: var(--r-sm); background: var(--field-bg);
}
.selectbox:hover { border-color: var(--ctl-hover); }
.selectbox:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--blue-soft); }
.selectbox label { font-size: var(--fs-ko-min); font-weight: 600; color: var(--fg-3); }
.selectbox select { flex: 1 1 auto; min-width: 0; min-height: 43px; border: 0; background-color: transparent; }   /* full-width box on phones: the chevron at its end */
.selectbox select:focus-visible { box-shadow: none; }
/* The summary: what this conversion costs, and the page's one blue button (.surface.stitched in the markup). */
.summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4) var(--s-5); padding: 24px 28px; }
.summary-text { flex: 1 1 320px; font-size: .9688rem; line-height: 1.75; color: var(--fg-2); }
.summary-text b { font-weight: 700; color: var(--fg); }
.notes { display: grid; gap: 4px; font-size: var(--fs-ko-min); color: var(--fg-3); }
.notes:not([hidden]) { margin-top: -4px; }

/* ───────────────────────── Conversion steps and the wardrobe (done.html) ───────────────────────── */
.card {
  display: flex; flex-direction: column; gap: var(--s-5); min-width: 0;
  padding: clamp(22px, 3vw, 34px); background: var(--night-2); border: 1px solid var(--line); border-radius: var(--r-md);
}
.card h1 { font-size: clamp(2rem, 1.55rem + 1.5vw, 2.75rem); }
.card .muted { color: var(--fg-2); }
.card .muted .btn { vertical-align: middle; }
/* Three steps on one seam: done = silver with a check, the one in progress = the blue thread, failed = --no. */
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); gap: var(--s-3); }
.step {
  position: relative; padding: 20px 16px 16px; font-size: .9375rem;
  background: var(--night-3); border: 1px solid var(--line); border-radius: var(--r-sm);
}
.step::before {
  content: ""; position: absolute; left: 14px; right: 14px; top: -1px; border-top: 2px solid var(--line-2);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap)));
          mask: repeating-linear-gradient(90deg, #000 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap)));
}
.step-title { display: flex; align-items: center; gap: 10px; font-weight: 700; color: var(--fg); }
.step-n {
  display: grid; place-items: center; flex: none; width: 30px; height: 30px; border: 1.5px solid var(--ctl); border-radius: 50%;
  font: var(--fw-num) 1.0625rem/1 var(--font-display); color: var(--fg-2); font-variant-numeric: tabular-nums;
}
.step-text { margin-top: 8px; font-size: .875rem; line-height: 1.6; color: var(--fg-3); }
.step.done::before { border-top-color: var(--silver-2); -webkit-mask: none; mask: none; }
.step.done .step-n {               /* the number stays in the text; the circle shows a check */
  color: transparent; border-color: var(--silver);
  background: var(--silver) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.4 8.6l3 3 6.2-6.7' fill='none' stroke='%230A0B0D' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 15px 15px no-repeat;
}
.step.done .step-text { color: var(--ok); }
.step.active { border-color: rgb(61 139 255 / .4); }
.step.active::before { border-top-color: var(--accent); }
.step.active .step-n { border-color: var(--accent); color: var(--accent); }
.step.active .step-text { color: var(--fg); }
.step.fail { border-color: rgb(255 138 128 / .5); }
.step.fail::before { border-top-color: var(--no); }
.step.fail .step-n { border-color: var(--no); color: var(--no); }
.step.fail .step-text { color: var(--no); }

.section-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px var(--s-4); }
.table-box { overflow: hidden; background: var(--night-2); border: 1px solid var(--line); border-radius: var(--r-md); }
.table-box > .empty { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }   /* the sentence and its button on one centre line */
.lib { width: 100%; border-collapse: collapse; table-layout: fixed; }
.lib th { text-align: left; padding: 12px 20px; font: 600 var(--fs-ko-min)/1.4 var(--font-body); color: var(--fg-3); border-bottom: 1px solid var(--line-2); }
.lib td { padding: 14px 20px; font-size: .9688rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
.lib tbody tr { transition: background-color var(--t-fast) ease; }
.lib tbody tr:hover { background: rgb(24 26 31 / .75); }
.lib tr:last-child td { border-bottom: 0; }
/* fixed columns for 종류 / 받은 날 / the action; the name takes the rest */
.lib td.c-name { font-weight: 600; color: var(--fg); }
.lib th:nth-child(2) { width: 128px; }
.lib th.date { width: 148px; }
.lib .c-act { width: 300px; }
.lib td.sub { color: var(--fg-2); overflow-wrap: normal; font-weight: 400; }
.lib td.date, .lib th.date { white-space: nowrap; font-variant-numeric: tabular-nums; }
.lib .prod { display: block; margin-top: 2px; font-size: var(--fs-ko-min); font-weight: 400; color: var(--fg-3); }
.lib .reason { font-size: var(--fs-ko-min); line-height: 1.6; color: var(--fg-2); }
.lib .dl-msg { display: block; margin-top: 6px; font-size: var(--fs-ko-min); color: var(--fg-3); font-variant-numeric: tabular-nums; }
.lib .dl-msg.err { color: var(--no); }
.lib tr.fresh { background: var(--night-4); }
.lib tr.fresh td:first-child { box-shadow: inset 2px 0 0 var(--accent); }   /* just converted: the thread */
.empty { padding: 22px 20px; color: var(--fg-2); }
/* The subscription nudge (.surface.stitched in the markup). */
.plan { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4) var(--s-5); padding: clamp(24px, 3vw, 34px); }
.plan-text { flex: 1 1 320px; display: grid; gap: 6px; }
.plan-sub { font-size: .9375rem; line-height: 1.65; color: var(--fg-2); }

/* ───────────────────────── Dialog (views/dialog.js) ───────────────────────── */
.dlg {
  width: min(500px, calc(100vw - 32px)); max-height: calc(100vh - 32px); padding: 0; color: var(--fg);
  background: var(--night-3); border: 1px solid var(--line-2); border-radius: var(--r-md); box-shadow: var(--shadow-lift);
}
.dlg::backdrop { background: rgb(5 5 6 / .74); }
.dlg-in { display: flex; flex-direction: column; gap: var(--s-4); padding: clamp(20px, 3vw, 28px); }
.dlg-body { display: flex; flex-direction: column; gap: 10px; }
.dlg-body :is(.state, .panel, .login-panel) { padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; }
.dlg-body :is(.state, .panel)::before, .dlg-body .stitched::after { display: none; }
.dlg-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; }
.dlg-fallback { position: fixed; inset: 0; z-index: var(--z-popover); margin: auto; height: fit-content; }
.consent a { white-space: nowrap; }

/* ───────────────────────── Footer (controllers/motion.js renders footer.foot) ───────────────────────── */
.foot { position: relative; margin-top: var(--s-8); padding: var(--s-5) 0 var(--s-6); background: rgb(5 5 6 / .88); }
.foot::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: repeating-linear-gradient(90deg, var(--line-2) 0 var(--stitch-len), transparent var(--stitch-len) calc(var(--stitch-len) + var(--stitch-gap)));
}
.foot-inner {
  width: min(100% - 2 * var(--gutter), var(--col)); margin-inline: auto;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px var(--s-5);
  font-size: var(--fs-ko-min); color: var(--fg-3);
}
.foot-links { display: flex; flex-wrap: wrap; gap: 0 18px; }
.foot-links a { padding: 8px 0; color: var(--fg-2); font-size: .875rem; text-decoration: none; }
.foot-links a:hover { color: var(--fg); text-decoration: underline; text-decoration-color: var(--accent); }
/* The 「배경 움직임」 switch pauses a moving sky; this sky is still, so there is nothing for it to do. */
.foot .switch { display: none; }

/* ───────────────────────── Draft policy pages (web/pricing|terms|refund|privacy.html) ───────────────────────── */
.legal { width: min(100% - 2 * var(--gutter), 46rem); gap: var(--s-5); color: var(--fg-2); }
.draft-banner {
  padding: 10px 14px; border: 1px dashed rgb(232 194 122 / .6); border-radius: var(--r-sm);
  color: var(--warn); font-size: .9375rem; font-weight: 600; line-height: 1.6;
}
.legal section { display: grid; gap: 10px; }
.legal h2 { padding-top: 18px; border-top: 1px solid var(--line); font-size: clamp(1.45rem, 1.25rem + .7vw, 1.8rem); color: var(--fg); }
.legal :is(p, li, td, th) { font-size: .9688rem; line-height: 1.85; }
.legal :is(ul, ol) { padding-left: 1.4em; }
.legal ul { list-style: disc; }
.legal ol { list-style: decimal; }
.legal li::marker { color: var(--fg-3); }
.legal a:not(.btn) { color: var(--fg); text-decoration-color: var(--line-3); }
.legal mark { padding: 0 4px; border-radius: 2px; background: rgb(232 194 122 / .12); color: var(--warn); }
.legal table { width: 100%; border-collapse: collapse; }
.legal :is(th, td) { padding: 10px 14px 10px 0; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
.legal thead th { font-size: var(--fs-ko-min); color: var(--fg-3); }
.legal tbody th { color: var(--fg); font-weight: 700; white-space: nowrap; }
.legal .foot-links { justify-content: flex-start; }

/* ───────────────────────── The Steam app's window (/auth/steam-app → steam-app.html) ───────────────────────── */
.steam-app { gap: var(--s-4); }
.steam-app h1 { font-size: clamp(1.9rem, 1.5rem + 1.5vw, 2.5rem); }
.steam-app.state { padding: clamp(24px, 3.4vw, 36px); }
.state.steam-app-warn {            /* a warning line inside the panel, not a card */
  display: block; width: 100%; padding: 12px 14px 12px 16px; background: rgb(232 194 122 / .06);
  border: 0; border-left: 2px solid var(--warn); border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--warn); font-size: .9375rem; line-height: 1.65;
}
.state.steam-app-warn::before { display: none; }

/* ───────────────────────── Responsive ───────────────────────── */
/* GD Logo (Xolonium) is a wide face. Where the header is tight (one row with KO / EN / JA at 961-1199px, then with the
   full language names up to 1279px, where the English header with every item needs it; row 1 below 480px) the
   wordmark steps down, so every part keeps the row it had with the old serif wordmark (measured with a desktop
   scrollbar's gutter: the avatar stays on row 1 at 1024px and at 1200-1279px, the avatar or the Steam login at 360px). */
@media (max-width: 1279px) {
  .app-bar .brand-word { font-size: 1.25rem; }
}
@media (min-width: 961px) and (max-width: 1099px) {
  .app-bar .brand-word { font-size: 1.1875rem; }   /* the English header with every item at 990 and 1050px */
}
@media (min-width: 481px) and (max-width: 960px) {
  .app-bar .brand-word { font-size: 1.4375rem; }   /* two rows: row 1 has room for the full-size wordmark */
}
@media (max-width: 960px) {
  /* header: two rows (see the header comment above) */
  .app-bar .top-inner { row-gap: 0; padding-block: 8px 6px; }
  .app-bar .top-inner::after { content: ""; order: 1; flex-basis: 100%; height: 0; }
  .app-bar .brand { margin-right: auto; }
  .app-bar .spacer { display: none; }
  .app-bar :is(.top-link, .top-nav, .lang-switch, .quota, .top-answer) { order: 2; }
  .app-bar .top-nav { flex: 0 1 auto; margin: 0 0 0 -12px; overflow: visible; }
  .app-bar .top-nav a { padding-block: 10px; }
  .lib th, .lib td { padding-left: 14px; padding-right: 14px; }
  .lib th:nth-child(2) { width: 112px; }
  .lib th.date { width: 128px; }
  .lib .c-act { width: 196px; }
}
@media (max-width: 760px) {
  /* base.css stacks .top-nav on a row of its own and hides it in .app-top: this header is different */
  .app-bar .top-nav { order: 2; flex: 0 1 auto; margin: 0 0 0 -12px; }
  .app-bar .top-inner { flex-wrap: wrap; }
  /* 내 의상함: one block per row */
  .lib, .lib tbody, .lib tr, .lib td { display: block; width: auto; }
  .lib thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .lib tr { padding: 14px 16px; border-bottom: 1px solid var(--line); }
  .lib tr:last-child { border-bottom: 0; }
  .lib td, .lib td.c-name, .lib td.c-act { padding: 2px 0; border: 0; width: auto; font-size: .9375rem; }
  .lib td.c-act { margin-top: 8px; }
  .lib td.sub { display: inline-block; margin-right: 12px; font-size: .875rem; }
  .lib tr.fresh td:first-child { box-shadow: none; }
  .lib tr.fresh { box-shadow: inset 2px 0 0 var(--accent); }
}
@media (max-width: 640px) {
  .btn { white-space: normal; text-align: center; }
  .file { grid-template-columns: minmax(0, 1fr) 96px; padding: 12px; }
  .file-name { grid-column: 1 / -1; }
  .cards { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
  .prefab { padding: 10px; }
  .thumb { height: 112px; }
  .thumb-name { font-size: 1.1875rem; }
  .toolbar > .btn, .selectbox { flex: 1 1 auto; }
  .summary { padding: 20px; }
  .summary .btn--lg, .end.btn--lg, .link-confirm .btn--lg, .plan .btn { width: 100%; }
  .end { align-self: stretch; }
  .facts { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .facts dt:not(:first-child) { margin-top: 8px; }
  .link-code { font-size: 2.125rem; }
  .login-code { font-size: 2rem; }
  .legal table { display: block; overflow-x: auto; }
}
@media (max-width: 480px) {
  /* row 1 = the mark and the avatar (or the Steam login): a signed-in header button (구독하기, or the wider 결제 수단
     바꾸기) joins row 2, so the avatar never drops onto a line of its own */
  .app-bar .top-inner > .btn--sm:not(.btn--silver) { order: 2; }
  .app-bar .lang-switch:not(.lang-switch--guest) { order: 0; }
  .app-bar .lang-switch :is(a, button) { padding-inline: 5px; }
  .app-bar .lang-switch [aria-current]::after { left: 5px; right: 5px; }
}
@media (max-width: 407px) {      /* 400px plus a desktop scrollbar's gutter, which the window width includes */
  .app-bar .top-inner { column-gap: var(--s-2); }   /* base.css's 400px gap, which the header's own gap above outranked */
  .app-bar .top-inner > .btn--sm { padding-inline: .8em; }
  .app-bar .brand-word { font-size: 1.0625rem; }
  .app-bar .brand-mark { width: 28px; height: 28px; }   /* the mark steps down with the word, as on the site */
}
@media (max-width: 377px) {
  .app-bar .brand-word { font-size: 1rem; }         /* the Steam login beside the mark, with a desktop scrollbar's gutter too */
  .app-bar .brand-mark { width: 26px; height: 26px; }
}
@media (forced-colors: active) {
  .sky { display: none; }
  .bar, .tag, .step-n, .account > summary { border: 1px solid ButtonText; }
  .brand-mark:not(svg) { forced-color-adjust: none; }
}
