/* Redis HOL — self-contained stylesheet. No framework, no remote theme.
   Redis HOL — 자체 스타일시트. 프레임워크와 원격 테마를 쓰지 않는다.

   Palette taken from redis.io's own page styles (read 2026-11-07):
   색상은 redis.io 페이지 스타일에서 가져왔다 (2026-11-07 확인):
     #FF4438  Redis red        (redis.io theme colour)
     #091A23  deep navy        (redis.io dark surface)
     #F3F3F3  light surface    (redis.io)
   Tints and shades below are derived from those three for contrast.
   아래의 밝기 변형은 대비 확보를 위해 이 세 색에서 파생했다.

   Dark is the default. Light is opt-in via [data-theme="light"].
   기본은 다크. 라이트는 [data-theme="light"] 로 선택한다. */

:root,
[data-theme="dark"] {
  --bg: #06111a;
  --bg-soft: #091a23;
  --bg-inset: #10242f;
  --fg: #eef1f3;
  --fg-muted: #9fb0ba;
  --border: #1d313c;
  --border-strong: #2a4250;

  --accent: #ff6b61;        /* readable red on dark */
  --accent-strong: #ff4438; /* brand red, for filled controls */
  --accent-soft: #2a1a1c;
  --on-accent: #ffffff;

  /* Heading gradient stops. Both ends stay bright on dark so the h1 keeps
     well clear of the 3:1 large-text minimum.
     제목 그라디언트. 다크에서는 양 끝을 모두 밝게 유지해
     대형 텍스트 최소 대비 3:1 을 여유 있게 넘긴다. */
  --h1-from: #ffb3ad;
  --h1-to: #ff6b61;

  --warn-bg: #2a2113;
  --warn-border: #d0a03c;
  --warn-fg: #f0d9a8;
  --danger-bg: #2c1720;
  --danger-border: #e0567c;
  --danger-fg: #f6bdcd;
  --ok-bg: #10281c;
  --ok-fg: #7fd7a4;

  --radius: 8px;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

[data-theme="light"] {
  --bg: #ffffff;
  --bg-soft: #f3f3f3;   /* redis.io light surface */
  --bg-inset: #e9edf5;
  --fg: #091a23;        /* redis deep navy */
  --fg-muted: #5a6a85;
  --border: #d7dee9;
  --border-strong: #c2ccdb;

  --accent: #d3261b;        /* brand red darkened for 4.5:1 on white */
  --accent-strong: #ff4438;
  --accent-soft: #ffeceb;
  --on-accent: #ffffff;

  --h1-from: #d3261b;
  --h1-to: #091a23;   /* red → navy / 레드 → 네이비 */

  --warn-bg: #fff7e6;
  --warn-border: #d99b1a;
  --warn-fg: #6b4c07;
  --danger-bg: #fdeef1;
  --danger-border: #d84e70;
  --danger-fg: #8a1f3c;
  --ok-bg: #e2f5e9;
  --ok-fg: #146138;

  --shadow: 0 1px 2px rgba(9, 26, 35, 0.08);
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  color-scheme: dark;
}

[data-theme="light"] { color-scheme: light; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 16px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI",
        "Apple SD Gothic Neo", "Noto Sans KR", Roboto, sans-serif;
  word-break: keep-all; /* keeps Korean line breaks sane / 한글 줄바꿈 개선 */
}

/* Chinese and Japanese have no spaces between words, so `keep-all` would leave
   a paragraph unbreakable. They break between characters; `strict` keeps
   closing punctuation off the start of a line. The font stacks put each
   script's own fonts first, so shared Han characters take that script's forms.
   중국어·일본어는 단어 사이에 공백이 없어 `keep-all` 이면 문단이 줄바꿈되지
   않는다. 글자 단위로 끊고, `strict` 로 닫는 문장부호가 줄 머리에 오지 않게 한다.
   언어마다 해당 문자권 폰트를 앞에 두어 공통 한자가 그 언어의 자형으로 나온다. */
.lang[data-lang="zh"], .lang[data-lang="ja"] { word-break: normal; line-break: strict; }
html:lang(zh-Hans) body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
               "Microsoft YaHei", "Noto Sans SC", "Noto Sans CJK SC", Roboto, sans-serif;
}
html:lang(ja) body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans",
               "Hiragino Kaku Gothic ProN", "Yu Gothic", "Meiryo", "Noto Sans JP",
               "Noto Sans CJK JP", Roboto, sans-serif;
}

