/* 한지 · 먹 · 도장 — the v4 theme: a scholar's desk. Hanji paper, brush ink,
   and red seal ink for accents and for marking work done. Dark mode is the
   same desk at night: ink-black paper with the writing in hanji tones. */

:root {
  color-scheme: light dark;

  /* Ink in four strengths: text, secondary text, tertiary text (still 4.4:1
     on the paper), and ink-4 for dashes and outlines only, never text. */
  --paper: #f4ecdd;
  --paper-raised: #fbf7ef;
  --ink: #1f1b16;
  --ink-2: #5e5447;
  --ink-3: #766955;
  --ink-4: #a39680;
  --rule: #dccfb8;
  --seal: #b8322a;
  --on-seal: #fff8ec;
  /* The carved character of a seal: hanji-white in both modes, unlike text
     on a seal-red button, which is dark at night to stay readable. */
  --seal-glyph: #fff8ec;
  --pine: #3f5e4b;
  --wood: #3b2b1d;
  --frame: color-mix(in srgb, var(--seal) 55%, var(--paper));
  --shadow: 0 1px 2px rgb(60 40 20 / .08), 0 8px 20px -10px rgb(60 40 20 / .3);
  --stamp-blend: multiply;
  /* Paper tooth plus a few long, faint fibres. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='t' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .36 0 0 0 0 .28 0 0 0 0 .18 .5 0 0 0 -.21'/%3E%3C/filter%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='turbulence' baseFrequency='.016' numOctaves='3' seed='9' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .36 0 0 0 0 .28 0 0 0 0 .18 -1.1 0 0 0 .1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23t)'/%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");

  --font-display: "Song Myung", "Gowun Batang", "AppleMyungjo", "Noto Serif KR", serif;
  --font-serif: "Gowun Batang", "AppleMyungjo", "Noto Serif KR", serif;
  --font-sans: system-ui, -apple-system, "Apple SD Gothic Neo", "Pretendard", "Noto Sans KR", sans-serif;

  /* The type scale for UI text; display sizes are set where they're used. */
  --text-xs: 12.5px;
  --text-sm: 14px;
  --text-md: 16px;
  --text-lg: 18px;
  --text-xl: 20px;
  --radius: 6px;
  --shadow-sm: 0 1px 2px rgb(60 40 20 / .12);

  /* 진도's meters: known words in pine, learning ones a lighter step of it,
     on a track lighter still. Both steps pass the dataviz ordinal checks
     against the raised paper, in light and dark. */
  --learning: color-mix(in srgb, var(--pine) 50%, var(--paper-raised));
  --track: color-mix(in srgb, var(--pine) 12%, var(--paper-raised));

  --measure: 680px;
  /* 단어장's list and word side by side. */
  --wide: 1120px;
  --gutter: 16px;
  --tabbar-h: 60px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #17140f;
    --paper-raised: #221d17;
    --ink: #ede4d3;
    --ink-2: #a89c88;
    --ink-3: #8f8472;
    --ink-4: #6e6557;
    --rule: #3a3228;
    --seal: #dd5c4e;
    --on-seal: #17140f;
    --pine: #86ad93;
    --wood: #7a6149;
    --shadow: 0 1px 2px rgb(0 0 0 / .4), 0 10px 24px -12px rgb(0 0 0 / .7);
    --shadow-sm: 0 1px 2px rgb(0 0 0 / .45);
    --stamp-blend: normal;
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='t' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .93 0 0 0 0 .89 0 0 0 0 .83 .4 0 0 0 -.17'/%3E%3C/filter%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='turbulence' baseFrequency='.016' numOctaves='3' seed='9' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .93 0 0 0 0 .89 0 0 0 0 .83 -1 0 0 0 .08'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23t)'/%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  }
}

/* Base */

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { background: var(--paper); -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  min-height: 100vh;
  padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  background: var(--paper) var(--grain);
  color: var(--ink);
  font: 16px/1.65 var(--font-serif);
  word-break: keep-all;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}
:focus-visible { outline: 2px solid var(--seal); outline-offset: 3px; border-radius: 2px; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.ink-defs { position: absolute; }

/* Seals: 음각 (carved), the character in paper on red. */

.seal { display: block; color: var(--seal); overflow: visible; }
.seal-face { fill: currentColor; }
.seal-text { fill: var(--seal-glyph); font: 700 25px var(--font-serif); }

/* Masthead and navigation: a tab bar along the bottom on the phone, links
   in the masthead on wider screens. */

.masthead {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: calc(var(--measure) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 14px var(--gutter);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-right: auto;
  color: var(--ink);
  text-decoration: none;
}
.brand .seal { width: 30px; height: 30px; rotate: -4deg; }
.brand-name { font-weight: 700; font-size: 17px; letter-spacing: .02em; }

.settings {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-right: -8px;
  padding: 8px;
  border-radius: 8px;
  color: var(--ink-2);
  text-decoration: none;
  font-size: 15px;
}
.settings[aria-current] { color: var(--ink); }
.settings svg { width: 22px; height: 22px; }
.settings-label { display: none; }

.tabs {
  position: fixed;
  inset: auto 0 0;
  z-index: 10;
  display: flex;
  padding: 0 max(8px, env(safe-area-inset-right)) env(safe-area-inset-bottom) max(8px, env(safe-area-inset-left));
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--rule);
}
.tab {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: var(--tabbar-h);
  color: var(--ink-2);
  text-decoration: none;
  font: 500 11px/1 var(--font-sans);
  letter-spacing: .02em;
}
.tab svg { width: 22px; height: 22px; }
.tab[aria-current] { color: var(--ink); font-weight: 700; }
.tab[aria-current]::before {
  content: "";
  position: absolute;
  top: -1px;
  left: calc(50% - 11px);
  width: 22px;
  height: 3px;
  border-radius: 0 0 2px 2px;
  background: var(--seal);
}

main {
  max-width: calc(var(--measure) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter) 48px;
}

/* Hero: the date, a brush-written 오늘, and a proverb hung like a scroll in
   front of a lattice window. */

.hero {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "main scroll" "cta cta";
  gap: 28px 16px;
  padding: 12px 0 40px;
}
.lattice {
  position: absolute;
  top: -8px;
  right: calc(-1 * var(--gutter));
  z-index: -1;
  width: 75%;
  height: 100%;
  color: var(--ink);
  opacity: .08;
  pointer-events: none;
}

.hero-main { grid-area: main; align-self: center; }
.hero-date {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 10px;
  min-height: 1.6em;
  margin: 0;
  color: var(--ink-2);
  font: 500 14px/1.6 var(--font-sans);
  letter-spacing: .02em;
}
.term { color: var(--pine); font: 700 14px var(--font-serif); }
.term::after { content: attr(data-hanja); margin-left: 5px; font-weight: 400; opacity: .75; }

.hero-title {
  position: relative;
  display: inline-block;
  margin: 10px 0 14px;
  font: 400 clamp(64px, 19vw, 96px)/1 var(--font-display);
  letter-spacing: .04em;
}
.hero-word { position: relative; }
.brush {
  position: absolute;
  left: -10%;
  bottom: -.14em;
  width: 150%;
  height: .55em;
  color: var(--ink);
  opacity: .17;
  overflow: visible;
}
.brush path { fill: currentColor; }
.hero-lede { margin: 0; color: var(--ink-2); }

.scroll {
  grid-area: scroll;
  position: relative;
  align-self: start;
  margin: 22px 6px 0 0;
  padding: 10px 7px 12px;
  background: color-mix(in srgb, var(--pine) 20%, var(--paper-raised));
  border-top: 4px solid var(--wood);
  box-shadow: var(--shadow);
}
/* The cord it hangs from, and the weighted rod at the bottom. */
.scroll::before {
  content: "";
  position: absolute;
  top: -12px;
  left: calc(50% - 10px);
  width: 20px;
  height: 20px;
  border-top: 1px solid var(--ink-2);
  border-left: 1px solid var(--ink-2);
  rotate: 45deg;
}
.scroll::after {
  content: "";
  position: absolute;
  left: -6px;
  right: -6px;
  bottom: -5px;
  height: 7px;
  border-radius: 4px;
  background: var(--wood);
}
.scroll-paper {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 16px 10px 12px;
  background: var(--paper-raised) var(--grain);
}
.scroll-text {
  min-height: 7em;
  margin: 0;
  writing-mode: vertical-rl;
  font: 400 19px/1.75 var(--font-display);
  letter-spacing: .12em;
}
.scroll-text span { display: block; }
/* 양각 (relief): the character in red inside a red border. */
.scroll-seal { align-self: flex-start; }
.scroll-seal .seal { width: 22px; height: 22px; }
.scroll-seal .seal-face { fill: none; stroke: currentColor; stroke-width: 3.2; }
.scroll-seal .seal-text { fill: currentColor; }

.cta {
  grid-area: cta;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 20px;
  border-radius: 4px;
  background: var(--ink);
  color: var(--paper);
  box-shadow: var(--shadow);
  text-decoration: none;
  font: 700 17px/1.2 var(--font-serif);
  transition: background-color .2s, color .2s;
}
.cta:active { translate: 0 1px; }
.cta-next { font: 500 14px var(--font-sans); opacity: .8; }
.cta-next::after { content: "→"; margin-left: 10px; }

/* Section headings, marked with a dab of seal red. */

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.section-head :is(h2, h3) {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font: 700 19px/1.3 var(--font-serif);
  letter-spacing: .02em;
}
.section-head :is(h2, h3)::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 1px;
  background: var(--seal);
}
.section-note { margin: 0; color: var(--ink-2); font: 14px var(--font-sans); }

