
:root {
  color-scheme: light;
  --canvas: #f7f8fa;
  --surface: #ffffff;
  --surface-subtle: #eef1f4;
  --surface-hover: #f4f6f8;
  --text: #191f28;
  --muted: #6b7684;
  --faint: #8b95a1;
  --line: #e6e8ec;
  --line-strong: #c4c9d0;
  --frame-line: #e6e8ec;
  --frame-head: #ffffff;
  --frame-radius: 12px;
  --accent: #e5453a;
  --accent-ink: #d63a30;
  --accent-soft: #fdece9;
  --positive: #10a877;
  /* 브랜드 `--accent`도 빨강이지만 그것은 금액과 LIVE 배지의 색이다. 내림을 그 색으로
     쓰면 팔레트를 손볼 때 떨어지는 숫자의 뜻이 조용히 따라 바뀐다. */
  --negative: #d1382c;
  --warning: #e8820c;
  --radius-sm: 7px;
  --radius-md: 10px;
  --card-shadow: 0 1px 2px rgb(25 31 40 / 4%), 0 10px 24px -14px rgb(25 31 40 / 16%);
  --dialog-backdrop: rgb(25 31 40 / 42%);
  --dialog-shadow: 0 24px 64px -20px rgb(25 31 40 / 38%);
  --page-section-gap: 14px;
  font-family: "Pretendard", "Pretendard Variable", -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", system-ui, "Segoe UI", sans-serif;
  font-variant-numeric: tabular-nums;
}
/* 다크 모드: OS 설정을 따르되 라이트 명시 선택은 존중하고, 헤더 토글이 data-theme으로 덮어쓴다.
   토큰만 바꾸므로 컴포넌트 규칙은 그대로 따라온다. 값을 두 곳에 적는 건 미디어쿼리와
   [data-theme] 를 한 규칙으로 합칠 수 없어서다. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --canvas: #14161b; --surface: #1c1f27; --surface-subtle: #262b35; --surface-hover: #222732;
    --text: #eef1f5; --muted: #98a2b0; --faint: #6d7683; --line: #2a2f3a; --line-strong: #3b414e;
    --frame-line: #2a2f3a; --frame-head: #1c1f27;
    --accent: #ff5a4d; --accent-ink: #ff7065; --accent-soft: rgb(255 90 77 / 16%);
    --positive: #2dd4a0; --negative: #ff8079; --warning: #f5a524;
    --card-shadow: 0 1px 2px rgb(0 0 0 / 50%), 0 12px 30px -16px rgb(0 0 0 / 85%);
    --dialog-backdrop: rgb(0 0 0 / 66%); --dialog-shadow: 0 26px 72px -18px rgb(0 0 0 / 86%);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --canvas: #14161b; --surface: #1c1f27; --surface-subtle: #262b35; --surface-hover: #222732;
  --text: #eef1f5; --muted: #98a2b0; --faint: #6d7683; --line: #2a2f3a; --line-strong: #3b414e;
  --frame-line: #2a2f3a; --frame-head: #1c1f27;
  --accent: #ff5a4d; --accent-ink: #ff7065; --accent-soft: rgb(255 90 77 / 16%);
  --positive: #2dd4a0; --negative: #ff8079; --warning: #f5a524;
  --card-shadow: 0 1px 2px rgb(0 0 0 / 50%), 0 12px 30px -16px rgb(0 0 0 / 85%);
  --dialog-backdrop: rgb(0 0 0 / 66%); --dialog-shadow: 0 26px 72px -18px rgb(0 0 0 / 86%);
}
* { box-sizing: border-box; }
html { scrollbar-gutter: stable; background: var(--canvas); }
body { margin: 0; color: var(--text); background: var(--canvas); font-size: 14px; line-height: 1.5; letter-spacing: -0.012em; }
a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent); }
button, input { color: inherit; font: inherit; }
/* Keep keyboard focus visible without drawing a ring outside the control. The old
   global outline made adjacent header items and compact table actions collide. */
:where(a, button, summary, [role="button"], [tabindex]):focus-visible { outline: 0; box-shadow: inset 0 -2px 0 var(--accent); }
.shell { width: min(1280px, calc(100% - 40px)); margin: auto; padding: 0 0 72px; }
/* With side ads the content column is what is left after two 160px rails and two
   16px gaps -- 928px inside a 1280px shell, which reads as a narrow site. The
   shell grows by exactly the space the rails take, so the content keeps the width
   it has on every other page instead of paying for the ads. */
.shell:has(.advertising-layout.has-side-ads) { width: min(1632px, calc(100% - 40px)); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.site-header { border-bottom: 1px solid var(--line); }
.main-header { height: 64px; display: flex; align-items: center; gap: 24px; }
.header-primary, .header-utility, .platform-navigation-group, .platform-navigation, .platform-subnav { display: flex; align-items: center; }
.header-primary { gap: 20px; min-width: 0; }
.platform-navigation-group { flex: 0 0 auto; gap: 2px; }
.wordmark { display: inline-flex; align-items: center; padding-left: 4px; color: var(--text); font-size: 20px; font-weight: 760; letter-spacing: -0.045em; text-decoration: none; }
/* 84px against a 64px header row: the mark is 25x13, so this renders about 44px tall. */
.wordmark-logo { display: block; width: 84px; height: auto; }
/* 로고는 <img> 라 CSS로 개별 색을 못 바꾼다. 다크에서는 명도만 반전하고 hue-rotate 로 색상을
   되돌려, 검은 글자는 밝아지고 점은 대체로 붉은색을 유지한다. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .wordmark-logo { filter: invert(1) hue-rotate(180deg); } }
:root[data-theme="dark"] .wordmark-logo { filter: invert(1) hue-rotate(180deg); }
.admin-wordmark span { margin-left: 0.25em; color: var(--accent); }
/* The admin menu is nineteen entries and still growing, which is more than one row
   of a 64px header holds. It wraps instead of scrolling sideways: an operator needs
   to see the whole menu to find a page, and a row that scrolls hides half of it
   behind a gesture. The header gives up its fixed height for the same reason -- with
   a wrapping nav inside, a fixed 64px would just clip the second line. */
.admin-header .main-header { height: auto; min-height: 64px; align-items: flex-start; padding: 10px 0; }
.admin-header .header-primary { flex-wrap: wrap; align-items: center; row-gap: 2px; }
.admin-header .platform-navigation { flex-wrap: wrap; row-gap: 2px; }
/* The utility links keep their own width; squeezed by a two-row nav they broke
   "내 정보" across two lines. */
.admin-header .header-utility { flex: 0 0 auto; align-self: center; }
.admin-header .header-utility a, .admin-header .header-utility button { white-space: nowrap; }
.platform-navigation { gap: 2px; }
.platform-navigation a, .header-search-link, .auth-link { min-height: 34px; border-bottom: 2px solid transparent; color: var(--muted); font-size: 12px; font-weight: 600; text-decoration: none; }
.platform-navigation a { padding: 7px 9px; }
.header-search-link, .auth-link { padding: 12px 9px 2px 9px; }
.platform-navigation a { padding: 7px 11px; border-radius: 8px; border-bottom: 0; }
.platform-navigation a:hover, .header-search-link:hover, .auth-link:hover { color: var(--text); }
.platform-navigation a:hover { background: var(--surface-hover); }
.platform-navigation a.is-active { background: var(--accent-soft); color: var(--accent-ink); }
.header-utility { margin-left: auto; gap: 8px; }
/* 유틸 링크(검색·내 정보·알림 토글)도 nav 처럼 pill 로. 고정 규칙(테스트가 문자열로 검사)은
   그대로 두고 더 높은 명시도로만 덮어써 pill 을 입힌다. */
.header-utility .header-search-link, .header-utility .auth-link { padding: 7px 11px; border-radius: 8px; border-bottom: 0; }
.header-utility .header-search-link:hover, .header-utility .auth-link:hover { background: var(--surface-hover); }
.header-search-trigger { appearance: none; border: 0; background: transparent; cursor: pointer; }
.header-search-dialog { position: fixed; inset: 0; width: min(600px, calc(100% - 32px)); max-width: none; max-height: calc(100dvh - 112px); margin: 88px auto auto; padding: 20px; overflow: visible; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); color: var(--text); box-shadow: var(--dialog-shadow); }
.header-search-dialog::backdrop { background: var(--dialog-backdrop); backdrop-filter: blur(3px); }
.header-search-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.header-search-dialog-head h2 { margin: 0; font-size: 19px; font-weight: 800; letter-spacing: -0.03em; }
.header-search-dialog-close { width: 34px; height: 34px; display: grid; place-items: center; flex: 0 0 auto; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--muted); cursor: pointer; }
.header-search-dialog-close:hover { background: var(--surface-hover); color: var(--text); }
.header-search-dialog-close svg { width: 18px; height: 18px; display: block; }
.header-search-dialog-form { min-height: 52px; display: grid; grid-template-columns: minmax(0, 1fr) auto; margin: 18px 0 14px; overflow: hidden; border: 1px solid var(--line-strong); border-radius: var(--radius-md); background: var(--surface); }
.header-search-dialog-form:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.header-search-dialog-field { min-width: 0; display: flex; align-items: center; gap: 10px; padding: 0 14px; color: var(--faint); }
.header-search-dialog-field svg { width: 18px; height: 18px; flex: 0 0 auto; }
.header-search-dialog-field input { width: 100%; min-width: 0; min-height: 50px; padding: 0; border: 0; outline: 0; background: transparent; }
.header-search-dialog-field input::placeholder { color: var(--faint); }
.header-search-dialog-form > button { min-width: 76px; padding: 0 20px; border: 0; background: var(--accent); color: #fff; font-size: 13.5px; font-weight: 700; cursor: pointer; }
.header-search-dialog-form > button:hover { filter: brightness(0.94); }
.header-search-dialog-foot { display: flex; justify-content: flex-end; color: var(--muted); font-size: 12px; }
.header-search-dialog-foot kbd { display: inline-flex; align-items: center; min-height: 22px; padding: 1px 6px; margin-right: 5px; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--surface-subtle); color: var(--text); font: inherit; font-size: 11px; box-shadow: inset 0 -1px 0 var(--line); }
/* 로그아웃은 폼 안의 버튼이라 이웃 링크가 받는 헤더 알약 규칙에 걸리지 않았다. 혼자 옛
   탭 여백(12px 9px 2px)을 쓰고 hover 배경도 없어 한 칸 어긋나 보였다. */
.header-utility .auth-sign-out { min-height: 34px; padding: 0; border-bottom: 0; }
.header-utility .auth-sign-out button { padding: 7px 11px; border-radius: 8px; line-height: 20px; }
.header-utility .auth-sign-out button:hover { background: var(--surface-hover); color: var(--text); }
/* 로고 점(dot)이 위쪽에 있어 글자가 아래로 쏠려 보인다. 메뉴(nav·유틸)를 로고 글자 두
   벡터의 세로 중앙에 맞춰 내린다 -- 측정상 44px 로고가 64px 행에서 글자 중앙이 행 중앙보다
   7px 아래다. 관리자 헤더는 높이 auto의 2행 랩이라 이 보정에서 제외한다. */