.wrap { max-width: 900px; margin: 0 auto; padding: 0 20px; }

/* --- Two-column layout ----------------------------------------------
   Page-level navigation stays in the header bar at every width. This left
   column holds only the current page's sections, and only where there is
   room for it — below 1000px the page falls back to a single column.
   페이지 이동은 모든 너비에서 상단 바가 담당한다. 이 좌측 열은 현재 페이지의
   섹션만 담으며, 공간이 있을 때만 나타난다. 1000px 미만에서는 한 열로 돌아간다. */

.layout { display: block; }

.sidebar { display: none; }

@media (min-width: 1000px) {
  .wrap { max-width: 1180px; }

  .layout {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 40px;
    align-items: start;
  }

  .sidebar {
    display: block;
    position: sticky;
    top: calc(var(--topbar-h, 100px) + 20px);
    max-height: calc(100vh - var(--topbar-h, 100px) - 40px);
    overflow-y: auto;
    padding: 32px 0 40px;
    font-size: 14px;
    scrollbar-width: thin;
  }

  /* hidden is set by script when a page has no sections */
  .sidebar[hidden] { display: none; }
}

.side-group {
  margin: 0 0 8px;
  padding-left: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
  opacity: 0.75;
}

/* The page tree for the current section, rendered server-side. Sits above the
   heading list and is separated from it, because it moves you between pages
   while the list below only moves you within one.
   현재 섹션의 페이지 트리. 서버에서 렌더링한다. 제목 목록 위에 두되 구분한다.
   이것은 페이지 사이를 이동하고, 아래 목록은 한 페이지 안에서만 이동한다. */
.side-tree {
  list-style: none;
  margin: 0;
  padding: 0 0 0 10px;
  border-left: 1px solid var(--border);
}

.side-tree li { margin: 0; }

.side-tree > li > a {
  display: block;
  padding: 3px 8px;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 600;
  color: var(--fg);
  text-decoration: none;
  border-radius: 4px;
}

.side-tree > li.side-child > a {
  padding-left: 18px;
  font-weight: 400;
  color: var(--fg-muted);
}

.side-tree > li > a:hover { color: var(--fg); background: var(--bg-soft); }

/* The page you are on is marked, not filled. The filled accent belongs to the
   heading you are currently reading, and two filled rows read as two
   selections.
   현재 페이지는 표시만 하고 배경은 채우지 않는다. 채워진 강조는 지금 읽고 있는
   제목의 몫이며, 채워진 행이 둘이면 선택이 둘로 보인다. */
.side-tree > li > a.here {
  color: var(--accent);
  font-weight: 700;
  box-shadow: inset 2px 0 0 var(--accent);
}

/* Headings of the current page, nested one level below it.
   현재 페이지의 제목들. 그 페이지보다 한 단계 아래에 중첩된다. */
.side-tree .side-toc {
  margin: 2px 0 6px;
  padding-left: 8px;
  border-left: 0;
}

.side-tree .side-toc a { font-size: 12.5px; }
.side-tree .side-toc a.lvl-2 { padding-left: 18px; }
.side-tree .side-toc a.lvl-3 { padding-left: 30px; }

/* In-page headings for the current page, injected by script.
   현재 페이지의 제목 목록. 스크립트가 삽입한다. */