/* The plan, ruled like a page of an old woodblock-printed book: a double
   frame (thick outside, thin inside) and a rule between the lines. The
   areas of a tab share the frame. */

.steps, .areas {
  margin: 0 5px;
  padding: 0;
  list-style: none;
  border: 1px solid var(--frame);
  outline: 2px solid var(--frame);
  outline-offset: 3px;
}
.step {
  position: relative;
  display: grid;
  grid-template-columns: 52px 1fr auto;
  align-items: center;
  min-height: 68px;
}
.step + .step { border-top: 1px solid var(--frame); }
.step-num {
  display: grid;
  place-items: center;
  align-self: stretch;
  border-right: 1px solid var(--frame);
  color: var(--ink-3);
  font: 400 26px/1 var(--font-display);
}
.step-body { min-width: 0; padding: 12px 14px; }
.step-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font: 700 17px/1.35 var(--font-serif);
}
.step-meta { margin: 2px 0 0; color: var(--ink-2); font: 13.5px/1.5 var(--font-sans); }
.step-time {
  padding-right: 14px;
  color: var(--ink-2);
  font: 13px var(--font-sans);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.step.is-done .step-title { color: var(--ink-2); }

.step.is-current { background: var(--paper-raised) var(--grain); }
.step.is-current .step-num { color: var(--seal); }
.now {
  padding: 4px 6px 3px;
  border-radius: 2px;
  background: var(--seal);
  color: var(--on-seal);
  font: 700 11px/1 var(--font-sans);
  letter-spacing: .04em;
}
.words {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 2px;
  padding: 0;
  list-style: none;
}
.words li {
  padding: 2px 9px 1px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: var(--paper);
  font-size: 15px;
}
/* Words already met today, ticked off in pine. */
.words li.is-learned { color: var(--ink-2); }
.words li.is-learned::before { content: "✓"; margin-right: 4px; color: var(--pine); font: 700 13px var(--font-sans); }

/* 참 잘했어요: the teacher's stamp on a finished step. */
.stamp {
  position: absolute;
  top: calc(50% - 34px);
  right: 50px;
  width: 68px;
  height: 68px;
  color: var(--seal);
  opacity: .9;
  mix-blend-mode: var(--stamp-blend);
  rotate: -14deg;
  pointer-events: none;
  animation: stamp-in .5s cubic-bezier(.2, .8, .3, 1) .3s both;
}
.stamp-text { fill: currentColor; font-family: var(--font-serif); font-weight: 700; }
/* A step that couldn't be prepared (today's text, when writing it failed):
   the reason in seal ink, its detail and 다시 시도 on a quieter line. */
.step.has-trouble .step-meta { color: var(--seal); }
.step-trouble { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 10px; margin: 2px 0 0; }
.step-trouble .note-detail { display: inline; margin: 0; }
.step-trouble .link { min-height: 28px; font-size: 13px; }

/* A step gets its stamp only once it was done today. */
.step:not(.is-stamped) .stamp { display: none; }
@keyframes stamp-in {
  from { opacity: 0; scale: 1.5; }
  60% { opacity: .9; scale: .95; }
  to { opacity: .9; scale: 1; }
}

/* This week, as a stamp board: each studied day gets its weekday's seal. */

.week { margin-top: 44px; }
.days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.day .seal { width: 100%; max-width: 44px; height: auto; aspect-ratio: 1; color: var(--ink-4); }
.day .seal-face { fill: none; stroke: currentColor; stroke-width: 1.2; stroke-dasharray: 3 3; }
.day .seal-text { fill: currentColor; opacity: .55; }

.day.is-done .seal { color: var(--seal); mix-blend-mode: var(--stamp-blend); rotate: -4deg; }
.day.is-done:nth-child(2n) .seal { rotate: 3deg; }
.day.is-done:nth-child(3n) .seal { rotate: -1deg; }
.day.is-done .seal-face { fill: currentColor; stroke: none; }
.day.is-done .seal-text { fill: var(--seal-glyph); opacity: 1; }
.day.is-missed .seal { opacity: .6; }
.day.is-today .seal { color: var(--ink); }
.day.is-today .seal-face { stroke-width: 1.6; stroke-dasharray: none; }
.day.is-today .seal-text { opacity: 1; }

/* 외부 링크: a small label per group over its links, each a chip opening in
   a new tab (↗), the ones added here with a × of their own to delete them. */

.links { margin-top: 44px; }
.link-group + .link-group { margin-top: 20px; }
.link-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.link-group-head h3 { margin: 0; color: var(--ink-2); font: 600 var(--text-sm)/1.3 var(--font-sans); letter-spacing: .02em; }
.link-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.link-chip {
  display: flex;
  min-width: 0;
  max-width: 100%;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--paper-raised);
  font: var(--text-sm)/1.3 var(--font-sans);
  transition: border-color .15s;
}
.link-chip a {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  min-height: 36px;
  padding: 6px 14px;
  border-radius: 999px;
  color: var(--ink);
  text-decoration: none;
}
.link-chip a::after { content: "↗"; content: "↗" / ""; flex: none; color: var(--ink-3); font-size: 12px; }
.link-chip-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.link-chip:has(.link-chip-remove) a { padding-right: 10px; border-radius: 999px 0 0 999px; }
.link-chip-remove {
  flex: none;
  width: 34px;
  padding: 0 3px 1px 0;
  border: 0;
  border-left: 1px solid var(--rule);
  border-radius: 0 999px 999px 0;
  background: none;
  color: var(--ink-3);
  font: 18px/1 var(--font-sans);
  cursor: pointer;
}
.link-empty { margin: 0; color: var(--ink-3); font: var(--text-sm)/1.5 var(--font-sans); }
.links .panel-error { margin: 8px 0 0; }
.link-form { display: grid; gap: 8px; margin-bottom: 14px; }
.link-form .panel-error { margin: 0; }
.link-form-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* A question to confirm (deleting a link), over the page. The dialog has no
   padding of its own, so a click on it is a click on the backdrop. */
.confirm {
  width: min(360px, calc(100% - 2 * var(--gutter)));
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised) var(--grain);
  color: var(--ink);
  box-shadow: var(--shadow);
}
.confirm::backdrop { background: rgb(20 15 10 / .45); }
.confirm form { padding: 20px 20px 16px; }
.confirm-title { margin: 0; font: 700 var(--text-lg)/1.4 var(--font-serif); }
.confirm-detail { margin: 6px 0 0; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); overflow-wrap: anywhere; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
.button.danger { background: var(--seal); color: var(--on-seal); }

/* The build line: only 설정 shows it, under its panels. */
.footer {
  max-width: calc(var(--measure) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter) 32px;
  color: var(--ink-2);
  text-align: center;
  font: 13px var(--font-sans);
}
.footer::before {
  content: "";
  display: block;
  width: 40px;
  height: 1px;
  margin: 0 auto 16px;
  background: var(--ink-4);
}

/* Buttons: ink on paper, turning seal red under a mouse pointer (hover
   styles wait for a mouse, so a tapped button doesn't stay red on a phone).
   A quiet one is just an outline, for the less usual actions; a disabled
   one is a dashed outline, so it can't be mistaken for either. */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 46px;
  padding: 10px 22px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--paper);
  box-shadow: var(--shadow-sm);
  font: 700 var(--text-md)/1.2 var(--font-serif);
  letter-spacing: .02em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .2s, color .2s, border-color .2s;
}
.button:active:not(:disabled) { translate: 0 1px; }
.button:disabled { border: 1px dashed var(--ink-4); background: none; color: var(--ink-3); box-shadow: none; cursor: default; }
.button.quiet:not(:disabled) { border-color: color-mix(in srgb, var(--ink) 35%, transparent); background: none; color: var(--ink); box-shadow: none; }

/* A plain text action (번역 보기, 그만하기, 되돌리기), padded to a size a
   thumb can hit without looking any bigger. */
.link {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-2);
  font: var(--text-sm) var(--font-sans);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  text-underline-offset: 3px;
  cursor: pointer;
}
.link:disabled { color: var(--ink-3); text-decoration: none; cursor: default; }

.field {
  width: 100%;
  min-height: 46px;
  padding: 10px 13px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
  color: var(--ink);
  font: var(--text-md)/1.4 var(--font-sans);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .15s, box-shadow .15s;
}
.field::placeholder { color: var(--ink-3); }
.field:focus { border-color: var(--ink-2); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink) 10%, transparent); }
.field.number { width: 5em; min-height: 40px; padding: 6px 10px; text-align: right; font-variant-numeric: tabular-nums; }
.is-missing { color: var(--ink-3); }