.platform-navigation, .header-utility { transform: translateY(7px); }
.admin-header .platform-navigation, .admin-header .header-utility { transform: none; }
.header-theme-toggle { display: inline-grid; place-items: center; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--muted); cursor: pointer; }
.header-theme-toggle:hover { background: var(--surface-hover); color: var(--text); }
.header-theme-toggle svg { width: 18px; height: 18px; display: block; }
/* 아이콘: 라이트=해, 다크=달 (prefers-color-scheme 자동 + data-theme 토글 둘 다 대응) */
.header-theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .header-theme-toggle .icon-sun { display: none; }
  :root:not([data-theme="light"]) .header-theme-toggle .icon-moon { display: block; }
}
:root[data-theme="dark"] .header-theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .header-theme-toggle .icon-moon { display: block; }
:root[data-theme="light"] .header-theme-toggle .icon-sun { display: block; }
:root[data-theme="light"] .header-theme-toggle .icon-moon { display: none; }
.site-presence { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; padding: 10px 9px 4px; color: var(--muted); font-size: 11px; line-height: 18px; }
.site-presence strong { min-width: 36px; height: 18px; display: inline-flex; align-items: center; justify-content: center; padding: 4px 8px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface-hover); color: var(--text); font-size: 8px; font-weight: 680; }
.auth-sign-out { min-height: 34px; display: flex; align-items: center; padding: 12px 9px 2px 9px; border-bottom: 2px solid transparent; margin: 0; }
.auth-sign-out button { display: block; padding: 0; border: 0; background: transparent; color: var(--muted); font-size: 12px; font-weight: 600; line-height: 18px; cursor: pointer; }
.auth-sign-out button:hover { color: var(--text); }
.platform-subheader { height: 44px; display: flex; align-items: center; border-top: 1px solid var(--line); }
.platform-subnav { gap: 4px; overflow-x: auto; scrollbar-width: none; }
.platform-subnav a { flex: 0 0 auto; padding: 7px 12px; border-radius: 8px; color: var(--muted); font-size: 12.5px; font-weight: 600; text-decoration: none; }
.platform-subnav a:hover { background: var(--surface-hover); color: var(--text); }
.platform-subnav a.is-active { background: var(--accent-soft); color: var(--accent-ink); }
.site-footer { display: grid; gap: 7px; padding: 28px 0 6px; margin-top: 64px; border-top: 1px solid var(--line); color: var(--muted); }
.footer-brand { min-height: 34px; display: flex; align-items: center; gap: 9px; }
.footer-brand strong { color: var(--text); font-size: 16px; letter-spacing: -0.035em; }
.footer-brand small, .site-footer p { font-size: 10px; }
.site-footer p { margin: 0; line-height: 17px; }
/* Its own row between the brand and the notices, on the same left edge as the brand
   and the notices. It used to be `justify-content: space-between`, left over from when
   `margin-left: auto` pushed a single link to the right of the brand row: as a row of
   its own that spread three buttons across the whole width with the gaps between them
   growing on wide screens. Wrapping, because an operator can rename the 문의 button and
   a narrow screen has to put the overflow on the next line rather than shrink them. */
.footer-links { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
/* A button next to the header's anchors. Only the parts a button brings of its own --
   its chrome and its font family -- are reset; the size, colour, padding and the
   transparent bottom border that keeps every header item on one baseline all come from
   `.auth-link`, so the toggle cannot drift away from its neighbours. */
.header-alert-toggle .icon-bell-off { display: none; }
.header-alert-toggle[aria-pressed="false"] .icon-bell-on { display: none; }
.header-alert-toggle[aria-pressed="false"] .icon-bell-off { display: block; }
.footer-inquiry-link, .footer-faq-link, .footer-legal-link { min-height: 30px; display: inline-flex; align-items: center; padding: 5px 9px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); color: var(--text); font-size: 11px; font-weight: 600; text-decoration: none; }
.footer-inquiry-link:hover, .footer-faq-link:hover, .footer-legal-link:hover { border-color: var(--accent); }
.footer-legal-link-privacy { font-weight: 700; }
.admin-footer { margin-top: 48px; }
.site-header + .metrics, .site-header + .notice { margin-top: 16px; }
.root-content { display: grid; gap: var(--page-section-gap); }
.root-search { padding-block: 6px; }
.advertising-content-root > .advertising-page-content { padding-top: 20px; }
.advertising-content-root > .promoted-live:not([hidden]) + .advertising-page-content { padding-top: 0; }
/* A control, not a card: the firmer control line, the control radius, and the same
   soft focus ring the other inputs carry. `overflow: hidden` keeps the accent submit
   inside the rounded corner instead of squaring it off. */
.root-search-form { width: 50%; min-height: 42px; display: grid; grid-template-columns: minmax(0, 1fr) auto; margin-inline: auto; overflow: hidden; border: 1px solid var(--line-strong); border-radius: var(--radius-md); background: var(--surface); }
.root-search-form input { min-width: 0; padding: 9px 13px; border: 0; border-radius: 0; outline: 0; background: var(--surface); font-size: 13px; }
.root-search-form input::placeholder { color: var(--faint); }
.root-search-form:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.root-search-form button { min-width: 62px; padding: 0 16px; border: 0; border-radius: 0; background: var(--accent); color: #fff; font-size: 12.5px; font-weight: 700; cursor: pointer; }
.root-search-form button:hover { filter: brightness(0.94); }
/* The portal gives search more presence than its compact list-toolbar reuse. Six
   inset pixels combine with the 14px section gap into an even 20px above and below. */
.root-search .root-search-form { width: 70%; min-height: 50px; }
.root-search .root-search-form input { padding: 12px 16px; font-size: 14px; }
.root-search .root-search-form button { min-width: 76px; padding: 0 20px; font-size: 13.5px; }
/* In a list toolbar the search sits beside the title rather than centred under a
   hero, so it takes its own width instead of half the page. */
.list-head-bar .root-search-form { width: min(320px, 100%); margin-inline: 0; }
.root-platform-summaries { display: grid; gap: var(--page-section-gap); padding-top: 0; }
.root-platform-summary { min-height: 120px; display: grid; grid-template-columns: 116px minmax(0, 1fr); grid-template-rows: minmax(88px, auto) auto; align-items: stretch; padding: 0; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); box-shadow: var(--card-shadow); overflow: hidden; }
.root-platform-summary h2 { grid-row: 1 / span 2; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 5px; margin: 0; padding: 0 14px; border-right: 1px solid var(--frame-line); background: var(--frame-head); font-size: 15px; font-weight: 800; letter-spacing: -0.02em; }
.root-platform-live { display: inline-flex; align-items: center; gap: 4px; color: var(--accent-ink); font-size: 9px; font-weight: 700; letter-spacing: 0; white-space: nowrap; }
.root-platform-live::before { content: ""; flex: none; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }
.root-platform-summary h2 a { text-decoration: none; }
/* 180px is what the widest of these needs with room to grow: "이번 달 누적 후원" at
   ten digits plus its unit measures 175px, and today's nine-digit 치즈 figure is one
   good month away from that.
   Wrapped flex rather than an auto-fit grid, because of what happens on the last row.
   Four metrics in a three-column grid leave a quarter of the row with no cell in it,
   so the row's separator stopped halfway across and the card looked cut off. Flex
   items on a short row grow to fill it, so the last metric takes the leftover width
   and its separator runs the whole way. Full rows are unchanged: equal basis, equal
   growth, equal widths. */
.root-platform-summary dl { grid-column: 2; display: flex; flex-wrap: wrap; margin: -1px 0 0 -1px; }
/* Each cell draws its own top and left separator, rather than a `:first-child` border
   rule -- that only knows where a row begins when the column count is fixed, and with
   auto-fit it is wrong at every count but one, which is why the first metric on a
   wrapped row had no line beside it.
   Painting the grid's gaps instead would colour the leftover area too: four metrics in
   a three-column row leave one cell's worth of grid with no cell in it, and that came
   out as a grey block. A shadow belongs to a cell, so empty space stays empty.
   The -1px offset pushes the outermost lines under the card's own edge, where
   `overflow: hidden` clips them. */
.root-platform-summary dl > div { flex: 1 1 180px; min-width: 0; display: grid; align-content: center; gap: 3px; padding: 10px 15px; box-shadow: inset 1px 0 0 var(--line), inset 0 1px 0 var(--line); }
.root-platform-summary dt { overflow: hidden; color: var(--muted); font-size: 10px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.root-platform-summary dd { margin: 0; white-space: nowrap; }
.root-platform-summary dd strong { color: var(--text); font-size: 22px; font-weight: 720; letter-spacing: -0.04em; }
.root-platform-summary dd small { margin-left: 4px; color: var(--muted); font-size: 9px; }
/* The change reading drops to its own line under the figure, the way the redesign
   stacks it, instead of trailing the value on one line. */
.root-platform-summary dd .change-badge { display: block; margin: 3px 0 0; }
.root-platform-summary-note { grid-column: 2; margin: 0; padding: 7px 15px 8px; border-top: 1px solid var(--line); color: var(--muted); font-size: 10px; line-height: 16px; }
/* 알림은 화면 한 귀퉁이에서 몇 초 사는 것이라, 읽을 것 하나에 필요한 만큼만 차지한다.
   360px x 108px는 후원 한 건이 담고 있는 것(이름 하나, 숫자 하나)보다 훨씬 컸다. */
.donation-alert-stack { position: fixed; z-index: 100; right: 16px; bottom: 16px; width: min(248px, calc(100vw - 24px)); display: grid; gap: 6px; pointer-events: none; }
/* 후원자 이름을 숨기는 설정에서는 카드에 스트리머 이름과 금액만 남으므로 더 좁아진다. */
.donation-alert-stack[data-supporters="hidden"] { width: min(206px, calc(100vw - 24px)); }
.donation-alert-card { position: relative; display: grid; grid-template-columns: 30px minmax(0, 1fr); gap: 8px; padding: 8px 26px 8px 8px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); box-shadow: 0 8px 22px -10px rgb(23 25 28 / 28%); pointer-events: auto; animation: donation-alert-enter 160ms ease-out; }
.donation-alert-card.is-leaving { opacity: 0; transform: translateX(12px); transition: opacity 120ms ease, transform 120ms ease; }
.donation-alert-avatar { width: 30px; height: 30px; display: grid; place-items: center; align-self: center; overflow: hidden; border: 1px solid var(--line); border-radius: 50%; background: var(--surface-subtle); }
.donation-alert-avatar img, .donation-alert-avatar span { width: 100%; height: 100%; display: block; object-fit: cover; object-position: 50% 50%; }
.donation-alert-body { min-width: 0; display: grid; align-content: center; gap: 3px; }
.donation-alert-platform { width: fit-content; padding: 2px 7px; border-radius: 999px; background: var(--accent-soft); color: var(--accent-ink); font-size: 10px; font-weight: 700; letter-spacing: 0.02em; line-height: 13px; }
.donation-alert-parties { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) 10px minmax(0, 1fr); align-items: center; gap: 4px; }
/* 후원자 칸이 없으면 남은 폭을 스트리머 이름이 다 쓴다. */
.donation-alert-parties.is-streamer-only { grid-template-columns: minmax(0, 1fr); }
.donation-alert-party { min-width: 0; display: block; }
.donation-alert-party a, .donation-alert-party span { min-width: 0; display: block; overflow: hidden; font-size: 11px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.donation-alert-arrow { color: var(--muted); font-size: 9px; }
.donation-alert-amount { margin: 0; font-size: 10px; }
.donation-alert-amount strong { margin-right: 3px; color: var(--accent); font-size: 14px; letter-spacing: -0.03em; }
.donation-alert-close { position: absolute; top: 4px; right: 4px; width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--muted); font-size: 14px; line-height: 1; cursor: pointer; }
.donation-alert-close:hover { background: var(--surface-hover); color: var(--text); }
@keyframes donation-alert-enter { from { opacity: 0; transform: translateX(16px); } }
@media (prefers-reduced-motion: reduce) {
  .donation-alert-card { animation: none; }
  .donation-alert-card.is-leaving { transition: none; }
}
.advertising-layout { display: block; }
.advertising-layout.has-side-ads { display: grid; grid-template-columns: 160px minmax(0, 1fr) 160px; gap: 16px; align-items: start; }
.advertising-content { min-width: 0; }
.advertising-page-content { min-width: 0; display: grid; gap: var(--page-section-gap); }
.advertising-page-content > :where(.notice, .panel, .detail-metrics, .entity-head, .filters, .community-directory, .community-board, .community-board-owner) { margin-block: 0; }
.advertising-side { display: none; min-width: 0; padding-top: 16px; position: sticky; top: 0; }
.has-side-ads .advertising-side { display: block; }
.advertising-banner-vertical, .advertising-banner-horizontal { position: relative; display: block; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-subtle); text-decoration: none; }
.advertising-banner-vertical { width: 100%; height: auto; }
.advertising-banner-horizontal { width: 100%; height: auto; }
.advertising-banner-vertical img, .advertising-banner-horizontal img { display: block; width: 100%; height: auto; }
.advertising-label { position: absolute; z-index: 1; top: 8px; left: 8px; padding: 1px 5px; border: 1px solid currentColor; border-radius: 999px; background: rgb(23 25 28 / 72%); color: #fff; font-size: 9px; font-weight: 700; line-height: 16px; }
.advertising-horizontal { margin-top: var(--page-section-gap); }
/* One creative per breakpoint in the same slot. Impressions come from an
   IntersectionObserver, so the hidden one never records a view. */
.advertising-horizontal-mobile { display: none; }
/* Four equal slots. An unsold slot keeps its space so the row does not reflow into
   three wider banners when one goes unfilled. */
.advertising-mini { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--page-section-gap); }
/* 일반 레이아웃에서는 위 콘텐츠와 붙는다 -- `.advertising-content`는 자식 사이 간격이 없는
   평범한 블록이고, 가로 배너만 자기 여백을 갖고 있었다. 서비스 메인은 미니 행을 직접
   `.root-content`(gap 있음) 안에 놓으므로 이 규칙이 닿지 않는다. */