.side-toc {
  list-style: none;
  margin: 0;
  padding: 0 0 0 10px;
  border-left: 1px solid var(--border);
}

.side-toc:empty { display: none; }

.side-toc a {
  display: block;
  padding: 3px 8px;
  font-size: 13px;
  line-height: 1.35;
  color: var(--fg-muted);
  text-decoration: none;
  border-radius: 4px;
}

/* Two levels: h2 sections, h3 beneath them.
   두 단계: h2 섹션과 그 아래 h3. */
.side-toc a.lvl-2 { font-weight: 600; color: var(--fg); }
.side-toc a.lvl-3 { padding-left: 18px; }

.side-toc a:hover { color: var(--fg); background: var(--bg-soft); }
.side-toc a.active { color: var(--accent); background: var(--accent-soft); }

/* Anchor jumps must clear the pinned bar.
   앵커 이동 시 고정된 상단 바에 가려지지 않도록. */
h2[id], h3[id] { scroll-margin-top: calc(var(--topbar-h, 100px) + 16px); }

/* --- Header --------------------------------------------------------- */

/* Header + nav pinned together, so the menu stays reachable while reading.
   Its measured height is published as --topbar-h by script, and anything that
   needs to clear it reads that variable rather than guessing.
   헤더와 네비게이션을 함께 고정해 읽는 동안에도 메뉴에 접근할 수 있게 한다.
   실제 높이는 스크립트가 --topbar-h 로 노출하고, 이를 피해야 하는 요소들은
   값을 추측하지 않고 그 변수를 읽는다. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
}

.site-header {
  border-bottom: 1px solid var(--border);
  background: var(--bg-soft);
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 56px;
  flex-wrap: wrap;
}

.brand {
  font-weight: 650;
  color: var(--fg);
  text-decoration: none;
  font-size: 15px;
}

.brand-mark { color: var(--accent); }

.header-right { display: flex; align-items: center; gap: 10px; }

/* Segmented switches, shared by language and theme.
   언어·테마 토글이 공유하는 세그먼트 스위치. */
.switch {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg);
}

.switch button {
  font: inherit;
  font-size: 12px;
  line-height: 1;
  padding: 6px 10px;
  border: 0;
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
}

.switch button + button { border-left: 1px solid var(--border-strong); }
.switch button:hover { background: var(--bg-inset); color: var(--fg); }

.switch button.active {
  background: var(--accent-strong);
  color: var(--on-accent);
}

.switch button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* Language menu: a globe that opens a short list under it.
   언어 메뉴: 지구본을 누르면 아래에 짧은 목록이 열린다. */
.lang-menu { position: relative; }

.lang-trigger {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: inherit;
  font-size: 12px;
  line-height: 1;
  padding: 5px 9px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--fg-muted);
  cursor: pointer;
}
.lang-trigger:hover,
.lang-trigger[aria-expanded="true"] { background: var(--bg-inset); color: var(--fg); }
.lang-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lang-code { min-width: 1.4em; text-align: left; }

.lang-list {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 128px;
  padding: 4px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .25);
}
.lang-list[hidden] { display: none; }
/* On a phone the header wraps and the globe sits at the left edge, so the
   menu opens rightwards instead of off-screen.
   휴대폰에서는 헤더가 줄바꿈되어 지구본이 왼쪽 끝에 오므로, 메뉴를 화면 밖이
   아니라 오른쪽으로 연다. */
@media (max-width: 600px) { .lang-list { left: 0; right: auto; } }
.lang-list button {
  font: inherit;
  font-size: 13px;
  text-align: left;
  padding: 7px 10px;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
}
.lang-list button:hover { background: var(--bg-inset); color: var(--fg); }
.lang-list button.active { color: var(--accent); font-weight: 600; }
.lang-list button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.gh { font-size: 13px; color: var(--fg-muted); text-decoration: none; }
.gh:hover { color: var(--accent); }