/* Page heads: every page but 오늘 opens with its name in the display face,
   under a link back to its tab when it's one of the tab's areas. */

.page-head { padding: 8px 0 32px; }
.crumb {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  color: var(--ink-2);
  text-decoration: none;
  font: 500 var(--text-sm)/1.6 var(--font-sans);
  letter-spacing: .02em;
}
.crumb::before { content: "←"; }
.page-title {
  margin: 2px 0 12px;
  font: 400 clamp(42px, 11.5vw, 60px)/1.15 var(--font-display);
  letter-spacing: .03em;
}
.page-lede { max-width: 32em; margin: 0; color: var(--ink-2); }
/* A session (복습, 아는 단어 표시하기) keeps its title small, so the card
   starts near the top of a phone's screen. */
.page-head.is-compact { padding-bottom: 18px; }
.is-compact .page-title { margin: 0 0 4px; font-size: 30px; }
.is-compact .page-lede { font: var(--text-sm)/1.6 var(--font-sans); }

/* A tab's areas, each marked with a relief seal of its first syllable. */

.areas li + li { border-top: 1px solid var(--frame); }
.area {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  color: var(--ink);
  text-decoration: none;
  transition: background-color .2s;
}
.area:active { background: var(--paper-raised); }
.area .seal { width: 38px; height: 38px; rotate: -3deg; }
.area .seal-face { fill: none; stroke: currentColor; stroke-width: 2.4; }
.area .seal-text { fill: currentColor; }
.area-body { display: flex; flex-direction: column; min-width: 0; }
.area-name { font: 700 17px/1.35 var(--font-serif); }
.area-about { color: var(--ink-2); font: 13.5px/1.5 var(--font-sans); }
.phase {
  padding: 3px 7px 2px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  color: var(--ink-2);
  font: 500 var(--text-xs)/1.3 var(--font-sans);
  white-space: nowrap;
}

/* What an unbuilt page will hold, on a plain sheet: the double frame is
   for what there is to do, not for what's still to come. */

.sheet {
  margin: 0;
  padding: 16px 18px;
  list-style: none;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised) var(--grain);
  color: var(--ink-2);
}
.plans li { position: relative; padding-left: 18px; }
.plans li + li { margin-top: 8px; }
.plans li::before {
  content: "";
  position: absolute;
  top: .7em;
  left: 2px;
  width: 6px;
  height: 6px;
  border-radius: 1px;
  background: var(--seal);
  opacity: .75;
}

/* A panel per topic, facts ruled like a ledger: the label in secondary ink,
   the value in ink at the same size, so a row reads across. */

.panel + .panel { margin-top: 44px; }
.panel-note { margin: -4px 0 16px; color: var(--ink-2); font: var(--text-sm)/1.6 var(--font-sans); }
.panel-error { margin: 0 0 16px; color: var(--seal); font: var(--text-sm)/1.5 var(--font-sans); }
.facts { margin: 0 0 18px; border-top: 1px solid var(--rule); }
.facts div {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 4px 16px;
  min-height: 48px;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
}
.facts dt { color: var(--ink-2); font: 15px/1.5 var(--font-sans); }
.facts dd { margin: 0; margin-left: auto; text-align: right; font: 500 15px/1.5 var(--font-sans); font-variant-numeric: tabular-nums; }
.mono, .facts .mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: var(--text-sm); }

/* Numbers worth a glance, as tiles: a label over a big figure, with an
   optional note under it. */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 8px; margin: 0 0 16px; }
.stats > div { min-width: 0; padding: 12px 14px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper-raised); }
.stats dt { color: var(--ink-2); font: 13.5px/1.4 var(--font-sans); }
.stats dd { margin: 4px 0 0; font: 600 24px/1.2 var(--font-sans); font-variant-numeric: tabular-nums; }
.stats .stat-note { margin-top: 2px; color: var(--ink-3); font: var(--text-xs)/1.4 var(--font-sans); }
/* A session's summary: two to a row on the phone. */
.stats.summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Login: one sheet in the plan's double frame, under the app's seal. No
   tab bar, so the sheet sits in the middle of the screen. */

.signin {
  display: grid;
  place-items: center;
  min-height: 100dvh;
  padding: 24px var(--gutter);
}
.login {
  width: 100%;
  max-width: 360px;
  margin: 0;
  padding: 36px 28px 28px;
  background: var(--paper-raised) var(--grain);
  border: 1px solid var(--frame);
  outline: 2px solid var(--frame);
  outline-offset: 3px;
}
.login-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin-bottom: 28px;
}
.login-head .seal { width: 52px; height: 52px; rotate: -4deg; }
.login-title { margin: 0; font: 400 30px/1.2 var(--font-display); letter-spacing: .06em; }

.login-field { display: block; margin-bottom: 16px; }
.login-label {
  display: block;
  margin-bottom: 6px;
  color: var(--ink-2);
  font: 500 13px var(--font-sans);
  letter-spacing: .02em;
}
.login-field input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: var(--paper);
  color: var(--ink);
  font: 17px/1.4 var(--font-serif);
}
.login-field input:focus { border-color: var(--ink-2); }

.login-error { margin: 0 0 14px; color: var(--seal); font: 14px/1.5 var(--font-sans); text-align: center; }
.login-submit { width: 100%; margin-top: 8px; padding: 15px 20px; font-size: 17px; }
.login-submit:disabled { cursor: wait; }
.login-note { margin: 20px 0 0; color: var(--ink-2); font: 13px/1.5 var(--font-sans); text-align: center; }

/* 어휘: the word bank. Filters are small ink chips; each word is a ruled row
   with its status as a seal-ink tag. */

/* The filters, one labelled row each. On the phone a row that doesn't fit
   scrolls sideways (fading out at the screen's edge) instead of wrapping,
   so the list starts higher up. */
.bank-tools { display: grid; gap: 12px; margin-bottom: 16px; }
.filters { display: grid; gap: 8px; }
.filter { display: grid; grid-template-columns: 2.4em minmax(0, 1fr); align-items: center; gap: 8px; }
.filter-label { color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); letter-spacing: .02em; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.filter .chips {
  flex-wrap: nowrap;
  overflow-x: auto;
  margin-right: calc(-1 * var(--gutter));
  padding-right: var(--gutter);
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(to left, transparent, #000 var(--gutter));
  mask-image: linear-gradient(to left, transparent, #000 var(--gutter));
}
.filter .chips::-webkit-scrollbar { display: none; }
.chip {
  flex: none;
  min-height: 34px;
  padding: 5px 13px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: none;
  color: var(--ink-2);
  font: var(--text-sm)/1.3 var(--font-sans);
  white-space: nowrap;
  cursor: pointer;
  transition: border-color .15s, background-color .15s, color .15s;
}
.chip[aria-pressed="true"] {
  border-color: var(--ink);
  background: color-mix(in srgb, var(--ink) 9%, var(--paper-raised));
  color: var(--ink);
  font-weight: 600;
}

/* Each word a ruled row. Its status is a dot in 진도's colors: hollow for
   new, the lighter pine for learning, pine for known. */
.word-list { margin: 0 0 16px; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.word-row {
  display: grid;
  grid-template-columns: auto auto 1fr;
  grid-template-areas: "head pos status" "gloss gloss gloss";
  align-items: baseline;
  gap: 2px 10px;
  padding: 11px 12px 11px 14px;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
  text-decoration: none;
}
.word-row:active { background: var(--paper-raised); }
.word-head { grid-area: head; font: 700 19px/1.3 var(--font-serif); }
.word-pos { grid-area: pos; color: var(--ink-3); font: var(--text-xs) var(--font-sans); }
.word-gloss { grid-area: gloss; overflow: hidden; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); white-space: nowrap; text-overflow: ellipsis; }
.status { grid-area: status; justify-self: end; color: var(--ink-2); font: 500 var(--text-xs) var(--font-sans); white-space: nowrap; }
.status::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 6px; border-radius: 50%; vertical-align: 0; }
.status-new { color: var(--ink-3); }
.status-new::before { box-shadow: inset 0 0 0 1.5px var(--ink-4); }
.status-learning::before { background: var(--learning); }
.status-known { color: var(--pine); }
.status-known::before { background: var(--pine); }
.homograph { margin-left: 1px; color: var(--ink-3); font-size: .55em; font-weight: 400; }

/* A word, in 단어장. */

.senses { margin: 0; padding-left: 1.4em; }
.senses li + li { margin-top: 8px; }
.senses li::marker { color: var(--ink-3); font: var(--text-sm) var(--font-sans); }
.sense-en { display: block; font: 600 var(--text-md)/1.45 var(--font-sans); }
.sense-ko { display: block; color: var(--ink-2); font: 14.5px/1.55 var(--font-serif); }
.examples { margin: 0; padding: 0; list-style: none; }
.examples li + li { margin-top: 16px; }
.example-ko { display: flex; align-items: center; gap: 8px; margin: 0; font: 17px/1.6 var(--font-serif); }
.example-en { margin: 2px 0 0; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
.example-source { margin: 2px 0 0; color: var(--ink-3); font: 12px var(--font-sans); }
.history { margin: 0 0 18px; padding: 0; list-style: none; font: 13.5px/1.5 var(--font-sans); }
.history li { display: flex; flex-wrap: wrap; gap: 4px 10px; padding: 7px 0; border-bottom: 1px dashed var(--rule); }
.history-when { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.history-answer { color: var(--ink-2); }
.result { margin-left: auto; font-weight: 600; }
.result-again { color: var(--seal); }
.result-known, .result-easy { color: var(--pine); }
/* Where a word comes from: a line of small print, not a framed sheet. */
.sources { margin: 0; padding: 0; list-style: none; color: var(--ink-2); font: var(--text-sm)/1.6 var(--font-sans); }
.sources li + li { margin-top: 4px; }

.speak {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--paper-raised);
  color: var(--ink-2);
  cursor: pointer;
  transition: border-color .15s, color .15s;
}
.speak svg { width: 17px; height: 17px; }
.speak.speaking { border-color: var(--seal); color: var(--seal); }

/* A session (단어 복습, 아는 단어 표시하기): what's left and the ways out on
   a line, one card on raised paper, and the answers under it. The answer
   bar sticks above the tab bar, so the buttons stay under the thumb however
   long the card grows once its answer shows. */

.progress-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 8px;
  color: var(--ink-2);
  font: var(--text-sm) var(--font-sans);
  font-variant-numeric: tabular-nums;
}
.flashcard {
  min-height: 240px;
  padding: 22px 20px 24px;
  border: 1px solid var(--frame);
  border-radius: var(--radius);
  background: var(--paper-raised) var(--grain);
  box-shadow: var(--shadow);
}
.card-kind {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 14px;
  color: var(--ink-3);
  font: 600 var(--text-xs) var(--font-sans);
  letter-spacing: .06em;
}
.card-kind::before { content: ""; width: 6px; height: 6px; border-radius: 1px; background: var(--seal); opacity: .8; }
.card-word { display: flex; align-items: center; gap: 14px; margin: 0; font: 400 48px/1.2 var(--font-display); letter-spacing: .02em; }
.card-prompt { margin: 0; font: 600 22px/1.4 var(--font-sans); }
.card-meta { margin: 6px 0 14px; color: var(--ink-2); font: 13.5px var(--font-sans); }
.card-example { margin-top: 16px; padding-top: 12px; border-top: 1px dashed var(--rule); }
[data-reveal] { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--rule); }
.typed .field { min-height: 54px; font: 22px/1.3 var(--font-serif); }
.verdict { display: flex; align-items: center; gap: 6px; margin: 0 0 8px; font: 700 15px var(--font-sans); }
.verdict.is-right { color: var(--pine); }
.verdict.is-right::before { content: "✓"; }
.verdict.is-wrong { color: var(--seal); }
.verdict.is-wrong::before { content: "✕"; }