.advertising-content > .advertising-mini { margin-top: var(--page-section-gap); }
.advertising-mini-slot { min-width: 0; }
/* `position: relative` is not decoration here: the AD label is absolutely positioned,
   so without a positioned ancestor it anchors to the page and floats off in the
   corner of the viewport instead of sitting on the banner. */
.advertising-banner-mini { position: relative; display: block; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-subtle); text-decoration: none; }
.advertising-banner-mini img { display: block; width: 100%; height: auto; }
/* Bottom-left on the mini row only. These four are small and wide, and their
   artwork carries its title along the top edge, so a label in that corner sits on
   top of the words it is labelling. The taller creatives keep it at the top. */
.advertising-banner-mini .advertising-label { top: auto; bottom: 8px; }
/* The track sizes its columns against this box, not against the viewport. The two
   are not the same width: with both ad rails out, a 1100px window leaves the carousel
   about 540px, and a rule written for the window would size four columns for a space
   that holds two. */
.promoted-live { --promoted-live-pad: 14px; container-type: inline-size; min-width: 0; padding: var(--promoted-live-pad); margin: 16px 0 var(--page-section-gap); border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); overflow: hidden; }
/* 머리줄은 패널의 패딩만큼 밖으로 나가 테두리 안쪽에 딱 붙는다. 그 값을 숫자로 적으면
   패딩이 좁은 화면에서 줄어들 때 머리줄이 2px 더 올라가 상단 테두리를 덮는다 -- 가장 작은
   화면에서 위쪽 회색 선이 사라져 보인 원인이다. 패딩을 그대로 따라가게 묶어 둔다. */
.promoted-live-heading { min-height: 38px; display: flex; align-items: center; gap: 7px; padding: 0 14px; margin: calc(var(--promoted-live-pad) * -1) calc(var(--promoted-live-pad) * -1) 14px; border-bottom: 1px solid var(--frame-line); background: var(--frame-head); }
.promoted-live-controls { display: flex; gap: 5px; margin-left: auto; }
.promoted-live-controls button { width: 26px; height: 26px; display: grid; place-items: center; padding: 0; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 12px; line-height: 1; cursor: pointer; }
.promoted-live-controls button:hover { border-color: var(--accent); color: var(--accent); }
/* Hidden rather than disabled when there is nothing to page through: a control that
   never does anything is better absent than greyed. */
.promoted-live-controls[hidden] { display: none; }
.promoted-live-heading h2 { margin: 0; font-size: 16px; font-weight: 700; letter-spacing: -0.028em; }
.promoted-live-heading span { display: inline-flex; align-items: center; height: 16px; padding: 0 7px; border-radius: 999px; background: var(--accent-soft); color: var(--accent-ink); font-size: 9px; font-weight: 700; letter-spacing: 0.02em; }
.promoted-live-viewport { overflow-x: auto; overscroll-behavior-inline: contain; scrollbar-width: none; scroll-behavior: smooth; scroll-snap-type: x mandatory; }
.promoted-live-viewport::-webkit-scrollbar { display: none; }
/* Two rows, always, so the block keeps one shape whatever is on air.
   Columns divide the width exactly, and the count drops as the box narrows. A floor
   like `max(210px, …)` gave the pictures a minimum but left a partial column at the
   edge, and a half-shown card is one a reader can never bring fully into view -- the
   scroll runs out before it is whole. Dividing exactly means every resting position
   shows whole cards, and the fewest columns is one.
   The steps keep a card at 216px or wider at every size, so the thumbnail never falls
   below about 121px tall. */
.promoted-live-track { width: 100%; display: grid; grid-auto-flow: column; grid-template-rows: repeat(2, auto); grid-auto-columns: calc((100% - 36px) / 4); gap: 12px; }
@container (max-width: 928px) { .promoted-live-track { grid-auto-columns: calc((100% - 24px) / 3); } }
@container (max-width: 728px) { .promoted-live-track { grid-auto-columns: calc((100% - 12px) / 2); } }
.promoted-live-card { min-width: 0; width: 100%; display: grid; gap: 8px; color: var(--text); text-decoration: none; scroll-snap-align: start; }
.promoted-live-thumbnail { position: relative; width: 100%; min-height: 106px; aspect-ratio: 16 / 9; display: block; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-subtle); }
.promoted-live-thumbnail img, .promoted-live-fallback { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }
/* 좁은 화면에서 한 장이 폭을 다 쓰면 16/9 썸네일이 화면 높이의 절반을 먹는다. 위 728px
   규칙의 2장 배치를 유지해 폭을 절반으로 두면 비율이 고정이라 높이도 절반이 된다. 풀어야
   하는 것은 `min-height`뿐인데 -- 컨테이너가 약 400px 아래로 내려가면 그 값이 비율을 이겨
   letterbox를 만든다 -- **기본 선언보다 뒤에 와야 한다**. `@container`는 우선순위를 더하지
   않으므로 앞에 두면 나중에 오는 106px이 그대로 이긴다. */
@container (max-width: 488px) { .promoted-live-thumbnail { min-height: 0; } }
.promoted-live-platform, .promoted-live-status { position: absolute; top: 8px; padding: 2px 6px; border-radius: 999px; color: #fff; font-size: 9px; font-weight: 750; line-height: 16px; }
.promoted-live-platform { left: 8px; background: rgb(23 25 28 / 78%); }
.promoted-live-status { right: 8px; background: var(--accent); display: inline-flex; align-items: center; gap: 4px; }
.promoted-live-status::before { content: ""; width: 4px; height: 4px; border-radius: 50%; background: #fff; }
.promoted-live-card strong, .promoted-live-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.promoted-live-card strong { font-size: 13px; }
.promoted-live-title { color: var(--muted); font-size: 11px; }
.axis, .comparison { color: var(--muted); }
.notice { min-height: 48px; padding: 13px 16px; border: 1px solid var(--line); border-radius: var(--radius-md); margin: 0 0 16px; background: var(--surface-subtle); color: var(--warning); }
/* No reserved height. The block used to hold every metric at once and reserved two
   rows of four; the page is now several one-row groups, and each reservation showed
   up as empty space under its row. Server-rendered markup arrives complete, so
   nothing shifts when the height follows the content. */
/* Column counts come from the width a tile actually needs, not from a breakpoint.
   The widest tile on the platform dashboards measures 205px ("이번 달 CHZZK 치즈"
   with nine digits and a unit), so below 4x205 the grid drops a column on its own and
   the numbers never run into each other at an in-between width. */
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(205px, 1fr)); gap: var(--page-section-gap); }
.metrics-single { grid-template-columns: repeat(auto-fit, minmax(205px, 1fr)); }
.metric, .panel { border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); box-shadow: var(--card-shadow); }
/* Fixed height keeps every card in the grid the same size; the content is centred
   vertically so a card with a change reading and one without both look balanced
   rather than top-anchored with a gap. */
.metric { height: 112px; padding: 14px 14px; overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
.metric > span:first-child { min-height: 16px; display: flex; align-items: center; color: var(--muted); font-size: 11px; font-weight: 650; }
.metric-figure { margin-top: 3px; }
.metric strong { display: inline-block; max-width: calc(100% - 28px); overflow: hidden; color: var(--text); font-size: 30px; font-weight: 780; line-height: 40px; letter-spacing: -0.04em; text-overflow: ellipsis; white-space: nowrap; }
.metric small { margin-left: 5px; color: var(--muted); font-size: 12px; }
/* The change reading drops under the figure on its own line, matching the summary. */
.metric .change-badge { display: block; margin: 4px 0 0; }
.comparison { display: flex; align-items: center; font-size: 13px; }
/* Panels hold tables and charts; below about 320px they stop being readable, so that
   is the floor at which they fold rather than a viewport width. */
.chart-grid, .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--page-section-gap); }
.grid-three { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--page-section-gap); }
/* The cell stays a real table-cell so its bottom border lines up with its row's other
   cells; the flex lockup that lays out rank + identity lives one level in. A `display:
   flex` on the td itself dropped it out of the row's height, stepping the divider. */