/* --- Nav ------------------------------------------------------------ */

.site-nav {
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

.nav-inner {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
}
.nav-inner::-webkit-scrollbar { display: none; }

.nav-inner a {
  padding: 10px 12px;
  font-size: 14px;
  color: var(--fg-muted);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}

.nav-inner a:hover { color: var(--fg); }

.nav-inner a.current {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

/* Separates the three kinds of page — start, lab tracks, reference — without
   spending a second nav row on group headings.
   시작 / 실습 트랙 / 레퍼런스 세 종류를 구분한다.
   그룹 제목을 위해 두 번째 줄을 쓰지 않아도 되도록. */
.nav-divider {
  flex: 0 0 auto;
  align-self: center;
  width: 1px;
  height: 14px;
  margin: 0 10px;
  background: var(--border-strong);
}

/* --- Content -------------------------------------------------------- */

.content { padding: 32px 20px 64px; }

h1, h2, h3, h4 { line-height: 1.3; margin: 1.8em 0 0.6em; }

h1 {
  font-size: 30px;
  margin-top: 0;
  letter-spacing: -0.02em;
  background: linear-gradient(92deg, var(--h1-from) 0%, var(--h1-to) 75%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  width: fit-content;
}

h2 {
  font-size: 22px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

h3 { font-size: 17px; }

p, ul, ol { margin: 0.8em 0; }
li { margin: 0.3em 0; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-strong); }

[data-theme="dark"] a:hover { color: #bbb6fd; }

hr { border: 0; border-top: 1px solid var(--border); margin: 2.5em 0; }

code {
  font-family: var(--mono);
  font-size: 0.88em;
  background: var(--bg-inset);
  padding: 0.15em 0.4em;
  border-radius: 4px;
}

pre {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  overflow-x: auto;
  font-size: 13px;
  line-height: 1.5;
}

pre code { background: none; padding: 0; font-size: inherit; }
/* A long inline path or id has no break opportunity and would widen a phone
   page past the screen; let it break anywhere. Code blocks scroll instead.
   긴 인라인 경로나 id 는 끊을 곳이 없어 휴대폰에서 페이지를 화면보다 넓힌다.
   아무 데서나 끊게 한다. 코드 블록은 대신 스크롤된다. */
:not(pre) > code { overflow-wrap: anywhere; }

blockquote {
  margin: 1.2em 0;
  padding: 2px 16px;
  border-left: 3px solid var(--accent-strong);
  background: var(--accent-soft);
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--fg);
}

table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.2em 0;
  font-size: 14px;
  display: block;
  overflow-x: auto;
}

th, td {
  border: 1px solid var(--border);
  padding: 8px 11px;
  text-align: left;
  vertical-align: top;
}

th { background: var(--bg-soft); font-weight: 600; }

/* --- Language blocks ------------------------------------------------ */

.lang[hidden] { display: none; }
.lang > h2:first-child { margin-top: 0.6em; }

/* --- Callouts ------------------------------------------------------- */

.note, .warn, .danger {
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-left-color: var(--accent-strong);
  border-radius: var(--radius);
  padding: 12px 16px;
  margin: 1.2em 0;
  background: var(--bg-soft);
}

.warn {
  background: var(--warn-bg);
  border-left-color: var(--warn-border);
  color: var(--warn-fg);
}

.danger {
  background: var(--danger-bg);
  border-left-color: var(--danger-border);
  color: var(--danger-fg);
}

.warn code, .danger code { background: rgba(127, 127, 127, 0.18); }
.warn a, .danger a { color: inherit; }

.note > :first-child, .warn > :first-child, .danger > :first-child { margin-top: 0; }
.note > :last-child, .warn > :last-child, .danger > :last-child { margin-bottom: 0; }

/* --- Track cards ---------------------------------------------------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
  margin: 1.5em 0;
}

.card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  background: var(--bg-soft);
  box-shadow: var(--shadow);
  transition: border-color 0.12s ease, transform 0.12s ease;
}

.card:hover {
  border-color: var(--accent-strong);
  transform: translateY(-1px);
}

.card h3 { margin: 0 0 6px; font-size: 16px; }
.card h3 a { text-decoration: none; }
.card p { margin: 0 0 8px; font-size: 14px; color: var(--fg-muted); }

.badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 20px;
  background: var(--bg-inset);
  color: var(--fg-muted);
}

.badge.ready { background: var(--ok-bg); color: var(--ok-fg); }
.badge.planned { background: var(--accent-soft); color: var(--accent); }
.badge.tbd { background: var(--warn-bg); color: var(--warn-border); }

/* --- Footer --------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--border);
  padding: 28px 0 48px;
  font-size: 13px;
  color: var(--fg-muted);
  background: var(--bg-soft);
}

.site-footer p { margin: 0.4em 0; }

@media (max-width: 600px) {
  h1 { font-size: 25px; }
  .content { padding-top: 24px; }
  .header-inner { padding-bottom: 8px; }
}

/* Console screenshots (#52, #53): captured in dark mode, account details masked. */
.shot { margin: 1.25rem 0 1.5rem; }
.shot img { display: block; max-width: 100%; height: auto; border: 1px solid var(--border-strong); border-radius: 8px; }
.shot figcaption { margin-top: .45rem; font-size: .85rem; color: var(--fg-muted); }

/* Sizing calculators on /readings/gpu-llm-basics/ (#58). */
.calc { border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--bg-soft); margin: 1.25rem 0 1.75rem; }
.calc-hd { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding: .7rem 1rem; border-bottom: 1px solid var(--border); }
.calc-hd span { font: .75rem var(--mono); color: var(--fg-muted); letter-spacing: .05em; }
.calc-bd { padding: 1rem; }
.calc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: .75rem 1rem; }
.calc-grid label { display: block; font-size: .8rem; color: var(--fg-muted); margin-bottom: .25rem; }
.calc-grid input, .calc-grid select { width: 100%; box-sizing: border-box; padding: .4rem .5rem; font: inherit; font-size: .9rem;
  color: var(--fg); background: var(--bg); border: 1px solid var(--border-strong); border-radius: 6px; }