.answer-bar {
  position: sticky;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 8px calc(-1 * var(--gutter)) 0;
  padding: 10px var(--gutter);
  background: var(--paper) var(--grain);
}
/* A short fade above it (no taller than the gap under the card), so a long
   card slides under it softly. */
.answer-bar::before {
  content: "";
  position: absolute;
  inset: -8px 0 100%;
  background: linear-gradient(color-mix(in srgb, var(--paper) 0%, transparent), var(--paper));
  pointer-events: none;
}
.answer-bar:empty { display: none; }
.answer-bar > .button { flex: 1 1 auto; }
.grades { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; width: 100%; }
.grade {
  display: grid;
  align-content: center;
  gap: 3px;
  min-height: 64px;
  padding: 8px 4px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: border-color .15s, background-color .15s;
}
.grade:active:not(:disabled) { translate: 0 1px; }
.grade:focus-visible { border-color: var(--ink); }
.grade:disabled { cursor: default; }
.grade-label { font: 700 var(--text-md) var(--font-serif); }
.grade-next { color: var(--ink-2); font: 12px var(--font-sans); font-variant-numeric: tabular-nums; }
.grade kbd { display: none; }
.grade-again .grade-label { color: var(--seal); }
.grade-easy .grade-label { color: var(--pine); }

/* A new word's card: its example sentences first, each translation behind a
   번역 보기 link, then (on 단어 보기) the word. */
.intro-example + .intro-example { margin-top: 14px; }
.intro-example .link { min-height: 28px; font-size: 13px; }
.intro-word { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--rule); }
.card-kind + .intro-word { margin-top: 0; padding-top: 0; border-top: 0; }

/* 아는 단어 표시하기: the levels on 어휘, each a link to its sweep with a
   meter of the words already sorted; in the sweep, the two answers under
   the card and the rest of the level below. */

.level-list { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.level-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas: "name grade left" "meter meter meter";
  align-items: baseline;
  gap: 8px 10px;
  padding: 12px 4px 14px;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
  text-decoration: none;
  font: var(--text-sm) var(--font-sans);
}
a.level-row:active { background: var(--paper-raised); }
.level-name { grid-area: name; font: 700 17px/1.3 var(--font-serif); }
.level-grade { grid-area: grade; color: var(--ink-3); font-size: var(--text-xs); }
.level-left { grid-area: left; color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
a.level-row .level-left::after { content: "›"; margin-left: 8px; color: var(--ink-3); font-size: 17px; }
.level-row.is-done .level-left { color: var(--pine); }
.level-row .meter { grid-area: meter; height: 6px; }

.progress-actions { display: flex; gap: 16px; }
[data-card] [data-show] { margin-top: 2px; }
.sweep-bar { display: grid; grid-template-columns: 1fr 1fr; }
.sweep-rest { margin-top: 14px; text-align: center; }
.sweep-confirm { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.sweep-confirm p { flex-basis: 100%; margin: 0 0 4px; color: var(--ink-2); font: var(--text-sm)/1.6 var(--font-sans); }
.sweep-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; }

/* 단어장: the list, and one word from it. On the phone they take turns, the
   word in the list's place with a way back to it, and 이전/다음 in a bar
   that sticks above the tab bar like a session's answers. From 960px they
   sit side by side (below, at the end), each scrolling on its own. */

.bank-count { margin: 0; color: var(--ink-2); font: var(--text-sm) var(--font-sans); font-variant-numeric: tabular-nums; }
.word-row[aria-current] { background: var(--paper-raised); box-shadow: inset 3px 0 var(--seal); }
/* Inside the side pane's scroller, an outline outside the row is cut off. */
.word-row:focus-visible { outline-offset: -2px; }
.word-pick {
  margin: 0;
  padding: 48px 24px;
  border: 1px dashed var(--ink-4);
  border-radius: var(--radius);
  color: var(--ink-2);
  font: var(--text-sm)/1.6 var(--font-sans);
  text-align: center;
}
.word-top { padding: 2px 0 32px; }
.word-title {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 10px;
  font: 400 clamp(42px, 11.5vw, 60px)/1.15 var(--font-display);
  letter-spacing: .03em;
}
.word-about { margin: 0; color: var(--ink-2); }
.word-nav { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; margin-top: 36px; }
.word-position {
  min-width: 6em;
  color: var(--ink-2);
  font: var(--text-sm) var(--font-sans);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

@media (width < 960px) {
  .word-pick { display: none; }
  .bank.has-word :is(.page-head, .bank-tools, .bank-side), .bank:not(.has-word) .word-view { display: none; }
}

/* 읽기: the level to write a new text at, and the texts as ruled rows. In the
   reader, a line per sentence beside its speaker button, every word a button
   that reads as plain text until it's looked up, the questions to answer and
   their grading, and the look-up on raised paper that sticks above the tab
   bar, like a session's answers. */

.write-level { margin-bottom: 16px; }
.panel-note[data-write-note], .panel-error[data-write-note] { margin: 0 0 14px; }
.note-detail { display: block; margin-top: 4px; color: var(--ink-3); font: var(--text-xs)/1.5 var(--font-sans); overflow-wrap: anywhere; }
.text-list { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.text-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
  text-decoration: none;
}
.text-row:active { background: var(--paper-raised); }
.text-row-title { grid-column: 1; font: 700 18px/1.4 var(--font-serif); }
.text-row-about { grid-column: 1; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
/* How it went, at the right: the score (pine once it reaches a level's
   80%), or 채점 전 / 읽음 in quieter ink. */
.text-row-score { grid-column: 2; grid-row: 1 / span 2; align-self: center; color: var(--ink-2); font: 600 var(--text-sm) var(--font-sans); font-variant-numeric: tabular-nums; }
.text-row-score.is-good { color: var(--pine); }
.text-row-score.is-quiet { color: var(--ink-3); font-weight: 400; }

.text-title { font-size: clamp(30px, 8.5vw, 44px); }
.lines { margin: 0 0 44px; padding: 0; list-style: none; }
.line { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 12px; }
.line + .line { margin-top: 14px; }
.line > .speak { margin-top: 2px; }
.line-ko { margin: 0; font: 19px/1.9 var(--font-serif); }
.line-speaker { margin-right: 8px; color: var(--ink-2); font: 700 var(--text-sm) var(--font-sans); }
.line-en { margin: 0; color: var(--ink-2); font: var(--text-sm)/1.55 var(--font-sans); }
.line .link, .questions .link { min-height: 28px; font-size: 13px; }
/* Reading, a text's translations wait until its questions are answered. */
.lines.is-untranslated [data-translation] { display: none; }

.tok {
  margin: 0;
  padding: 0 1px;
  border: 0;
  border-radius: 3px;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}
.tok.is-active { background: color-mix(in srgb, var(--seal) 15%, transparent); box-shadow: inset 0 -2px 0 var(--seal); }

.questions { margin: 0; padding-left: 1.4em; }
.questions li + li { margin-top: 18px; }
.questions li::marker { color: var(--ink-3); font: var(--text-sm) var(--font-sans); }
.question { margin: 0; font: 17px/1.8 var(--font-serif); }
.questions .reply { margin-top: 4px; font: 17px/1.4 var(--font-serif); }
/* Once answered: 내 답 and 답 as labelled lines, and between them the
   teacher's mark: ○ right, △ half right, ✕ wrong, with the note on why. */
.given { display: flex; align-items: baseline; gap: 10px; margin: 4px 0 0; font: 16px/1.6 var(--font-serif); }
.given-label { flex: none; min-width: 2.6em; color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); }
.answer { margin: 0; color: var(--pine); font: 600 16px/1.6 var(--font-serif); }
.verdict { margin: 6px 0 0; font: 700 var(--text-sm) var(--font-sans); }
.verdict::before { display: inline-block; width: 1.4em; font-weight: 400; }
.is-right .verdict { color: var(--pine); }
.is-right .verdict::before { content: "○" / ""; }
.is-partial .verdict { color: var(--ink-2); }
.is-partial .verdict::before { content: "△" / ""; }
.is-wrong .verdict { color: var(--seal); }
.is-wrong .verdict::before { content: "✕" / ""; }
.verdict-note { margin: 2px 0 0 1.4em; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
.panel-note[data-grade-note], .panel-error[data-grade-note] { margin: 16px 0 0; }
.read-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }
.read-actions:not(:has(> :not([hidden]))) { display: none; }

.lookup {
  position: sticky;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 8px);
  z-index: 5;
  max-height: 55vh;
  overflow-y: auto;
  margin-top: 24px;
  padding: 12px 16px 14px;
  border: 1px solid var(--frame);
  border-radius: var(--radius);
  background: var(--paper-raised) var(--grain);
  box-shadow: var(--shadow);
}
.lookup-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.lookup-form { margin: 0; color: var(--ink-2); font: var(--text-sm) var(--font-sans); }
.matches { margin: 0; padding: 0; list-style: none; }
.match + .match { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--rule); }
.match-or { margin: 0 0 2px; color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); }
.match-word { display: flex; align-items: center; gap: 12px; margin: 0; font: 700 24px/1.35 var(--font-serif); }
.match-word a { color: var(--ink); text-decoration: none; }
.match-word a::after { content: "›"; margin-left: 6px; color: var(--ink-3); font: 400 18px var(--font-sans); }
.match-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin: 2px 0 0; color: var(--ink-2); font: var(--text-xs) var(--font-sans); }
.match-gloss { margin: 4px 0 0; font: 600 var(--text-md)/1.45 var(--font-sans); }
.match-gloss.is-missing { font-weight: 400; }
.lookup-note { margin: 10px 0 0; color: var(--ink-2); font: var(--text-xs)/1.5 var(--font-sans); }
.lookup-note:empty { display: none; }