.rank-identity { vertical-align: middle; }
.rank-lockup { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rank-identity .rank { min-width: 14px; color: var(--accent-ink); font-weight: 700; }
.rank-identity .identity { min-width: 0; }
.platform-badge { flex: none; display: inline-flex; align-items: center; height: 16px; padding: 0 7px; margin-right: 5px; border-radius: 999px; background: var(--accent-soft); color: var(--accent-ink); font-size: 10px; font-weight: 700; letter-spacing: 0.02em; }
/* Two columns: the first carries rank, avatar, name and badge, the second only a
   number. `table-layout: fixed` splits them evenly by default, which clipped the
   name to nothing. */
/* Every ranking panel sizes to its content now; what is left here is the
   rendering. These three are the first thing on the service main, so they are
   never the off-screen case `content-visibility: auto` is for, and skipping them
   only delays the page's own opening screen.

   Two class names, not one: `.ranking-panel` is set further down the sheet, so a
   single class ties on specificity and loses on source order. It did -- these
   panels stayed 362px while their content ran to 379px, and
   `.panel { overflow: hidden }` cut the note off mid-line. */
.panel.root-ranking-panel { height: auto; content-visibility: visible; contain-intrinsic-size: auto; }
/* Widths on the header row only: a fixed table takes its column widths from the first
   row, so the header row alone decides them. (The body cell is a plain table-cell that
   holds a flex `.rank-lockup`; sizing it too would just repeat the header.) */
.root-ranking-panel th:first-child { width: 60%; }
.root-ranking-panel th:last-child { width: 40%; }
/* And the body cell fills the column the header sized. It needs saying because
   `th:first-child, td:first-child` reserves 48px for the rank column elsewhere,
   which would otherwise leave this flex cell at 48px inside a 152px column. */
.root-ranking-panel td:first-child { width: auto; }
/* The second column is one number per row and nothing else, so it reads down the
   column: right-aligned, the digits and the unit under them line up on the same
   edge whatever their length. The header goes with them -- a label over a column
   of right-aligned figures belongs on the same side. */
.root-ranking-panel :where(th, td):last-child { text-align: right; }
.root-ranking-panel td.number .unit { margin-left: 3px; color: var(--muted); font-size: 10px; font-weight: 600; }
/* No row rules: the first cell is a flex row whose content stops well short of the
   column edge, so a per-cell border read as a line that breaks mid-table. Spacing
   separates the rows instead. */
/* A filled row is taller than an empty one because of the 24px avatar, which made
   the three panels look differently spaced whenever one had no data. The row height
   is fixed so all three read the same whether or not a slot is filled. */
.root-ranking-panel :where(th, td) { height: 44px; }
.root-ranking-panel th { height: 34px; }
.root-ranking-panel .ranking-note { height: auto; margin-top: 10px; }
.panel { padding: 14px; margin-bottom: 14px; overflow: hidden; }
/* 그 아래 여백은 패널이 흐름에 쌓일 때를 위한 것이고, gap을 가진 grid 안에서는 두 번
   세는 셈이 된다. 대부분의 페이지에서는 눈에 띄지 않았다: 패널이 트랙을 채우도록 늘어나며
   여백을 흡수한다. 늘어나지 않는 곳 -- `height: auto`를 주는 `.root-ranking-panel` --
   에서만 여백이 트랙 안에 남고, 그래서 메인의 TOP 5가 두 줄로 접히는 순간에만 줄 사이가
   12px이 아니라 26px이 되어 다른 간격과 어긋났다. 간격은 컨테이너의 gap 하나로 정한다. */
:where(.chart-grid, .grid, .grid-three, .detail-grid, .metrics) > .panel { margin-bottom: 0; }
.panel h2 { margin: 0; font-size: 16px; font-weight: 700; letter-spacing: -0.028em; }
.panel-head, .panel > h2:first-child { min-height: 38px; margin: -14px -14px 12px; padding: 0 12px; border-bottom: 1px solid var(--frame-line); background: var(--frame-head); }
.panel-head { display: flex; justify-content: space-between; align-items: center; }
.panel-head-titles { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.panel-eyebrow { color: var(--faint); font-size: 10px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ranking-panel .panel-head { margin: 0; padding: 13px 12px; }
.panel > h2:first-child { display: flex; align-items: center; }
.panel-head a { color: var(--muted); font-size: 11px; font-weight: 600; }
.panel-head a::after { content: "→"; margin-left: 4px; }
.panel-head a:hover { color: var(--accent); }
.chart-panel { height: 270px; }
.chart-panel-empty { display: grid; align-content: center; }
.chart-body { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: stretch; gap: 8px; margin-top: 5px; }
.chart-panel svg { width: 100%; height: 185px; display: block; }
.chart-gridline { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; }
/* The labels sit beside the drawing, not inside it: `preserveAspectRatio="none"`
   stretches everything in the SVG, text included. */
.chart-scale { display: flex; flex-direction: column; justify-content: space-between; padding: 3px 0 12px; color: var(--muted); font-size: 10px; line-height: 12px; text-align: right; white-space: nowrap; }
.chart-plot { position: relative; min-width: 0; }
.chart-panel .chart-area { fill: url(#ptd-chart-fill); }
#ptd-chart-fill .chart-fill-top { stop-color: var(--accent); stop-opacity: 0.22; }
#ptd-chart-fill .chart-fill-bottom { stop-color: var(--accent); stop-opacity: 0; }
.chart-panel .chart-line { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
/* Positioned by app.js from its data-endpoint-* offsets, not an inline style: the CSP
   refuses inline `style` attributes, so a style there never applied and the dot fell to
   the corner. Hidden until the script places it so it never flashes there first. */
.chart-endpoint { position: absolute; width: 9px; height: 9px; border-radius: 50%; background: var(--accent); border: 2.5px solid var(--surface); transform: translate(-50%, -50%); opacity: 0; }
.axis { display: flex; justify-content: space-between; font-size: 10px; }
.daily-stats .streamer-period { margin-bottom: 8px; }
/* Content-sized, like the service main's panels. `fixed_rows` pads every list
   to five rows, so the height is stable whatever the data does -- the only thing
   that varied was the note, and a fixed 362px cut its last line off. The
   reservation stays as a hint for a panel that is still off-screen: `auto 362px`
   uses the remembered size once one has been rendered. */
.ranking-panel { height: auto; content-visibility: auto; contain-intrinsic-size: auto 362px; padding: 0; }
/* The table bleeds to the card edges so its columns share the head's 16px inset --
   otherwise the title sits left of the rows it heads. */
.ranking-panel .table-wrap { margin-top: 0; }
.ranking-panel :where(th, td) { padding: 10px 12px; }
/* The header row sits on a stronger line than the body's dividers, the way the redesign
   separates the column heads from the data. */
.ranking-panel th { border-bottom: 1px solid var(--line-strong); }
/* A subtle line divides rows, but not under the last one (nor an empty slot), so the
   panel does not close on a double edge above its footer. */
.ranking-panel tbody tr:last-child :where(th, td) { border-bottom: 0; }
.ranking-panel .placeholder :where(th, td) { border-bottom: 0; }
/* The footnote is inset with the columns now the panel body carries no padding. */
.ranking-panel .ranking-note { padding: 0 12px; }
/* The second column carries the identity -- avatar, name, sometimes a LIVE badge
   -- and the rest carry five digits at most. A fixed table splits what is left
   evenly, which starved the name at 118px while a number column sat at 118px for
   44px of content. Measured on the SOOP dashboard: the identity needs 127px and
   no number column more than 87px. Not the service main's panels -- those are two
   columns and declare their own split above. */
.ranking-panel:not(.root-ranking-panel) th:nth-child(2) { width: 32%; }
/* 오늘 큰손 names two people -- the 큰손 and the streamer they gave the most to --
   so it is the only panel whose last column is an identity too, and the number
   between them is the one with slack. */
.ranking-panel:has([data-ranking="supporter-ranking"]) th:nth-child(3) { width: 22%; }
/* The two 별풍선/치즈 panels are down to a rank, a name and one number, so the name
   takes the room 후원 횟수 and 큰손 수 left behind rather than handing it all to a
   column that holds five digits. Both ids end the same way: live and today. */
.ranking-panel:has([data-ranking$="donation-ranking"]) th:nth-child(2) { width: 62%; }
.table-wrap { margin-top: 12px; }
.ranking-note { min-height: 32px; margin: 6px 0 0; color: var(--muted); font-size: 10px; line-height: 16px; }
table { border-collapse: collapse; table-layout: fixed; width: 100%; }
th, td { height: 38px; padding: 7px 8px; border-bottom: 1px solid var(--line); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 12px; }
th { height: 34px; background: var(--frame-head); color: var(--faint); font-size: 11px; font-weight: 650; text-align: left; letter-spacing: 0.01em; }
th:first-child, td:first-child { width: 48px; }
/* The title carries the reason to open a broadcast, so it gets the slack the
   category column was holding: categories are a handful of short words. */
.live-table th:nth-child(1), .live-table td:nth-child(1) { width: 18%; }
.live-table th:nth-child(2), .live-table td:nth-child(2) { width: 38%; }
.live-table th:nth-child(3), .live-table td:nth-child(3) { width: 14%; }
.live-table th:nth-child(4), .live-table td:nth-child(4),
.live-table th:nth-child(5), .live-table td:nth-child(5),
.live-table th:nth-child(6), .live-table td:nth-child(6) { width: 10%; }
tbody tr:hover { background: var(--surface-hover); }
td strong, td small { display: block; overflow: hidden; text-overflow: ellipsis; }
td small { color: var(--muted); font-size: 10px; margin-top: 2px; }
/* Only the rank is tinted -- the redesign keeps every value in the plain text
   colour (bold, not red) so a table reads as one voice with a single accent. */
.rank { color: var(--accent-ink); font-weight: 700; }
.accent { color: var(--text); font-weight: 700; }
.identity { display: flex; align-items: center; gap: 7px; min-width: 0; }
.identity-stacked { align-items: center; gap: 8px; }
.identity-lines { min-width: 0; display: grid; gap: 1px; }
.identity-labels { min-height: 14px; display: flex; align-items: center; gap: 3px; }
.identity-labels .platform-badge { margin-right: 0; }
/* 증감 표시. 색은 확인용이고 방향은 화살표가 말한다 -- 색만으로 방향을 싣지 않는다. */
.change-badge { margin-left: 6px; color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: -0.01em; white-space: nowrap; }
.change-badge-up { color: var(--positive); }
.change-badge-down { color: var(--negative); }
.identity-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 650; }
.live-badge { flex: none; display: inline-flex; align-items: center; gap: 3px; height: 16px; padding: 0 6px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 9px; font-weight: 700; letter-spacing: 0.02em; }
.live-badge::before { content: ""; flex: none; width: 4px; height: 4px; border-radius: 50%; background: #fff; }
.identity > a, .identity > span:last-child, .identity strong { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.avatar { display: grid; place-items: center; flex: 0 0 24px; width: 24px; height: 24px; border: 1px solid var(--line); border-radius: 50%; overflow: hidden; background: var(--surface-subtle); }
.profile-thumb, .avatar-fallback { display: block; width: 100%; height: 100%; }
.profile-thumb { object-fit: cover; object-position: 50% 50%; }
.avatar-fallback { background: var(--surface-subtle); }
.placeholder { color: transparent; user-select: none; }
.placeholder .rank { color: var(--line-strong); }
.page-head { min-height: 104px; padding: 22px 0 18px; }
.page-head h1 { margin: 0 0 6px; font-size: 27px; font-weight: 720; letter-spacing: -0.055em; }
.page-aggregation-note { margin: 0; color: var(--muted); font-size: 10px; line-height: 16px; }
/* Ranking list toolbar: a compact title and the period filter share one row, with
   the aggregation note beneath. The title is far smaller than a page hero -- it is
   a section label sitting next to its control, the way the redesign frames a list. */
.list-head { padding: 20px 0 14px; }
.list-head-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap; }
.list-head h1 { margin: 0; font-size: 18px; font-weight: 800; letter-spacing: -0.03em; }
.list-head .page-aggregation-note { margin: 8px 0 0; }
/* The handle is an identifier, so it is set in mono the way the redesign sets it --
   it reads as the thing you type, not as prose. */
.entity-head p { margin: 0; color: var(--muted); font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; font-size: 11.5px; }
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--page-section-gap); align-items: start; }
.detail-grid > .panel { min-width: 0; }
.detail-grid.detail-stack { grid-template-columns: minmax(0, 1fr); }
.detail-metrics { min-height: 0; margin-bottom: 16px; }
.entity-head { min-height: 72px; display: flex; align-items: center; gap: 14px; padding: 16px 18px; margin-bottom: 14px; background: var(--surface); border: 1px solid var(--frame-line); border-radius: var(--frame-radius); box-shadow: var(--card-shadow); }
.entity-head h2 { margin: 0 0 2px; font-size: 18px; letter-spacing: -0.035em; }
.entity-avatar { display: grid; place-items: center; flex: 0 0 48px; width: 48px; height: 48px; border: 1px solid var(--line); border-radius: 50%; overflow: hidden; background: var(--surface-subtle); }
.entity-avatar .profile-thumb, .entity-avatar .avatar-fallback { width: 48px; height: 48px; }
.streamer-profile { min-height: 96px; padding: 16px 18px; }
.streamer-profile .entity-avatar, .streamer-profile .entity-avatar .profile-thumb, .streamer-profile .entity-avatar .avatar-fallback { flex-basis: 56px; width: 56px; height: 56px; }
.streamer-profile-identity { min-width: 0; }
.streamer-profile-identity h1 { margin: 0 0 2px; overflow: hidden; font-size: 19px; font-weight: 800; letter-spacing: -0.03em; text-overflow: ellipsis; white-space: nowrap; }
.streamer-badges { min-height: 20px; display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
/* Tags are filled chips, not outlined ones -- an outline competes with the card's
   own border for attention at this size. */
.streamer-badge { padding: 2px 8px; border-radius: 999px; background: var(--surface-subtle); color: var(--muted); font-size: 10.5px; font-weight: 600; line-height: 15px; }
.streamer-board-link { min-height: 30px; display: inline-flex; align-items: center; padding: 5px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); color: var(--text); font-size: 11px; font-weight: 650; text-decoration: none; }
.streamer-board-link:hover { border-color: var(--accent); }
.streamer-channel-metrics { min-width: 260px; display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; gap: 8px 18px; margin-left: auto; }
.streamer-channel-metrics > span { min-width: 88px; }
.streamer-channel-metrics small, .streamer-channel-metrics strong { display: block; }
.streamer-channel-metrics small, .streamer-channel-metrics time { color: var(--muted); font-size: 11px; font-weight: 600; }
/* The headline figure carries the same weight as a metric card's, so the identity
   card states the streamer's one number rather than whispering it. */
.streamer-channel-metrics strong { margin-top: 2px; font-size: 20px; font-weight: 800; letter-spacing: -0.03em; }
.streamer-channel-metrics time { flex-basis: 100%; margin-left: auto; }
/* Period / tab selectors read as pill tabs: no boxed border, the active one a filled
   accent-soft pill like the badges. One treatment for the list's 오늘/어제·이번 달, the
   fan ranking's 연/월, and the history metric tabs, so they all read as the same control. */
.streamer-period { min-height: 36px; display: flex; align-items: center; flex-wrap: wrap; gap: 4px; margin-bottom: 12px; }
.streamer-period a { display: inline-flex; align-items: center; justify-content: center; padding: 6px 13px; border-radius: 8px; color: var(--muted); font-size: 12.5px; font-weight: 600; text-decoration: none; }
.streamer-period a:hover { background: var(--surface-hover); color: var(--text); }
.streamer-period a.is-active { background: var(--accent-soft); color: var(--accent-ink); }
/* List-page period filter reads as a segmented control -- an enclosing track with
   a raised active segment -- so it stays distinct from the accent-soft pills that
   mark navigation. Matches the redesign's `.p-tabs`. */
.ranking-period { display: inline-flex; width: fit-content; max-width: 100%; align-items: center; flex-wrap: wrap; gap: 3px; padding: 3px; background: var(--surface-subtle); border: 1px solid var(--line); border-radius: 10px; }
.ranking-period a { padding: 6px 13px; border-radius: 7px; }
.ranking-period a:hover { background: transparent; color: var(--text); }
.ranking-period a.is-active { background: var(--surface); color: var(--accent-ink); box-shadow: 0 1px 2px rgba(25, 31, 40, 0.06); }
/* 현재 방송은 상세 페이지에서 유일하게 카드가 아닌 구역이었다. 프로필·기록 패널과 같은
   프레임으로 묶는다. */
.current-live-card { display: grid; grid-template-columns: minmax(230px, 36%) minmax(0, 1fr); gap: 16px; margin-top: 14px; padding: 14px; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); box-shadow: var(--card-shadow); }
.current-live-thumbnail { position: relative; display: block; overflow: hidden; aspect-ratio: 16 / 9; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-subtle); }
.current-live-thumbnail img, .current-live-thumbnail-fallback { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }
/* The same LIVE pill as everywhere else -- it used to be a hard-coded red that never
   followed the accent into dark mode, and it carried no dot. */
.current-live-flag { position: absolute; top: 8px; left: 8px; display: inline-flex; align-items: center; gap: 3px; padding: 2px 6px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 9px; font-weight: 700; }
.current-live-flag::before { content: ""; flex: none; width: 4px; height: 4px; border-radius: 50%; background: #fff; }
/* The count sits on the picture the way a player overlays it, so the thumbnail says
   how many are watching without the eye leaving it. It reads on any frame, so it
   carries its own dark ground rather than a theme surface. */
.current-live-watching { position: absolute; right: 8px; bottom: 8px; padding: 2px 7px; border-radius: 999px; background: rgba(15, 18, 24, 0.66); color: #fff; font-size: 10px; font-weight: 700; }
.current-live-info { min-width: 0; }
/* A broadcast title is the one line worth two: it is cut at two rather than at one,
   because a stream title carries the reason someone would click it. */
/* The card states what it is before it states what is on: a broadcast card and a
   record panel otherwise open the same way. */
.current-live-now { display: inline-flex; align-items: center; gap: 4px; color: var(--accent-ink); font-size: 10.5px; font-weight: 700; letter-spacing: 0.02em; }
.current-live-now::before { content: ""; flex: none; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }
.current-live-info h3 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; margin: 5px 0 0; overflow: hidden; font-size: 17px; font-weight: 700; line-height: 1.35; letter-spacing: -0.03em; }
/* The category reads as a chip, like every other label on the page. */
.current-live-info p { width: fit-content; margin: 7px 0 0; padding: 2px 8px; border-radius: 999px; background: var(--surface-subtle); color: var(--muted); font-size: 10.5px; font-weight: 600; }
/* The three figures are inset tiles, the same ones the 방송 기록 요약 panel below uses. */
.current-live-info dl { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 12px 0 0; }
.current-live-info dl div { min-width: 0; padding: 9px 11px; border-radius: 10px; background: var(--surface-subtle); }
.current-live-info dt { color: var(--muted); font-size: 10.5px; font-weight: 600; }
.current-live-info dd { margin: 2px 0 0; overflow: hidden; font-size: 18px; font-weight: 780; letter-spacing: -0.03em; text-overflow: ellipsis; white-space: nowrap; }
/* An empty history metric is still a chart panel: it carries the same head bar, and
   its message sits in the middle of the drawing area instead of being pushed down by
   a hand-tuned margin. */
.streamer-empty-chart { display: flex; flex-direction: column; }
.streamer-empty-chart > h3 { min-height: 38px; display: flex; align-items: center; margin: -14px -14px 0; padding: 0 12px; border-bottom: 1px solid var(--frame-line); background: var(--frame-head); font-size: 16px; font-weight: 700; letter-spacing: -0.028em; }
.streamer-empty-chart p { flex: 1; display: grid; place-items: center; margin: 0; padding: 0 14px; color: var(--muted); font-size: 12px; text-align: center; }
.streamer-live-strip { margin: 0 0 var(--page-section-gap); }
.streamer-record, .streamer-standing, .streamer-fans, .streamer-history { margin-bottom: var(--page-section-gap); }
.month-selector { display: grid; gap: 2px; margin-bottom: 12px; }
.month-selector .streamer-period { min-height: 34px; flex-wrap: wrap; margin-bottom: 0; }
.month-selector .streamer-period:last-child a { min-width: 40px; }
.streamer-standing-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(155px,1fr)); gap: 14px 18px; margin: 0; }
.streamer-standing-grid div { min-width: 0; }
.streamer-standing-grid dt { color: var(--muted); font-size: 10px; }
.streamer-standing-grid dd { margin: 3px 0 0; overflow: hidden; font-size: 15px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.streamer-standing-grid dd.is-unknown { color: var(--muted); font-size: 12px; font-weight: 500; }
/* Five metrics, one drawn. Radio inputs and a sibling selector rather than script:
   every series is already on the page, and switching must not cost a request. */
.streamer-metric-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
/* The history tabs are the same control as the period pills, so they carry the same
   height and spacing rather than sitting 4px shorter beside them. */
.streamer-metric-tabs { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; margin-bottom: 12px; }
/* The panels share the tab row's container, so they take a line of their own rather
   than lining up beside the tabs as another flex item. */
.streamer-metric-panels { flex: 1 0 100%; margin-top: 8px; }
.streamer-metric-label { min-height: 36px; display: inline-flex; align-items: center; padding: 6px 13px; margin: 0; border-radius: 8px; color: var(--muted); font-size: 12.5px; font-weight: 600; cursor: pointer; }
.streamer-metric-label:hover { background: var(--surface-hover); color: var(--text); }
.streamer-metric-label.is-empty { color: var(--line-strong); }
.streamer-metric-input:checked + .streamer-metric-label { background: var(--accent-soft); color: var(--accent-ink); }
.streamer-metric-input:focus-visible + .streamer-metric-label { box-shadow: inset 0 -2px 0 var(--accent); }
.streamer-metric-panel { display: none; }
.streamer-metric-panel .chart-panel { margin: 0; }
#streamer-metric-donations:checked ~ .streamer-metric-panels .streamer-metric-donations,
#streamer-metric-viewers:checked ~ .streamer-metric-panels .streamer-metric-viewers,
#streamer-metric-fans:checked ~ .streamer-metric-panels .streamer-metric-fans,
#streamer-metric-up:checked ~ .streamer-metric-panels .streamer-metric-up,
#streamer-metric-subscribers:checked ~ .streamer-metric-panels .streamer-metric-subscribers { display: block; }
.page-subtitle { min-height: 30px; margin: 0 0 12px; overflow: hidden; font-size: 17px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.table-scroll { width: 100%; max-height: 640px; overflow: auto; }
.table-scroll th { position: sticky; top: 0; background: var(--frame-head); }
/* The daily Excel matrix can grow to dozens of broadcaster columns. Giving that
   table the global fixed layout divides the viewport evenly until full dates and
   amounts become ellipses. Let its contents set a readable minimum instead and
   use the existing scroll container for the extra width. The date, header, and
   totals stay in view while an operator checks missing entries in either axis. */
.excel-daily-table { width: auto; min-width: 100%; border-collapse: separate; border-spacing: 0; table-layout: auto; }
.excel-daily-table :where(th, td) { overflow: visible; text-overflow: clip; }
.excel-daily-table :where(th, td):first-child { width: auto; min-width: 108px; position: sticky; left: 0; z-index: 1; background: var(--surface); }
.excel-daily-table :where(th, td):not(:first-child) { min-width: 132px; }
.excel-daily-table .number { text-align: right; font-variant-numeric: tabular-nums; }
.excel-daily-table thead th { z-index: 2; border-top: 1px solid var(--line-strong); }
.excel-daily-table thead th:first-child { z-index: 3; background: var(--frame-head); }
.excel-daily-table tbody th { top: auto; }
.excel-daily-table tfoot :where(th, td) { position: sticky; top: auto; bottom: 0; z-index: 2; border-top: 1px solid var(--line-strong); background: var(--frame-head); }
.excel-daily-table tfoot th:first-child { z-index: 3; }
/* 리스트(랭킹 등) 표는 맨몸이 아니라 카드로 감싼다. 관리자 표는 .paged-list 밖이라 영향 없음. */
.paged-list .table-scroll { max-height: none; overflow: hidden; background: var(--surface); border: 1px solid var(--frame-line); border-radius: var(--frame-radius); box-shadow: var(--card-shadow); }
/* The header row gets a firmer rule than the light dividers between rows, so the
   thead reads as the frame of the table -- matching the ranking panels and the redesign. */
.paged-list .table-scroll th { border-bottom: 1px solid var(--line-strong); }
/* A table inside a panel earns the same firm header rule -- otherwise the detail
   page's fan ranking separates its header from its rows with the same hairline it
   uses between rows. And a table already inside a panel must not draw a second card. */
.panel .table-scroll th { border-bottom: 1px solid var(--line-strong); }
.panel .paged-list .table-scroll { border: 0; border-radius: 0; background: transparent; box-shadow: none; }
/* Figures sit against the right edge with their header, the way the redesign sets a
   data table -- a left-aligned column of numbers cannot be read down the page. */
.paged-list :where(th, td).number { text-align: right; }
/* A full-width list has room to keep the unit beside its figure; stacking it is a
   concession to the narrow half-width panels, not the house style. */
.paged-list td.number .unit { display: inline; margin-left: 3px; color: var(--muted); font-size: 10px; font-weight: 600; }
.pagination { min-height: 48px; display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 6px; margin-top: 12px; font-size: 11px; }
.pagination-pages { display: inline-flex; align-items: center; gap: 4px; }
.pagination-control, .pagination-page { display: inline-flex; align-items: center; justify-content: center; min-width: 32px; min-height: 32px; padding: 4px 9px; border: 1px solid transparent; border-radius: 8px; background: transparent; color: var(--muted); font-weight: 600; text-decoration: none; }
.pagination-control:hover, .pagination-page:hover { background: var(--surface-hover); color: var(--text); }
.pagination-page.is-current { border-color: var(--accent); background: var(--accent); color: var(--surface); font-weight: 700; }
/* The submit is the page's primary action, so it is the accent -- the same button
   the home page's search carries. It used to be black here and red there. */
.inquiry-form { max-width: 720px; display: grid; gap: 14px; padding: 18px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.inquiry-form label { display: grid; gap: 6px; color: var(--muted); font-size: 11px; font-weight: 600; }
.inquiry-form input, .inquiry-form select, .inquiry-form textarea { width: 100%; min-height: 38px; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; }
.inquiry-form textarea { min-height: 180px; resize: vertical; }
.inquiry-consent { grid-template-columns: auto minmax(0,1fr); align-items: start; }
.inquiry-consent input { width: 16px; min-height: 16px; margin-top: 2px; }
.inquiry-form input:focus, .inquiry-form select:focus, .inquiry-form textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); outline: 0; }
.inquiry-form button { width: fit-content; min-height: 36px; padding: 7px 16px; border: 1px solid transparent; border-radius: var(--radius-sm); background: var(--accent); color: #fff; font-weight: 700; cursor: pointer; }
.inquiry-form button:hover { filter: brightness(0.94); }
.inquiry-honeypot { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.inquiry-faq-note { max-width: 720px; margin: 0 0 14px; color: var(--muted); font-size: 12px; }
.inquiry-result { min-height: 48px; display: flex; align-items: center; padding: 12px 14px; margin-bottom: 16px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); color: var(--positive); }
.faq-list { max-width: 820px; display: grid; gap: 8px; }
.faq-list details { border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); box-shadow: var(--card-shadow); }
.faq-list summary { min-height: 48px; display: flex; align-items: center; padding: 11px 14px; font-size: 13px; font-weight: 650; cursor: pointer; }
.faq-list details[open] summary { border-bottom: 1px solid var(--line); }
.faq-list details p { margin: 0; padding: 13px 14px 15px; color: var(--muted); font-size: 12px; line-height: 1.75; }
.faq-list details p a { color: var(--text); }
/* 공지·문의 상세는 마크업에 훅만 있고 규칙이 없어 브라우저 기본 스택으로 떨어져 있었다.
   사이트의 다른 표면과 같은 카드로 세운다. */
.notice-list { display: grid; gap: 10px; }
.notice-row { padding: 14px 16px; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); box-shadow: var(--card-shadow); }
.notice-row h2 { margin: 0; font-size: 15px; font-weight: 700; letter-spacing: -0.02em; }
.notice-row p { margin: 5px 0 0; color: var(--muted); font-size: 12px; }
.notice-row time { display: block; margin-top: 8px; color: var(--faint); font-size: 11px; }
.notice-detail, .inquiry-detail { padding: 20px 22px; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); box-shadow: var(--card-shadow); }
.notice-detail h1, .inquiry-detail h1 { margin: 0; font-size: 19px; font-weight: 800; letter-spacing: -0.03em; }
.notice-detail time, .inquiry-detail time { display: block; margin-top: 6px; color: var(--faint); font-size: 11px; }
.notice-body { margin-top: 16px; font-size: 13.5px; line-height: 1.8; }
.inquiry-response { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line); }
.inquiry-response h2 { margin: 0 0 6px; font-size: 14px; font-weight: 700; }
.account-password h2 { margin: 0 0 10px; font-size: 17px; font-weight: 700; letter-spacing: -0.02em; }
/* A panel already is the card; the tiles inside it read as inset stats instead of
   drawing a second card each. */