.calc-grid select:disabled { opacity: .5; }
.calc-out { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: .5rem; margin-top: 1rem; }
.calc-out div { background: var(--bg-inset); border-radius: 6px; padding: .5rem .65rem; }
.calc-out span { display: block; font-size: .75rem; color: var(--fg-muted); }
.calc-out b { font: 600 1.15rem var(--mono); }
.calc-out .hi { outline: 1px solid var(--accent); }
.calc-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; margin-top: .9rem; background: var(--bg-inset); }
.calc-bar i:nth-child(1) { background: var(--accent); }
.calc-bar i:nth-child(2) { background: var(--warn-border); }
.calc-bar i:nth-child(3) { background: var(--danger-border); }
.calc-bar i:nth-child(4) { background: var(--fg-muted); }
.calc-key { display: flex; flex-wrap: wrap; gap: .3rem 1rem; font-size: .75rem; color: var(--fg-muted); margin-top: .4rem; }
.calc-key s { display: inline-block; width: .7rem; height: .7rem; border-radius: 2px; margin-right: .3rem; vertical-align: -1px; text-decoration: none; }
.calc-key s.k1 { background: var(--accent); } .calc-key s.k2 { background: var(--warn-border); }
.calc-key s.k3 { background: var(--danger-border); } .calc-key s.k4 { background: var(--fg-muted); }
.calc-verdict { margin-top: .9rem; font-size: .9rem; line-height: 1.55; }
.calc-bad { color: var(--danger-border); }
@media (max-width: 600px) { .calc-grid, .calc-out { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem; } .calc-bd { padding: .75rem; } }