/* 듣기: the speed as chips over the lines; each line veiled until the
   questions are answered, a bar about as long as its sentence beside its
   speaker; the line playing (or next to play) marked with a stroke of seal
   red in the margin; and the player's buttons on a bar that sticks above
   the tab bar, like a session's answers. */

.speeds { margin-bottom: 18px; }
.lines.is-veiled .line-text, .lines.is-veiled [data-translation], .lines:not(.is-veiled) .line-veil { display: none; }
.lines.is-veiled .line + .line { margin-top: 8px; }
.line-veil {
  display: inline-block;
  width: min(100%, calc(var(--len) * .8em));
  height: .65em;
  vertical-align: middle;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 13%, transparent);
  transition: background-color .2s;
}
.line.is-current { position: relative; }
.line.is-current::before {
  content: "";
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: -10px;
  width: 3px;
  border-radius: 2px;
  background: var(--seal);
}
.line.is-current .line-veil { background: color-mix(in srgb, var(--seal) 35%, transparent); }

.player-bar {
  position: sticky;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  z-index: 5;
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 6px;
  margin: 24px calc(-1 * var(--gutter)) 0;
  padding: 10px var(--gutter);
  background: var(--paper) var(--grain);
}
.player-bar::before {
  content: "";
  position: absolute;
  inset: -8px 0 100%;
  background: linear-gradient(color-mix(in srgb, var(--paper) 0%, transparent), var(--paper));
  pointer-events: none;
}
.player-step {
  display: grid;
  place-items: center;
  width: 44px;
  min-height: 46px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
  color: var(--ink);
  cursor: pointer;
  transition: border-color .15s, color .15s;
}
.player-step:active:not(:disabled) { translate: 0 1px; }
.player-step:disabled { border-style: dashed; background: none; color: var(--ink-3); cursor: default; }
.player-step svg { width: 20px; height: 20px; }
.player-play { justify-content: flex-start; gap: 8px; min-width: 0; padding-inline: 12px 14px; }
.player-play [data-play-label] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.player-icon { display: grid; flex: none; }
.player-icon svg { width: 19px; height: 19px; }
.player-icon svg + svg, .is-playing .player-icon svg:first-child { display: none; }
.is-playing .player-icon svg + svg { display: block; }
.player-count { flex: none; margin-left: auto; font: 500 var(--text-sm) var(--font-sans); font-variant-numeric: tabular-nums; opacity: .8; }

/* 쓰기: the prompts as 읽기's texts are, ruled rows. On a prompt, the task
   in the reader's face with its words as small ruled chips (ticked in pine
   once the paragraph used them), the paragraph's field, and then its
   sentences numbered as the questions are: each with the teacher's mark,
   ○ right, △ nearly, ✕ wrong (– not fixed), and the labelled lines of a
   graded answer for the hint, the fix and the correction. The model's
   thinking is folded away under the corrections, in small print. */

.task { margin: 0; font: 18px/1.8 var(--font-serif); }
.task-en { margin: 4px 0 0; color: var(--ink-2); font: var(--text-sm)/1.55 var(--font-sans); }
.task + .link, .task-en + .link { min-height: 28px; font-size: 13px; }
.task-words-title { margin: 16px 0 8px; color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); letter-spacing: .02em; }
.task-words { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.task-words li { display: flex; align-items: baseline; gap: 8px; padding: 4px 10px; border: 1px solid var(--rule); border-radius: var(--radius); background: var(--paper-raised); }
.task-words a { color: var(--ink); font: 700 17px/1.4 var(--font-serif); text-decoration: none; }
.task-word-gloss { color: var(--ink-2); font: var(--text-xs)/1.4 var(--font-sans); }
.task-words li.is-used a::before { content: "✓"; margin-right: 4px; color: var(--pine); font: 700 13px var(--font-sans); }

.field.draft { display: block; min-height: 9em; resize: vertical; font: 17px/1.7 var(--font-serif); }
.draft-count { min-height: 1.5em; margin: 6px 0 0; color: var(--ink-3); font: var(--text-xs)/1.5 var(--font-sans); text-align: right; font-variant-numeric: tabular-nums; }
.draft-count.is-problem { color: var(--seal); text-align: left; }
/* Under the paragraph: the mic that writes what's said (where the browser
   has speech recognition), what it's doing, and the count at the right. */
.draft-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-top: 8px; }
.draft-foot .draft-count { flex: 1 1 auto; margin: 0; }
.mic.dictate { width: 44px; height: 44px; }
.mic.dictate svg { width: 20px; height: 20px; }
.dictate-hint { min-width: 0; margin: 0; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); overflow-wrap: anywhere; }
.panel-note[data-check-note], .panel-error[data-check-note] { margin: 16px 0 0; }
.panel-note[data-note], .panel-error[data-note] { margin: 12px 0 0; }
.panel-note[data-draft-note]:empty { display: none; }

.drafted { margin: 0; padding-left: 1.4em; }
.drafted > li + li { margin-top: 18px; }
.drafted > li::marker { color: var(--ink-3); font: var(--text-sm) var(--font-sans); }
.sentence { margin: 0; font: 17px/1.8 var(--font-serif); }
.drafted .fix { display: block; margin-top: 8px; resize: vertical; font: 17px/1.5 var(--font-serif); }
.hint { color: var(--ink); font: var(--text-sm)/1.6 var(--font-sans); }
.verdict.mark-good { color: var(--pine); }
.verdict.mark-good::before { content: "○" / ""; }
.verdict.mark-minor { color: var(--ink-2); }
.verdict.mark-minor::before { content: "△" / ""; }
.verdict.mark-error { color: var(--seal); }
.verdict.mark-error::before { content: "✕" / ""; }
.verdict.mark-unchanged { color: var(--ink-2); font-weight: 600; }
.verdict.mark-unchanged::before { content: "–" / ""; }