.panel .metric { border-color: transparent; background: var(--surface-subtle); box-shadow: none; }
/* A subtitle under a page title is caption text, not body copy. */
.page-head p { margin: 0; color: var(--muted); font-size: 12px; }
/* A detail page's identity card is its heading, and the pages that carry one no longer
   render a second heading above it, so the card sets its own top margin. */
.entity-head:first-child { margin-top: 22px; }
.auth-page { min-height: 620px; display: grid; place-items: start center; padding: 72px 0; }
.auth-panel { width: min(400px, 100%); padding: 24px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.auth-panel-wide { width: min(460px, 100%); }
.auth-heading { margin-bottom: 22px; }
.auth-heading h1 { margin: 0; font-size: 22px; letter-spacing: -0.035em; }
.auth-heading p { margin: 5px 0 0; color: var(--muted); font-size: 12px; }
.auth-form { display: grid; gap: 14px; }
.auth-form label { display: grid; gap: 6px; color: var(--text); font-size: 12px; font-weight: 650; }
.auth-form input { width: 100%; min-height: 40px; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); }
.auth-form input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); outline: 0; }
.auth-form small { color: var(--muted); font-size: 10px; font-weight: 450; }
.auth-form button { min-height: 40px; margin-top: 4px; border: 1px solid transparent; border-radius: var(--radius-sm); background: var(--accent); color: #fff; font-weight: 700; cursor: pointer; }
.auth-form button:hover { filter: brightness(0.94); }
/* Built from tokens, not fixed light-mode hexes -- this panel used to stay near-white
   with orange text on the dark canvas. */
.auth-error { min-height: 42px; padding: 10px 12px; margin: 0 0 14px; border: 1px solid var(--line); border-left: 3px solid var(--warning); border-radius: var(--radius-sm); background: var(--surface-subtle); color: var(--warning); font-size: 12px; }
.auth-notice { padding: 12px 14px; margin: 0; border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: var(--radius-sm); background: var(--accent-soft); font-size: 13px; line-height: 1.7; }
.auth-legal { margin: 0; color: var(--muted); font-size: 10px; font-weight: 450; line-height: 1.7; }
.auth-legal a { color: var(--text); }
.auth-link-attention { color: var(--warning); }
.auth-switch { color: var(--muted); font-size: 11px; line-height: 1.6; }
.auth-switch { display: flex; justify-content: center; gap: 3px; margin: 18px 0 0; }
.account-page { width: min(620px, 100%); min-height: 560px; padding: 56px 0; margin-inline: auto; }
.legal-page { width: min(760px, 100%); min-height: 560px; padding: 48px 0; margin-inline: auto; }
.legal-change-summary { margin: -12px 0 18px; color: var(--muted); font-size: 11px; }
.legal-content { display: grid; gap: 24px; padding: 24px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.legal-content section { display: grid; gap: 7px; }
.legal-content h2 { margin: 0; font-size: 15px; }
.legal-content p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.8; white-space: pre-line; }
.legal-versions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 18px; color: var(--muted); font-size: 11px; }
.legal-versions strong { margin-right: 4px; color: var(--text); }
.legal-versions a { padding: 5px 8px; border: 1px solid var(--line); border-radius: 999px; }
.legal-versions a.is-active { border-color: var(--text); color: var(--text); }
.consent-panel { display: grid; gap: 16px; }
.consent-panel .auth-heading { margin-bottom: 0; }
.consent-documents { display: grid; gap: 8px; }
.consent-document { display: grid; gap: 7px; padding: 13px; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.consent-document div { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.consent-document span, .consent-document p { margin: 0; color: var(--muted); font-size: 10px; }
.consent-document a { width: fit-content; color: var(--text); font-size: 11px; text-decoration: underline; text-underline-offset: 2px; }
.account-information { display: grid; margin: 0; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.account-information > div { min-height: 68px; display: grid; grid-template-columns: 120px minmax(0, 1fr); align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.account-information > div:last-child { border-bottom: 0; }
.account-information dt { color: var(--muted); font-size: 11px; font-weight: 600; }
.account-information dd { min-width: 0; margin: 0; overflow-wrap: anywhere; font-size: 13px; font-weight: 600; }
.account-information dd small { display: block; margin-top: 3px; color: var(--muted); font-size: 10px; font-weight: 450; }
.account-moderation { display: grid; gap: 12px; margin-top: 28px; }
.account-moderation h2, .account-moderation h3 { margin: 0; }
.account-moderation h2 { font-size: 17px; }
.account-moderation h3 { margin-top: 8px; font-size: 13px; }
.moderation-help, .moderation-appeal-status { margin: 0; color: var(--muted); font-size: 11px; line-height: 1.7; }
.member-appeal-form { display: grid; gap: 8px; padding: 14px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); }
.member-appeal-form label { display: grid; gap: 7px; font-size: 12px; font-weight: 650; }
.member-appeal-form textarea { min-height: 100px; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); resize: vertical; }
.member-appeal-form button { width: fit-content; min-height: 34px; padding: 6px 12px; border: 1px solid var(--text); border-radius: var(--radius-sm); background: var(--text); color: var(--surface); }
.moderation-member-head > div { display: grid; gap: 4px; }
.moderation-member-head a { width: fit-content; color: var(--muted); font-size: 11px; }
.moderation-admin-section { display: grid; gap: 12px; margin-top: 28px; }
.moderation-admin-section h2, .moderation-action-form h2, .moderation-policy-form h2 { margin: 0; font-size: 16px; }
.moderation-admin-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 28px; }
.moderation-action-form, .moderation-policy-form { align-content: start; }
.moderation-action-form textarea { min-height: 86px; }
.moderation-case-list { display: grid; gap: 12px; }
.moderation-case { padding: 16px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.moderation-case > div { display: flex; align-items: center; gap: 8px; }
.moderation-case h3 { margin: 0 auto 0 0; font-size: 14px; }
.moderation-case > div span { padding: 3px 7px; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: 9px; }
.moderation-case > p { color: var(--muted); font-size: 11px; line-height: 1.7; }
.moderation-case dl { display: grid; grid-template-columns: 90px minmax(0, 1fr); gap: 7px 12px; margin: 12px 0 0; font-size: 11px; }
.moderation-case dt { color: var(--muted); }
.moderation-case dd { min-width: 0; margin: 0; overflow-wrap: anywhere; }
.moderation-case pre, .moderation-admin-section pre { max-width: 680px; margin: 0; overflow: auto; white-space: pre-wrap; font: inherit; }
.inline-admin-action { display: flex; align-items: center; gap: 5px; }
.inline-admin-action input, .inline-admin-action select, .inline-admin-action textarea { min-height: 30px; padding: 5px 7px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); }
.inline-admin-action button { min-height: 30px; padding: 5px 8px; border: 1px solid var(--text); border-radius: var(--radius-sm); background: var(--text); color: var(--surface); }
.site-popup-host:empty { display: none; }
.site-popup-host { display: grid; gap: 10px; padding-top: 12px; }
.site-popup { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; justify-content: space-between; padding: 14px 16px; border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: var(--radius-md); background: var(--accent-soft); color: var(--text); }
.site-popup-main { flex: 1 1 320px; min-width: 0; }
.site-popup-title { margin: 0 0 6px; font-size: 15px; letter-spacing: -0.025em; }
.site-popup-body { font-size: 13px; line-height: 1.75; }
.site-popup-body > :first-child { margin-top: 0; }
.site-popup-body > :last-child { margin-bottom: 0; }
.site-popup-body img { max-width: 100%; height: auto; }
.site-popup-actions { display: flex; flex-shrink: 0; gap: 6px; align-items: center; }
.site-popup-actions button { min-height: 30px; padding: 0 10px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--muted); font-size: 11px; cursor: pointer; }
.site-popup-actions button:hover { border-color: var(--text); color: var(--text); }
.site-notice-host:empty { display: none; }
.site-notice-host { display: grid; gap: 8px; padding-top: 12px; }
.site-notice { border: 1px solid var(--line); border-radius: 8px; background: var(--surface); }
.site-notice a { display: flex; gap: 10px; align-items: baseline; padding: 10px 12px; color: inherit; text-decoration: none; }
.site-notice span { color: var(--muted); font-size: 12px; }
.moderation-appeal-review { align-items: stretch; margin-top: 12px; }
.moderation-appeal-review textarea { flex: 1; min-height: 56px; }
.moderation-policy-form { margin-top: 24px; }
.admin-inquiries-table td:nth-child(4) { max-width: 420px; white-space: normal; }
.admin-inquiry-body { margin: 8px 0 0; color: var(--muted); white-space: pre-wrap; }
.empty-state { min-height: 120px; display: flex; align-items: center; margin: 0; color: var(--muted); }
.primary-entity { min-height: 82px; }
.primary-entity h2 { margin-bottom: 12px; }
.admin-page-head p { margin: 0; color: var(--muted); font-size: 12px; }
.menu-settings { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.menu-card { padding: 18px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.menu-card-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding-bottom: 14px; border-bottom: 1px solid var(--line); }
.menu-card h2 { margin: 0; font-size: 16px; }
.submenu-settings { display: grid; gap: 2px; padding-top: 10px; }
.menu-toggle { min-height: 38px; display: flex; align-items: center; justify-content: space-between; gap: 16px; color: var(--muted); font-size: 12px; font-weight: 600; cursor: pointer; }
.menu-toggle input { width: 34px; height: 18px; accent-color: var(--accent); cursor: pointer; }
.menu-toggle:has(input:disabled) { opacity: 0.45; cursor: default; }
.menu-toggle input:disabled { cursor: default; }
.menu-card-head .menu-toggle { min-height: 24px; color: var(--text); }
.menu-empty { margin: 12px 0 0; color: var(--muted); font-size: 12px; }
.menu-save-bar { min-height: 56px; display: flex; align-items: center; justify-content: flex-end; gap: 16px; margin-top: 12px; }
.menu-save-status { margin: 0; color: var(--positive); font-size: 12px; }
.menu-save-bar button { min-height: 36px; padding: 7px 14px; border: 1px solid var(--text); border-radius: var(--radius-sm); background: var(--text); color: var(--surface); font-weight: 650; cursor: pointer; }
.menu-save-bar button:disabled { border-color: var(--line); background: var(--surface-subtle); color: var(--muted); cursor: default; }
.community-directory, .community-board { margin-top: 24px; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); overflow: hidden; }
.community-directory > header, .community-board-heading { min-height: 44px; display: flex; align-items: center; padding: 0 14px; border-bottom: 1px solid var(--frame-line); background: var(--frame-head); }
.community-directory > header :where(h1, h2), .community-board-heading :where(h1, h2) { margin: 0; font-size: 15px; font-weight: 700; letter-spacing: -0.035em; }
.community-directory-row { min-height: 66px; display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; align-items: center; gap: 11px; padding: 10px 16px; border-bottom: 1px solid var(--line); }
.community-directory-row:last-child { border-bottom: 0; }
.community-directory-row:hover, .community-board-row:hover { background: var(--surface-hover); }
.community-directory-avatar, .community-board-avatar { display: grid; place-items: center; overflow: hidden; border: 1px solid var(--line); border-radius: 50%; background: var(--surface-subtle); }
.community-directory-avatar { width: 38px; height: 38px; }
.community-directory-avatar .profile-thumb, .community-directory-avatar .avatar-fallback, .community-board-avatar .profile-thumb, .community-board-avatar .avatar-fallback { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }
.community-directory-row h2 { margin: 0; font-size: 14px; }
.community-directory-row h2 a { text-decoration: none; }
.community-directory-row p { margin: 2px 0 0; color: var(--muted); font-size: 10px; }
.community-directory-badges { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 5px; }
.community-directory-badges span { padding: 2px 6px; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: 9px; font-weight: 650; }
.community-board-owner { min-height: 106px; display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; align-items: center; gap: 14px; padding: 18px 16px; margin-top: 20px; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); }
.community-board-avatar { width: 64px; height: 64px; }
.community-board-owner-identity { min-width: 0; }
.community-board-owner-identity > span { color: var(--faint); font-size: 10px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; }
.community-board-owner-identity h1 { margin: 2px 0 0; overflow: hidden; font-size: 22px; letter-spacing: -0.045em; text-overflow: ellipsis; white-space: nowrap; }
.community-board-owner-identity p { margin: 2px 0 0; color: var(--muted); font-size: 11px; }
.community-board-owner-links { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 6px; }
.community-board-owner-links a { min-height: 30px; display: inline-flex; align-items: center; padding: 5px 9px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--muted); font-size: 10px; font-weight: 650; text-decoration: none; }
.community-board-owner-links a:hover { border-color: var(--accent); color: var(--accent); }
.community-board-columns { min-height: 32px; display: grid; grid-template-columns: minmax(0, 1fr) 150px; align-items: center; padding: 0 16px; border-bottom: 1px solid var(--line); background: var(--surface-hover); color: var(--muted); font-size: 9px; font-weight: 650; }
.community-board-columns span:last-child { padding-left: 14px; }
.community-board-row { min-height: 68px; display: grid; grid-template-columns: minmax(0, 1fr) 150px; align-items: center; padding: 10px 16px; border-bottom: 1px solid var(--line); }
.community-board-row:last-child { border-bottom: 0; }
.community-board-row-main { min-width: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 7px; }
.community-board-marker { padding: 1px 6px; border-radius: 999px; background: var(--accent-soft); color: var(--accent-ink); font-size: 9px; font-weight: 700; line-height: 16px; }
.community-board-row h2 { min-width: 0; margin: 0; overflow: hidden; font-size: 13px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.community-board-row h2 a { text-decoration: none; }
.community-board-row-main p { grid-column: 1 / -1; margin: 3px 0 0; overflow: hidden; color: var(--muted); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
.community-board-row-meta { display: grid; gap: 2px; padding-left: 14px; color: var(--muted); font-size: 9px; }
.community-board-empty { min-height: 132px; display: flex; align-items: center; padding: 16px; margin: 0; color: var(--muted); font-size: 12px; }
.talk-detail { padding: 18px; border: 1px solid var(--frame-line); border-radius: var(--frame-radius); background: var(--surface); }
.talk-detail-meta { display: flex; gap: 12px; color: var(--muted); font-size: 10px; }
.talk-detail > p { margin: 18px 0 0; white-space: pre-wrap; line-height: 1.75; }
.admin-editor { display: grid; gap: 12px; padding: 18px; margin-bottom: 18px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.admin-editor label { display: grid; gap: 6px; color: var(--muted); font-size: 12px; font-weight: 600; }
.admin-editor input, .admin-editor select, .admin-editor textarea { width: 100%; min-height: 38px; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; }
.admin-editor textarea { min-height: 120px; resize: vertical; }
/* The rule above sizes text inputs, and a checkbox is not one: stretched to the full
   width and 38px tall it renders as a large empty box with its label stranded
   underneath by the grid. Checkboxes keep their own size and sit beside their text. */
.admin-editor input[type="checkbox"] { width: auto; min-height: 0; margin: 0; }
.admin-editor label:has(> input[type="checkbox"]) { grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: 8px; }
.admin-editor label:has(> input[type="checkbox"]) > :not(input[type="checkbox"]) { grid-column: 2; }
.admin-editor > div { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
.admin-weekdays, .admin-footer-links { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.admin-weekdays legend, .admin-footer-links legend { padding: 0 4px; color: var(--muted); font-size: 12px; font-weight: 600; }
.admin-weekdays label, .admin-footer-links label { display: inline-flex; align-items: center; gap: 5px; }
/* The 제30조 warning belongs under the row of switches, not beside the last one. */
.admin-footer-links .admin-field-note { flex: 0 0 100%; }
.admin-editor > div p { margin: 0; color: var(--muted); font-size: 12px; }
.admin-editor button { min-height: 36px; padding: 7px 14px; border: 0; border-radius: var(--radius-sm); background: var(--text); color: var(--surface); cursor: pointer; }
.admin-footer-form { max-width: 820px; }
.legal-admin-section { display: grid; gap: 12px; margin-top: 24px; }
.legal-admin-section h2 { margin: 0; font-size: 16px; }
.legal-admin-editor { max-width: 920px; }
.legal-admin-editor .legal-body-editor { min-height: 360px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; line-height: 1.7; }
.legal-admin-editor small { color: var(--muted); font-size: 10px; font-weight: 450; }
.legal-reconsent-option { grid-template-columns: auto minmax(0, 1fr); align-items: start; }
.legal-reconsent-option input { width: 16px; min-height: 16px; margin-top: 2px; }
.legal-admin-table td:nth-child(2) { min-width: 180px; white-space: normal; }
.legal-admin-table td:nth-child(2) small { display: block; margin-top: 3px; color: var(--muted); font-size: 9px; }
.legal-admin-table td:last-child { min-width: 250px; white-space: normal; }
.legal-status { display: inline-flex; padding: 3px 7px; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: 9px; font-weight: 650; }
.legal-status.is-current { border-color: var(--positive); color: var(--positive); }
.legal-status.is-scheduled { border-color: var(--accent); color: var(--accent); }
.legal-status.is-retired { opacity: 0.6; }
.legal-admin-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.legal-admin-actions form { display: inline-flex; gap: 5px; }
.legal-admin-actions input { min-height: 28px; padding: 4px 6px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); }
.legal-admin-actions button, .legal-admin-actions a { min-height: 28px; display: inline-flex; align-items: center; padding: 4px 7px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 10px; cursor: pointer; }
.legal-admin-audit-table td:nth-child(2) { max-width: 220px; overflow-wrap: anywhere; }
.admin-permission-note { padding: 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--muted); font-size: 11px; }
.account-legal-history { display: grid; gap: 12px; }
.account-legal-history h2 { margin: 0; font-size: 17px; }
.account-legal-history > p { margin: 0; color: var(--muted); font-size: 11px; }
.admin-users-table th:first-child, .admin-users-table td:first-child { width: auto; }
.admin-users-table th:last-child, .admin-users-table td:last-child { min-width: 110px; }
.admin-users-table td small { display: block; margin-top: 3px; color: var(--muted); font-size: 9px; }
.admin-users-table td:last-child a { display: inline-flex; margin: 2px 8px 2px 0; font-size: 10px; white-space: nowrap; }
.admin-member-search { display: grid; grid-template-columns: minmax(220px, 1fr) 130px 130px auto auto; align-items: center; gap: 8px; margin-bottom: 18px; }
.admin-member-search input, .admin-member-search select { min-height: 36px; padding: 7px 9px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; }
.admin-member-search button, .admin-member-search a, .admin-member-links a { min-height: 36px; display: inline-flex; align-items: center; justify-content: center; padding: 7px 11px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font-size: 11px; text-decoration: none; cursor: pointer; }
.admin-member-search button { border-color: var(--text); background: var(--text); color: var(--surface); }
.admin-member-links { display: flex; justify-content: flex-end; margin-top: 14px; }
.admin-member-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; gap: 16px; margin-top: 20px; }
.admin-member-grid .admin-editor { min-width: 0; margin: 0; }
.admin-member-grid .admin-editor h2 { margin: 0; font-size: 16px; }
.admin-member-grid .admin-editor p { margin: 0; color: var(--muted); font-size: 11px; line-height: 1.7; }
.admin-verification-grid, .admin-lifecycle-grid { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.admin-member-notice { padding: 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--muted); font-size: 11px; }
.admin-danger-form { border-color: #d7a5a5; }
.admin-danger-form button { background: #a51d1d; }
.admin-editor button:disabled { opacity: 0.45; cursor: default; }
.admin-user-form { display: flex; align-items: center; gap: 6px; }
.admin-user-form input { display: none; }
.admin-user-form select, .admin-user-form button { min-height: 30px; padding: 4px 7px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; }
.admin-user-form button { background: var(--text); color: var(--surface); cursor: pointer; }
.admin-ad-editors { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; align-items: start; }
.admin-ad-form { min-width: 0; margin-bottom: 18px; }
.admin-ad-form h2 { margin: 0; font-size: 16px; }
.admin-field-note { margin: 0; color: var(--muted); font-size: 11px; }
.admin-section { display: grid; gap: 12px; margin-top: 28px; }
.webhook-events { display: grid; gap: 10px; padding: 14px; border: 1px solid var(--line); border-radius: var(--radius-md); }
.webhook-events legend { padding: 0 6px; color: var(--muted); font-size: 11px; font-weight: 650; }
.webhook-event { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 9px; align-items: start; }
.webhook-event input { width: 16px; min-height: 16px; margin-top: 3px; }
.webhook-event span { display: grid; gap: 2px; }
.webhook-event strong { font-size: 13px; font-weight: 650; }
.webhook-event small { color: var(--muted); font-size: 11px; }
.admin-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.admin-section h2 { margin: 0; font-size: 16px; }
.quota-gauges { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }
.quota-gauge { display: grid; gap: 6px; padding: 14px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.quota-gauge-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 13px; }
.quota-gauge-head span { color: var(--muted); font-size: 12px; font-weight: 650; }
.quota-gauge-track { height: 8px; border-radius: 999px; background: var(--line); overflow: hidden; }
.quota-gauge-fill { height: 100%; background: var(--positive); }
.quota-gauge-warning .quota-gauge-fill { background: var(--warning); }
.quota-gauge-spent .quota-gauge-fill { background: var(--accent); }
.quota-gauge-spent { border-color: var(--accent); }
.quota-gauge small { color: var(--muted); font-size: 11px; }
.visibility-anonymise { border-color: var(--warning); }
.visibility-anonymise legend { color: var(--warning); font-weight: 700; }
.admin-field-note-warning { color: var(--warning); }
.admin-field-note-warning a { color: var(--warning); }
.admin-ad-section { padding: 18px; }
.admin-ad-section > h2 { margin-bottom: 12px; }
.admin-ad-table th:first-child, .admin-ad-table td:first-child { width: auto; }
/* The row editors sit in the last column of a table that has up to twelve of them,
   so the cell they live in is about a hundred pixels wide. Left in flow, the form
   stretched its row to the height of the whole form -- a screen of empty cells beside
   it -- and its fields ran off the right edge of the scrolling container.
   Taken out of flow and anchored to the cell's right edge, the form opens leftwards
   over the columns it does not need, the row keeps its height, and nothing crosses
   the container's edge. It carries its own scroll because it is taller than the
   viewport on the banner table. */
/* `th, td` clip their content so long values ellipsis rather than spill, and `.panel`
   clips so its rounded corners hold. Both of those clip the floating editor too, and
   the cell's box ends exactly where the panel starts, so it disappeared entirely.
   Only the cell holding an open editor, and the section around it, stop clipping. */
.admin-ad-table td:has(> details[open]) { position: relative; overflow: visible; }
.admin-ad-section:has(.admin-ad-table details[open]) { overflow: visible; }
.admin-ad-table details[open] > form {
  position: absolute; top: 100%; right: 0; z-index: 20;
  width: min(340px, 78vw); max-height: min(70vh, 520px); overflow: auto;
  margin: 0; box-shadow: 0 10px 28px rgb(23 25 28 / 22%);
}
/* The summary stays where it is; only the panel moves. */
.admin-ad-table details[open] > summary { position: relative; z-index: 21; }
/* While an editor is open the container stops clipping. An absolutely positioned
   child adds nothing to a scroll container's height, so the panel would be cut off at
   the bottom of the table with no way to scroll down to it. The table is `width: 100%`
   with fixed layout, so nothing escapes sideways; the sticky header gives up its
   stickiness until the editor is closed, which is the cheaper of the two losses. */
.table-scroll:has(.admin-ad-table details[open]) { overflow: visible; max-height: none; }
.admin-inline-action { margin: 0; }
.admin-inline-action button { min-height: 28px; padding: 4px 8px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); font-size: 11px; cursor: pointer; }
.admin-inline-actions { display: flex; align-items: center; gap: 6px; }
.admin-delete-action button { border-color: #c84a4a; color: #a51d1d; }
.admin-campaign-period summary { cursor: pointer; }
.admin-campaign-period form { min-width: 250px; display: grid; gap: 8px; padding: 10px 0 4px; }
.admin-campaign-period label { display: grid; gap: 4px; color: var(--muted); font-size: 10px; }
.admin-campaign-period input { min-height: 32px; padding: 5px 7px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; }
.admin-campaign-period p { margin: 0; color: var(--muted); font-size: 10px; }
.admin-campaign-period button { width: fit-content; min-height: 30px; padding: 4px 8px; border: 1px solid var(--text); border-radius: var(--radius-sm); background: var(--text); color: var(--surface); font-size: 11px; cursor: pointer; }
@media (max-width: 900px) {
  .root-search-form { width: 70%; }
  .advertising-layout.has-side-ads { display: block; }
  .advertising-side { display: none !important; }
  .main-header { height: 112px; align-content: center; flex-wrap: wrap; gap: 4px 12px; padding: 10px 0; }
  .header-primary { width: 100%; overflow-x: auto; scrollbar-width: none; }
  .header-utility { width: 100%; margin-left: 0; justify-content: flex-end; }
  .advertising-mini { display: none; }
  .advertising-horizontal-pc { display: none; }
  .advertising-horizontal-mobile { display: block; }
  .menu-settings { grid-template-columns: 1fr; }
  .admin-ad-editors { grid-template-columns: 1fr; }
  .root-platform-summary { grid-template-columns: 92px minmax(0, 1fr); }
  .streamer-profile { align-items: flex-start; flex-wrap: wrap; }
  .streamer-board-link { margin-left: 76px; }
  .streamer-channel-metrics { width: 100%; margin-left: 76px; justify-content: flex-start; }
  .streamer-channel-metrics time { margin-left: 0; }
  .current-live-card { grid-template-columns: 1fr; }
  .ranking-panel { contain-intrinsic-size: auto 362px; }
}
@media (max-width: 520px) {
  .shell { width: calc(100% - 20px); padding-bottom: 40px; }
  .header-search-dialog { width: calc(100% - 20px); max-height: calc(100dvh - 88px); margin-top: 72px; padding: 16px; }
  .header-search-dialog-form { grid-template-columns: minmax(0, 1fr) 62px; }
  .header-search-dialog-form > button { min-width: 0; padding-inline: 12px; }
  .header-search-dialog-field { padding-inline: 8px; }
  .header-search-dialog-field > svg { display: none; }
  .header-search-dialog-foot { display: none; }
  .root-search-form { width: 100%; }
  .root-search .root-search-form { width: 100%; }
  .donation-alert-stack { right: 8px; bottom: 8px; width: min(272px, calc(100vw - 16px)); }
  
  .wordmark { font-size: 19px; }
  /* `gap`이 없다. `dl`은 `margin: -1px`로 프레임 선 위에 겹쳐 앉도록 되어 있어서, 간격이
     생기면 겹칠 대상을 잃고 셀의 inset 헤어라인이 h2 아래선과 따로 보인다 -- 좁은 화면에서
     회색 줄이 두 개로 읽히던 원인이다. 붙여 두면 넓은 화면과 같은 한 줄이 된다. */
  .root-platform-summary { grid-template-columns: 1fr; grid-template-rows: auto; }
  /* Full mobile: the brand cell is a row, so the live count sits inline beside the
     platform name instead of stacked under it. */
  .root-platform-summary h2 { grid-row: auto; min-height: 32px; flex-direction: row; align-items: center; gap: 8px; border-right: 0; border-bottom: 1px solid var(--frame-line); }
  .root-platform-summary dl { grid-column: 1; }
  .root-platform-summary-note { grid-column: 1; }
  .platform-navigation a { padding-right: 6px; padding-left: 6px; }
  .comparison { display: block; }
  .chart-panel { height: 250px; }
  .chart-panel svg { height: 165px; }
  .panel { padding: 13px; }
  th, td { padding: 7px 5px; font-size: 12px; }
  .identity { gap: 5px; }
  .promoted-live { --promoted-live-pad: 12px; }
  .streamer-metric-label { padding: 6px 8px; margin-right: 4px; }
  .community-board-owner { grid-template-columns: 52px minmax(0, 1fr); }
  .community-board-avatar { width: 52px; height: 52px; }
  .community-board-owner-links { grid-column: 1 / -1; justify-content: flex-start; }
  .community-board-columns { display: none; }
  .community-board-row { grid-template-columns: 1fr; gap: 7px; }
  .community-board-row-meta { display: flex; gap: 10px; padding-left: 0; }
  .community-directory-row { grid-template-columns: 34px minmax(0, 1fr); }
  .community-directory-avatar { width: 34px; height: 34px; }
  .community-directory-badges { grid-column: 2; justify-content: flex-start; }
  .auth-page { min-height: 0; padding: 32px 0; }
  .auth-panel { padding: 18px; }
  .account-page { min-height: 0; padding: 32px 0; }
  .legal-page { min-height: 0; padding: 32px 0; }
  .legal-content { padding: 18px; }
  .account-information > div { grid-template-columns: 88px minmax(0, 1fr); padding: 12px 14px; }
  .moderation-admin-grid { grid-template-columns: 1fr; }
  .admin-member-search, .admin-member-grid, .admin-verification-grid, .admin-lifecycle-grid { grid-template-columns: 1fr; }
  .admin-member-search a, .admin-member-search button { width: 100%; }
  .moderation-case dl { grid-template-columns: 1fr; }
  .inline-admin-action { align-items: stretch; flex-direction: column; }
}