.thinking + .thinking { margin-top: 10px; }
.thinking summary { min-height: 32px; color: var(--ink-2); font: var(--text-sm)/32px var(--font-sans); cursor: pointer; }
.thinking-text {
  max-height: 24em;
  margin: 6px 0 0;
  padding: 12px 14px;
  overflow: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
  color: var(--ink-2);
  font: var(--text-xs)/1.6 ui-monospace, "SF Mono", Menlo, monospace;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* 문법: the patterns are listed as 단어장's words are (문형 목록 shares its
   layout). On a pattern, its name smaller than a word (a pattern runs
   longer), the explanation in the sans face (it's English), how it attaches
   as ruled rows, the mistakes as a graded answer's labelled lines, and
   practice on raised paper: the sentence with a field in its blank,
   underlined like a worksheet's, growing with what's typed. In 문법 복습, the
   same blank on the card, under the pattern's name. */

.panel-note[data-unfilled] { margin: 0 0 16px; }
.word-title.pattern-title { font-size: clamp(30px, 8.5vw, 44px); }
.pattern-gloss { margin: 0 0 4px; font: 600 var(--text-md)/1.45 var(--font-sans); }
.card-pattern { margin: 0; font: 400 clamp(28px, 8vw, 38px)/1.25 var(--font-display); letter-spacing: .02em; }
.flashcard .forms { margin-top: 14px; }
.intro-examples { margin-top: 16px; }
.flashcard .drill-sentence { margin-top: 4px; }

.pattern-meaning { margin: 0; font: 600 var(--text-md)/1.55 var(--font-sans); }
.pattern-use { margin: 10px 0 0; color: var(--ink-2); font: 15px/1.65 var(--font-sans); }
.forms { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.forms li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "after after" "form example";
  align-items: baseline;
  gap: 2px 14px;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule);
}
.form-after { grid-area: after; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
.form-form { grid-area: form; font: 700 18px/1.4 var(--font-serif); }
.form-example { grid-area: example; justify-self: end; color: var(--ink-2); font: 16px/1.5 var(--font-serif); text-align: right; }
.mistakes { margin: 0; padding: 0; list-style: none; }
.mistakes li + li { margin-top: 16px; padding-top: 14px; border-top: 1px dashed var(--rule); }
.mistakes .given-label { min-width: 4.6em; }
.mistake-wrong [lang] { color: var(--seal); }
.mistake-right [lang] { color: var(--pine); font-weight: 600; }
.mistake-why { margin: 4px 0 0; color: var(--ink-2); font: var(--text-sm)/1.55 var(--font-sans); }

.drill {
  padding: 16px 18px 18px;
  border: 1px solid var(--frame);
  border-radius: var(--radius);
  background: var(--paper-raised) var(--grain);
  box-shadow: var(--shadow-sm);
}
.drill-count { margin: 0 0 8px; color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); letter-spacing: .04em; font-variant-numeric: tabular-nums; }
.drill-sentence { margin: 0; font: 19px/2.1 var(--font-serif); }
.blank {
  width: calc(var(--chars, 3) * 1.05em + 20px);
  max-width: 100%;
  margin: 0 2px;
  padding: 0 8px;
  border: 0;
  border-bottom: 2px solid var(--ink-2);
  border-radius: 0;
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  color: var(--ink);
  font: inherit;
  line-height: 1.5;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
.blank:focus { border-bottom-color: var(--seal); }
.blank.is-wrong { border-bottom-color: var(--seal); color: var(--seal); }
.drill-cue { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 6px 0 0; font: 17px/1.5 var(--font-serif); }
.drill-cue-label { color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); }
.drill-en { margin: 4px 0 0; color: var(--ink-2); font: var(--text-sm)/1.55 var(--font-sans); }
.drill-result { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--rule); }
.drill-result:empty { display: none; }
.drill-result .verdict { margin-top: 0; }
.drill-answer { display: flex; align-items: center; gap: 8px; margin: 6px 0 0; font: 18px/1.6 var(--font-serif); }
.drill-answer strong { color: var(--pine); }

/* 퀴즈: a sentence with a gap where the answer goes, and four choices; once
   one is picked, the right one in pine and a wrong pick struck out in seal. */
.gap {
  display: inline-block;
  width: 4em;
  height: 1.3em;
  margin: 0 3px;
  vertical-align: -.25em;
  border-bottom: 2px solid var(--ink-2);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}
.choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 16px 0 0; padding: 0; list-style: none; }
.choice {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 52px;
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
  color: var(--ink);
  font: 18px/1.35 var(--font-serif);
  text-align: left;
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: border-color .15s;
}
.choice:active:not(:disabled) { translate: 0 1px; }
.choice:focus-visible { border-color: var(--ink); }
.choice:disabled { color: var(--ink-2); box-shadow: none; cursor: default; }
.choice-num { flex: none; color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); font-variant-numeric: tabular-nums; }
.choice.is-right { border: 1.5px solid var(--pine); color: var(--pine); font-weight: 700; }
.choice.is-wrong { border: 1.5px solid var(--seal); color: var(--seal); text-decoration: line-through; }
@media (max-width: 359px) { .choices { grid-template-columns: 1fr; } }
.drill-also { margin: 4px 0 0; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
.drill .link { min-height: 28px; font-size: 13px; }
.drill-done { margin: 0; font: 700 18px/1.5 var(--font-serif); }

/* 숫자: the run's settings as rows of chips (the topics wrapping, since
   any of them can be picked), then one number at a time, large, over a wide
   field; the clock beside the count. At the end, each miss with its reading
   to hear, and the records: the place in a square (the first three in seal),
   the day, the score and the time with its penalty. */
.drill-setup { display: grid; gap: 8px; margin-bottom: 16px; }
.filter.is-wrapping { align-items: start; }
.filter.is-wrapping .filter-label { padding-top: 9px; }
.filter.is-wrapping .chips { flex-wrap: wrap; overflow: visible; margin-right: 0; padding-right: 0; -webkit-mask-image: none; mask-image: none; }
.drill-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.drill-actions > .button { flex: 1 1 auto; }
.run-clock { color: var(--ink); font-weight: 600; }
.number-card { display: grid; justify-items: center; align-content: center; gap: 14px; text-align: center; }
.number-card .card-kind { margin: 0; }
.number-shown { margin: 4px 0; font: 400 clamp(30px, 10vw, 52px)/1.2 var(--font-display); letter-spacing: .02em; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.number-listen, .phrase-play { width: 64px; height: 64px; margin: 4px 0; }
.number-listen svg, .phrase-play svg { width: 28px; height: 28px; }
.number-answer { max-width: 22em; min-height: 54px; text-align: center; font: 22px/1.3 var(--font-serif); }
.number-card .drill-also { margin: 0; }
.number-card .drill-also:empty { display: none; }
.stats dd small { color: var(--ink-3); font-size: 15px; font-weight: 500; }
.stat-quiet { color: var(--ink-3); font-weight: 400; }

.misses { margin: 0 0 20px; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.miss { padding: 10px 2px; border-bottom: 1px solid var(--rule); }
.miss p { margin: 0; }
.miss-q { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; font: 18px/1.5 var(--font-serif); }
.miss-shown { font-variant-numeric: tabular-nums; }
.miss-reading { color: var(--pine); font-weight: 700; }
.miss-answer, .miss-given { margin-top: 2px; padding-left: 46px; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
.miss-answer span { color: var(--pine); font-weight: 700; font-variant-numeric: tabular-nums; }
.miss-given span { color: var(--seal); }

.records { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.record {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) auto 5.5em;
  align-items: center;
  gap: 12px;
  min-height: 46px;
  padding: 6px 4px;
  border-bottom: 1px solid var(--rule);
  font: var(--text-sm) var(--font-sans);
  font-variant-numeric: tabular-nums;
}
.record.is-new { background: color-mix(in srgb, var(--seal) 8%, var(--paper-raised)); }
.record-rank { display: inline-grid; place-items: center; width: 26px; height: 26px; border: 1px solid var(--rule); border-radius: 3px; color: var(--ink-2); font-weight: 600; }
.record-rank.is-top { border-color: var(--seal); color: var(--seal); }
.record-date { color: var(--ink-2); }
.record-score { font-weight: 600; }
.record-score small { color: var(--ink-3); font-weight: 400; }
.record-time { text-align: right; font-weight: 600; }
.records-empty { padding: 12px 4px; border-bottom: 1px solid var(--rule); color: var(--ink-3); font: var(--text-sm) var(--font-sans); }

/* 생활 표현: a run's card asks one phrase, heard (a large speaker in the
   middle) or by its English to type or say. The mic is a round button that
   turns seal red, pulsing, while it listens. Once answered: what the mic
   heard, each try marked, then the phrase large, with the words it didn't
   hear underlined in seal. Below the setup, the whole list, folded by
   situation, each phrase a ruled row with its speaker. */
.chip:disabled { border-style: dashed; color: var(--ink-3); cursor: default; }
.phrase-listen { display: grid; justify-items: center; margin: 6px 0 14px; }
.phrase-note { margin: 6px 0 0; color: var(--ink-2); font: var(--text-sm)/1.55 var(--font-sans); }
.phrase-typed { margin-top: 18px; }
.typed .field.is-wrong { border-color: var(--seal); color: var(--seal); }
.mic-area { display: grid; justify-items: center; gap: 10px; margin: 20px 0 4px; text-align: center; }
.mic {
  display: inline-grid;
  place-items: center;
  width: 72px;
  height: 72px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--paper-raised);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: border-color .15s, color .15s, background-color .15s;
}
.mic svg { width: 30px; height: 30px; }
.mic.is-listening { border-color: var(--seal); background: var(--seal); color: var(--on-seal); animation: listening 1.4s ease-in-out infinite; }
@keyframes listening {
  50% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--seal) 18%, transparent); }
}
.mic-hint { min-height: 1.5em; margin: 0; color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
.phrase-answer { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 6px 0 4px; }
.phrase-ko { font: 400 clamp(26px, 7.5vw, 36px)/1.3 var(--font-display); letter-spacing: .02em; overflow-wrap: anywhere; }
.missed-word {
  color: var(--seal);
  text-decoration: underline wavy color-mix(in srgb, var(--seal) 60%, transparent);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 6px;
}
.phrase-en { margin: 4px 0 0; font: 600 var(--text-md)/1.45 var(--font-sans); }
.register {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 6px 1px;
  border: 1px solid var(--rule);
  border-radius: 3px;
  color: var(--ink-2);
  font: 500 var(--text-xs)/1.3 var(--font-sans);
  letter-spacing: 0;
  vertical-align: .2em;
  white-space: nowrap;
}
.phrase-answer .register { margin-left: 0; }
.tries { margin: 0 0 8px; }
.tries-label { margin: 0 0 2px; color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); letter-spacing: .02em; }
.tries ol { margin: 0; padding: 0; list-style: none; }
.tries li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; padding: 2px 0; font: 17px/1.5 var(--font-serif); }
.try-mark { font: 600 var(--text-xs) var(--font-sans); }
.try-mark.is-right { color: var(--pine); }
.try-mark.is-wrong { color: var(--seal); }

.phrase-group { border-top: 1px solid var(--rule); }
.phrase-group:last-child { border-bottom: 1px solid var(--rule); }
.phrase-group summary {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
  padding: 8px 4px;
  list-style: none;
  cursor: pointer;
}
.phrase-group summary::-webkit-details-marker { display: none; }
.phrase-group summary::after {
  content: "";
  width: 7px;
  height: 7px;
  margin: 0 4px 3px;
  border-right: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3);
  rotate: 45deg;
}
.phrase-group[open] summary::after { margin-bottom: -3px; rotate: -135deg; }
.phrase-group-name { flex: 1; font: 700 var(--text-md)/1.4 var(--font-serif); }
.phrase-group-count { color: var(--ink-3); font: var(--text-sm) var(--font-sans); font-variant-numeric: tabular-nums; }
.phrase-list { margin: 0 0 8px; padding: 0; list-style: none; }
.phrase-row { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 12px; padding: 10px 4px; border-top: 1px dashed var(--rule); }
.phrase-row p { margin: 0; }
.phrase-row-ko { font: 18px/1.5 var(--font-serif); }
.phrase-row-also { color: var(--ink-2); font: var(--text-sm)/1.5 var(--font-sans); }
.phrase-row-en { font: 500 var(--text-sm)/1.5 var(--font-sans); }
.phrase-row-note { margin-top: 2px; color: var(--ink-2); font: 13px/1.5 var(--font-sans); }

/* 말하기: the texts to pick are ruled rows like 읽기's, as buttons. A run's
   card asks one line of the text, large, with the speaker's name before it
   in a dialogue (섀도잉: a bar as long as the line until it's been said),
   its speaker and 번역 보기 under it, and the mic, as 생활 표현's; the
   words the mic didn't hear are underlined in seal. At the end, the text's
   lines as the reader shows them, each with what the mic heard. */
button.text-row {
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--rule);
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
button.text-row:disabled { color: var(--ink-3); cursor: default; }
.more-texts { margin-top: 14px; }
.speak-line { margin: 0; font: 24px/1.7 var(--font-serif); overflow-wrap: anywhere; }
.speak-line .line-veil { width: min(100%, calc(var(--len) * 1em)); }
.speak-line .missed-word { text-underline-offset: 7px; }
.speak-tools { display: flex; align-items: center; gap: 12px; min-height: 34px; margin-top: 10px; }
.speak-tools:empty { display: none; }
.speak-tools .link { min-height: 28px; font-size: 13px; }
.speak-en { margin: 6px 0 0; color: var(--ink-2); font: var(--text-sm)/1.55 var(--font-sans); }
.speak-card [data-reveal] .verdict { margin-bottom: 8px; }
.spoken { margin-bottom: 28px; }
.spoken .line-ko .missed-word { text-underline-offset: 5px; }
.line-heard { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; margin: 0; color: var(--ink-2); font: var(--text-sm)/1.55 var(--font-sans); }
.line-heard [lang="ko"] { color: var(--ink); font: 16px/1.5 var(--font-serif); }

/* 설정's tools, side by side while they fit. */
.tool-links { display: flex; flex-wrap: wrap; gap: 10px; }

/* 설정's speed: a slider across the panel, its ends named under it. */
.speed { margin: 0 0 16px; }
.speed-range { display: block; width: 100%; height: 32px; margin: 0; accent-color: var(--pine); cursor: pointer; }
.speed-ends { display: flex; justify-content: space-between; color: var(--ink-3); font: var(--text-xs)/1.4 var(--font-sans); }

/* 설정's AI: a ruled row a task, its two selects under its name on the
   phone and beside it once they fit, under a head naming the columns. */
.ai-head, .ai-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: center; gap: 8px; }
.ai-head { padding-bottom: 6px; border-bottom: 1px solid var(--rule); color: var(--ink-3); font: 600 var(--text-xs) var(--font-sans); letter-spacing: .02em; }
.ai-head > :first-child { display: none; }
.ai-row { padding: 10px 0; border-bottom: 1px solid var(--rule); }
.ai-task { grid-column: 1 / -1; color: var(--ink-2); font: 15px/1.5 var(--font-sans); }
.ai-row.is-all .ai-task { color: var(--ink); font-weight: 600; }
.ai-hint { display: block; color: var(--ink-3); font: var(--text-xs)/1.5 var(--font-sans); }
@media (min-width: 640px) {
  .ai-head, .ai-row { grid-template-columns: minmax(0, 1fr) 180px 200px; }
  .ai-head > :first-child { display: block; }
  .ai-task { grid-column: auto; }
}

/* A select drawn as a field, its arrow a chevron in the field's quiet ink. */
.field.select {
  min-height: 40px;
  padding: 6px 30px 6px 10px;
  font-size: 15px;
  text-overflow: ellipsis;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%), linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 17px) 52%, calc(100% - 12px) 52%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
}

/* 오디오 클립 (from 설정): each clip a ruled row, its button to hear it
   beside the text, and under the text when it was last sent, 다시 만들기
   and how that went. */
.clip-search { margin-bottom: 4px; }
.clip-list { margin: 16px 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.clip-list:empty { display: none; }
.clip {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 0 12px;
  padding: 10px 4px 6px;
  border-bottom: 1px solid var(--rule);
}
.clip > .speak { grid-row: 1 / span 3; margin-top: 2px; }
.clip-text { margin: 0; font: 18px/1.6 var(--font-serif); overflow-wrap: anywhere; }
.clip-about { display: flex; flex-wrap: wrap; align-items: center; gap: 0 12px; margin: 0; color: var(--ink-3); font: var(--text-xs) var(--font-sans); font-variant-numeric: tabular-nums; }
.clip-about .link { min-height: 30px; font-size: 13px; }
.clip-note { margin: 0 0 4px; color: var(--pine); font: var(--text-sm)/1.5 var(--font-sans); }
.clip-note.is-error, .panel-note.is-error { color: var(--seal); }

/* 진도: the estimated level with its parts (어휘, 문법, 읽기); each part's
   level over a ladder of the six levels, a meter per level (its words or
   patterns confirmed, known and being learned, or its recent reading
   scores) with a tick where the level is reached; stat tiles; and the weeks
   studied as rows of stamps. */

.level { display: flex; align-items: center; gap: 20px; margin-bottom: 14px; }
.level-now { margin: 0; font: 400 52px/1.1 var(--font-display); letter-spacing: .04em; white-space: nowrap; }
.level-next { flex: 1; min-width: 0; }
.level-to { margin: 0 0 8px; font: 600 16px/1.4 var(--font-sans); }
.level-parts { display: flex; gap: 8px 28px; margin: 0; }
.level-parts dt { color: var(--ink-2); font: 13.5px/1.4 var(--font-sans); }
.level-parts dd { margin: 2px 0 0; font: 600 22px/1.2 var(--font-sans); white-space: nowrap; }

.meter { position: relative; display: flex; gap: 2px; height: 10px; border-radius: 3px; background: var(--track); }
.meter-known, .meter-confirmed, .meter-unconfirmed, .meter-learning { flex: none; }
.ladder .meter > span { min-width: 3px; }
/* A word's or pattern's ladder: confirmed by a quiz in solid pine, known but
   not confirmed yet in pine hatched over the learning tint, being learned in
   the tint alone. */
.meter-known, .meter-confirmed { background: var(--pine); }
.meter-unconfirmed { background: repeating-linear-gradient(-45deg, var(--pine) 0 2px, var(--learning) 2px 5px); }
.meter-learning { background: var(--learning); }
.meter > :first-child { border-radius: 3px 0 0 3px; }
.meter > :last-child { border-top-right-radius: 3px; border-bottom-right-radius: 3px; }

.ladder { width: 100%; margin: 0 0 10px; border-collapse: collapse; font: 14px var(--font-sans); }
.ladder th { width: 3em; padding: 8px 12px 8px 0; color: var(--ink-2); font-weight: 500; text-align: left; white-space: nowrap; }
.ladder td { padding: 8px 0; }
.ladder .meter::after, .meter.has-reach::after {
  content: "";
  position: absolute;
  top: -3px;
  bottom: -3px;
  left: calc(80% - 1px);
  width: 2px;
  border-radius: 1px;
  background: var(--ink-2);
}
.ladder .ladder-count { width: 1%; padding-left: 12px; color: var(--ink-2); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ladder .is-reached th, .ladder .is-next th { color: var(--ink); font-weight: 700; }
/* 쓰기's weeks have no level to reach. */
.ladder.no-reach .meter::after { content: none; }

.legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0 0 16px; color: var(--ink-2); font: 13px var(--font-sans); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.key { display: inline-block; width: 12px; height: 8px; border-radius: 2px; }
.key-known, .key-confirmed { background: var(--pine); }
.key-unconfirmed { background: repeating-linear-gradient(-45deg, var(--pine) 0 2px, var(--learning) 2px 5px); }
.key-learning { background: var(--learning); }
.key-reach { width: 2px; height: 14px; border-radius: 1px; background: var(--ink-2); }

.weeks { width: calc(100% + 10px); margin: -5px; border-spacing: 5px; font: 13px var(--font-sans); }
.weeks thead th { color: var(--ink-3); font-weight: 500; text-align: center; }
.weeks tbody th { padding-right: 4px; color: var(--ink-2); font-weight: 500; text-align: left; white-space: nowrap; }
.cell { height: 26px; padding: 0; border: 1px dashed var(--ink-4); border-radius: 3px; }
.cell.is-done { border: 0; background: var(--seal); }
.cell.is-missed { opacity: .6; }
.cell.is-today { border: 1.5px solid var(--ink); }
.cell.is-future { border: 1px solid var(--rule); opacity: .5; }
.weeks-count { padding-left: 4px; color: var(--ink-2); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Hover styles, only for a mouse: on a phone a tapped element would keep
   them until the next tap elsewhere. */
@media (hover: hover) {
  .settings:hover, .tab:hover, .crumb:hover, .link:hover:not(:disabled) { color: var(--ink); }
  .cta:hover { background: var(--seal); color: var(--on-seal); }
  .button:hover:not(:disabled) { background: var(--seal); color: var(--on-seal); }
  .button.quiet:hover:not(:disabled) { border-color: var(--seal); background: none; color: var(--seal); }
  .area:hover, .word-row:hover, a.level-row:hover, .text-row:hover { background: var(--paper-raised); }
  .tok:hover:not(.is-active) { background: color-mix(in srgb, var(--ink) 8%, transparent); }
  .match-word a:hover { color: var(--seal); }
  .chip:hover:not([aria-pressed="true"]) { border-color: var(--ink-3); color: var(--ink); }
  .link-chip:hover { border-color: var(--ink-3); }
  .link-chip a:hover, .link-chip-remove:hover { color: var(--seal); }
  .grade:hover:not(:disabled), .choice:hover:not(:disabled) { border-color: var(--ink); }
  .speak:hover, .mic:hover:not(.is-listening) { border-color: var(--seal); color: var(--seal); }
  .phrase-group summary:hover .phrase-group-name { color: var(--seal); }
  .player-step:hover:not(:disabled) { border-color: var(--seal); color: var(--seal); }
}

@media (min-width: 760px) {
  body { padding-bottom: 0; }
  .masthead { padding-block: 22px; }
  .settings-label { display: inline; }

  .tabs {
    position: static;
    gap: 2px;
    padding: 0;
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border: 0;
  }
  .tab {
    flex: none;
    flex-direction: row;
    gap: 7px;
    height: auto;
    padding: 8px 12px;
    border-radius: 6px;
    font: 400 15px/1.2 var(--font-serif);
  }
  .tab svg { width: 18px; height: 18px; }
  .tab[aria-current]::before { top: auto; bottom: -3px; left: calc(50% - 9px); width: 18px; border-radius: 2px; }

  .page-head { padding: 28px 0 44px; }

  .hero { grid-template-areas: "main scroll" "cta scroll"; gap: 28px 48px; padding: 28px 0 56px; }
  .cta { justify-self: start; min-width: 340px; }
  .scroll-text { font-size: 22px; }

  .step { grid-template-columns: 64px 1fr auto; min-height: 76px; }
  .step-num { font-size: 30px; }
  .step-body { padding: 14px 18px; }
  .step-title { font-size: 18px; }
  .step-time { padding-right: 18px; }
  .stamp { top: calc(50% - 38px); right: 72px; width: 76px; height: 76px; }

  .days { gap: 14px; }
  .link-form { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
  .link-form .panel-error, .link-form-actions { grid-column: 1 / -1; }

  .area { gap: 18px; padding: 16px 20px; }
  .area .seal { width: 42px; height: 42px; }
  .area-name { font-size: 18px; }
  .sheet { padding: 22px 26px; }

  .level-now { font-size: 64px; }
  .stats > div { padding: 14px 16px; }
  .stats dd { font-size: 28px; }
  .stats.summary { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
  .cell { height: 30px; }

  .answer-bar { bottom: env(safe-area-inset-bottom); }
  .player-bar { bottom: env(safe-area-inset-bottom); }
  .lookup { bottom: calc(env(safe-area-inset-bottom) + 16px); }
  .line-ko { font-size: 20px; }
  .speak-line { font-size: 27px; }
  .forms li { grid-template-columns: minmax(8em, 14em) auto minmax(0, 1fr); grid-template-areas: "after form example"; }
  .form-example { justify-self: start; text-align: left; }
  .drill { padding: 22px 26px 24px; }
  .drill-sentence { font-size: 20px; }
  .filter .chips { flex-wrap: wrap; overflow: visible; margin-right: 0; padding-right: 0; -webkit-mask-image: none; mask-image: none; }
  .is-compact .page-title { font-size: 36px; }

  .flashcard { padding: 30px 36px 32px; }
  .card-word { font-size: 60px; }
  .grade kbd { display: block; color: var(--ink-3); font: 11px var(--font-sans); }
}

/* 단어장 side by side: the page fills the window, with the search and the
   filters across the top (the search over the list, the filters over the
   word) and the list's pane and the word's under them, each scrolling on
   its own. */
@media (min-width: 960px) {
  body.is-wide { display: flex; flex-direction: column; height: 100vh; height: 100dvh; }
  .is-wide .masthead { width: 100%; max-width: calc(var(--wide) + 2 * var(--gutter)); }
  .bank {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    width: 100%;
    max-width: calc(var(--wide) + 2 * var(--gutter));
    padding-bottom: 0;
  }
  .bank .page-head { display: flex; align-items: baseline; gap: 16px; padding: 0 0 16px; }
  .bank .page-title { margin: 0; font-size: 30px; }
  .bank-panes {
    display: grid;
    grid-template-columns: minmax(300px, 380px) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    column-gap: 24px;
    flex: 1;
    min-height: 0;
  }
  .bank-tools { grid-column: 1 / -1; grid-template-columns: subgrid; align-items: start; gap: 8px 24px; }
  .bank-tools .field { min-height: 42px; }
  .bank-count { grid-column: 1; }
  .bank-tools .filters {
    grid-column: 2;
    grid-row: 1 / span 2;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 24px;
    padding-left: var(--gutter);
  }
  .bank-tools .filter { display: flex; align-items: flex-start; gap: 8px; }
  .bank-tools .filter:last-child { flex-basis: 100%; }
  .bank-tools .filter-label { flex: none; line-height: 30px; }
  .bank-tools .chips { flex: 1; min-width: 0; }
  .bank-tools .chip { min-height: 30px; padding: 3px 11px; font-size: 13px; }
  .bank-side, .word-view { min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
  .bank-side { padding-bottom: 24px; }
  /* The word keeps a gutter inside its pane, so the bar under it can reach
     the pane's edges as it does the screen's on the phone. */
  .word-view { padding: 0 var(--gutter) 24px; }
  .word-view .crumb { display: none; }
  .word-top { padding-top: 0; }
  .word-title { font-size: 52px; }
  .word-nav { bottom: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .stamp, .mic.is-listening { animation: none; }
  .cta, .button, .area, .chip, .link-chip, .grade, .speak, .mic, .field { transition: none; }
}
