/* Shared page styles. Linked after most pages' own <style>, so these win at equal specificity.

   ══ Component tiers: one hierarchy on every page (和纸 refresh, 2026-10-11) ══
   Height --control-height (44px), radius --radius-control (12px), label weight 500, focus = 2px --accent-focus ring,
   offset 2px. No gradients or shadows on in-flow controls, and never a box inside a box.
   Tier         Class                         Look
   Primary      .btn.btn-primary              apricot fill --color-primary, charcoal --color-on-primary, 1px --color-primary-line.
                                              At most ONE per screen: the main thing to do next.
   Secondary    .btn                          paper fill, 1px --color-line-strong outline (≥3:1), same height and radius.
   Tertiary     .btn.btn-soft                 soft tint fill (--tint-3), no border: utility actions beside a primary.
   Text link    .link-arrow (.btn-quiet)      --color-link at 500, no fill, the label ends in 「→」; underline on hover.
   Chip / tag   .note-chip, .note-tag         sticky-note fill (--note-*); selected = --color-selected + 1px --color-selected-line.
   Input        input, select, textarea       radius --radius-input (12px), 1px --color-line-strong, ≥44px, paper fill, focus ring.
   Disclosure   <details> / toggle rows       label left (ink-2, 500), a +/− in a soft 24px circle after it; full-width rows
                                              (标签筛选, 用文章生成词汇, 看解析, word rows) push it right and sit on hairlines.
   Answer state --color-ok / --color-bad      くすみ sage / dusty rose text and edges on --ok-bg / --bad-bg paper tints,
                                              always with ✓ / ✕ (never colour alone).
*/

/* ── Fonts ──
   Body: the device's own CJK fonts, nothing to download (Google Fonts is blocked in mainland China, and the old
   self-hosted Noto files weighed ~1.2 MB). Japanese gets Japanese glyph forms (直, 今, 骨) from :lang(ja), so every
   Japanese string needs lang="ja". There is no display or handwritten face: page titles, Sandy's lines, tip bubbles,
   buttons, nav and body text all use the system sans, and hierarchy comes only from size, weight and line-height.
   Numbers and English follow the font around them; never give them a font of their own.
   See assets/fonts/README.md. `html body` / `html :lang(ja)` outrank the older page-level font stacks. */
html body { font-family: var(--font-body); }
html :lang(ja) { font-family: var(--font-ja); }

/* The hidden attribute always wins over component display rules */
[hidden] { display: none !important; }

/* ── Typography ── */
/* Tags, chips and pills: medium weight so they sit with the body text instead of shouting */
.tag-chip, .notebook-chip, .category, .category-group-select, .tag-group-select,
.tag, .freq, .grammar-tag, .badge, .answer,
.mobile-tab-btn, .mobile-tab-badge, .sidebar-badge, .tag-summary-pill,
.filter-summary, .category-summary, .tag-summary, .category-count, .tag-count {
  font-weight: 500;
}

/* Chips that show Japanese words: Japanese font first so kana/kanji use Japanese glyphs */
.notebook-chip { font-family: var(--font-ja); }

/* ── Page heading: one style on every page ──
   Eyebrow (「01 学习 · VOCABULARY」) above, the title (system sans 600). Titles carry no decorative dot. */
.page-header { margin: 4px 0 18px; text-align: left; }
.page-eyebrow, .eyebrow { margin: 0 0 4px; color: var(--muted); font-family: var(--font-body); font-size: var(--text-xs); font-weight: 500; letter-spacing: var(--tracking-eyebrow); line-height: 1.6; text-transform: uppercase; }
/* The eyebrow always sits on its own line above the title, also when 「使用说明」 (assets/help.css) turns the header into a
   flex row, so every page's title area stacks the same way (2026-10-12). */
.page-header.has-study-help > :is(.page-eyebrow, .eyebrow) { flex: 1 1 100%; margin-bottom: 0; }
.page-title { margin: 0 0 6px; color: var(--ink); font-family: var(--font-body); font-size: clamp(1.625rem, 4vw, 2rem); font-weight: 600; letter-spacing: .02em; line-height: var(--leading-tight); word-break: normal; line-break: strict; overflow-wrap: anywhere; }
/* Section and card titles: system sans at 500 (never 700) */
.section-title, .card-title { font-family: var(--font-body); font-weight: 500; }
.page-desc { margin: 0; color: var(--muted); font-size: .9rem; line-height: 1.7; }
/* 「No. 001」 item numbers */
.entry-no { color: var(--muted); font-size: var(--text-xs); font-weight: 500; letter-spacing: .04em; font-variant-numeric: tabular-nums; }

/* ── Buttons: flat (tiers above). .btn alone is the secondary outline; primary = soft apricot with charcoal text. ── */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: var(--control-height); padding: 10px 16px; border: 1px solid var(--color-line-strong); border-radius: var(--radius-control); background: var(--surface); color: var(--ink); font: inherit; font-weight: 500; line-height: 1.4; text-decoration: none; cursor: pointer; box-shadow: none; }
.btn:hover { background: var(--tint-1); border-color: var(--ink-2); }
.btn-primary { border-color: var(--color-primary-line); background: var(--color-primary); color: var(--color-on-primary); }
.btn-primary:hover { background: var(--color-primary-hover); border-color: var(--color-primary-line); }
.btn-soft { border-color: transparent; background: var(--tint-3); color: var(--ink); }
.btn-soft:hover { border-color: transparent; background: var(--blue-200); }
.btn-quiet { border-color: transparent; background: transparent; color: var(--color-link); }
.btn-quiet:hover { background: var(--tint-2); border-color: transparent; }
.btn-block { width: 100%; }
.btn:focus-visible { outline: 2px solid var(--accent-focus); outline-offset: 2px; }
/* Text link with an arrow: the quietest action (「去练习 →」, 「在词汇表里学这一类 →」). The arrow is part of the label. */
.link-arrow { display: inline-flex; align-items: center; min-height: var(--control-height); padding: 0 4px; border: 0; background: transparent; color: var(--color-link); font: inherit; font-weight: 500; text-decoration: none; white-space: nowrap; cursor: pointer; }
.link-arrow:hover { text-decoration: underline; text-underline-offset: 4px; }
.link-arrow:focus-visible { outline: 2px solid var(--accent-focus); outline-offset: 2px; border-radius: 6px; }

/* ── Sticky-note chips (付箋): square on the left, round on the right. Fill = one stationery colour.
   Interactive chips are 44px tall; the selected one becomes a pale apricot note with dark brown text and a 1px edge
   (--color-selected / --color-on-selected / --color-selected-line), so it's never marked by colour alone. ── */
.note-chip { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; padding: 8px 14px 8px 12px; border: 0; border-radius: var(--radius-chip); background: var(--note-cream); color: var(--ink-2); font: inherit; font-size: var(--text-sm); font-weight: 500; line-height: 1.3; text-decoration: none; white-space: nowrap; cursor: pointer; }
.note-chip.is-blush { background: var(--note-blush); }
.note-chip.is-sage { background: var(--note-sage); }
.note-chip.is-mist { background: var(--note-mist); }
.note-chip.is-lilac { background: var(--note-lilac); }
.note-chip:hover { color: var(--ink); }
.note-chip:is([aria-pressed="true"], [aria-current], [aria-selected="true"], .is-active) { background: var(--color-selected); color: var(--color-on-selected); box-shadow: inset 0 0 0 1px var(--color-selected-line); }
/* Page chips that use --color-selected get the same 1px edge and weight (an inset shadow, so pages that set
   border-color: transparent still show it, and nothing shifts) */
:is(.category, .category-chip, .category-group-select, .tag-group-select, .scope-chip, .chip-toggle, .topic-chip, .langs button)[aria-pressed="true"],
.contact-kind input:checked + span { box-shadow: inset 0 0 0 1px var(--color-selected-line); font-weight: 500; }
.note-chip:focus-visible { outline: 2px solid var(--accent-focus); outline-offset: 2px; }
/* Small static tags (动词, N2, # 考点): same shape, smaller, not a control */
.note-tag { display: inline-flex; align-items: center; padding: 2px 8px 2px 6px; border-radius: var(--radius-chip-sm); background: var(--note-cream); color: var(--ink-2); font-size: var(--text-xs); font-weight: 500; line-height: 1.6; white-space: nowrap; }
/* Existing page chips take the sticky-note shape too (their colours still come from each page) */
.category, .category-chip, .category-group-select, .tag-group-select, .tag-chip, .notebook-chip { border-radius: var(--radius-chip); }

/* ── Hairline lists: rows divided by thin lines, no card inside a card ──
   .list-head is the count row above a list: a charcoal rule underneath, like a ruled notebook. */
.list-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; padding-bottom: 6px; border-bottom: 1px solid var(--ink); color: var(--muted); font-size: var(--text-xs); letter-spacing: .06em; }
.hairline-list { margin: 0; padding: 0; list-style: none; }
.hairline-list > * { padding: var(--space-5) 0; border-bottom: 1px solid var(--color-line); }
.hairline-list.is-compact > * { padding: var(--space-3) 0; }

/* ── Headword: the Japanese word is the focal point (Japanese sans via :lang(ja), 700, the owner's pick); the reading sits beside it
   in a quiet cocoa brown (--color-reading) with normal spacing ──
   Keep the tap-to-read button on the word itself (the whole .headword can be the button). */
.headword { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin: 2px 0; }
.headword-kanji { color: var(--ink); font-size: var(--text-head); font-weight: 700; letter-spacing: .02em; line-height: 1.25; }
.headword-reading { color: var(--color-reading); font-size: .95rem; font-weight: 400; letter-spacing: normal; }

/* ── Grid paper: for ONE example box per item, not for whole pages ── */
.paper-grid { padding: 10px 14px; border: 1px solid var(--color-line); border-radius: var(--radius-input); background-color: var(--surface); background-image: linear-gradient(var(--grid-line) 1px, transparent 1px), linear-gradient(90deg, var(--grid-line) 1px, transparent 1px); background-size: 12px 12px; color: var(--ink); line-height: 1.8; }
/* A highlighter mark under the word being studied, inside an example */
.mark-word { font-weight: 500; background: linear-gradient(transparent 62%, rgb(227 154 99 / .35) 62%); }
:root[data-page-tone="dark"] .mark-word, :root[data-theme="dark"] .mark-word { background: linear-gradient(transparent 62%, rgb(227 154 99 / .28) 62%); }

/* ── Dialogs and toasts: paper on paper, a hairline and one soft lift ── */
.paper-dialog { padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-dialog); background: var(--surface); color: var(--ink); box-shadow: var(--shadow-float); }
.paper-dialog::backdrop { background: rgb(var(--shadow-rgb) / .28); }
.paper-toast { padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--radius-input); background: var(--surface); color: var(--ink); font-size: var(--text-sm); line-height: 1.7; box-shadow: var(--shadow-float); }

/* Sandy's words (her bubbles on Today and the quizzes, and her tip notes) use the same sans as the nav and buttons, at 400 */
.sandy-speech, .sandy-line, .sandy-note-text { font-family: var(--font-body); font-weight: 400; }

/* Toolbar toggles (语音 / 收藏 / 自动听读): off = paper with outline, on = the selected sticky note (pale apricot,
   dark brown text, 1px edge), same as a selected chip. Never a "disabled" grey. */
.toolbar button.sound-toggle, .toolbar button.favorite-filter, .toolbar button.scroll-toggle, .toolbar button.auto-toggle {
  border: 1px solid var(--color-line-strong); border-radius: var(--radius-control); background: var(--surface); color: var(--ink); box-shadow: none; font-weight: 500;
}
.toolbar button.sound-toggle[aria-pressed="true"], .toolbar button.favorite-filter[aria-pressed="true"],
.toolbar button.scroll-toggle[aria-pressed="true"], .toolbar button.auto-toggle[aria-pressed="true"] {
  border-color: var(--color-selected-line); background: var(--color-selected); color: var(--color-on-selected);
}
/* Toolbars wrap as complete controls; search must never collapse to 20px.
   List-specific phone layouts live in list.css. Tag review has only two actions. */
.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding: var(--space-3); border-radius: var(--radius-card); }
.toolbar > * { min-width: 0; }
.toolbar .search { flex: 1 1 240px; width: auto; min-height: var(--control-height); }
.toolbar .voice-picker { flex: 1 1 200px; justify-content: space-between; }
.toolbar .voice-picker select { min-width: 0; max-width: 180px; min-height: var(--control-height); }
.toolbar > button { min-height: var(--control-height); }
.toolbar:has(.list-toggle) { align-items: stretch; }
.toolbar:has(.list-toggle) .search { flex-basis: calc(100% - 260px); align-self: center; }
.toolbar:has(.list-toggle) .voice-picker { flex: 0 1 240px; align-items: center; flex-wrap: nowrap; }
.toolbar:has(.list-toggle) .voice-picker select { flex: 1 1 100px; max-width: 130px; }
.toolbar:has(.list-toggle) > button { flex: 1 1 0; white-space: normal; }
@media (min-width: 601px) {
  .toolbar:has(.list-toggle) > button { padding: 8px 12px; font-size: .86rem; line-height: 1.5; }
  /* Wide list toolbars (2026-10-12): search on its own row, then the study toggles sized by their labels, then the voice
     controls (语音 on/off + 日语声音) at the end of the row, so the voice name has room instead of five equal boxes. */
  .toolbar:has(.list-toggle) .search { flex: 1 1 100%; }
  .toolbar:has(.list-toggle) > button { flex: 0 1 auto; white-space: nowrap; }
  .toolbar:has(.list-toggle) > .sound-toggle { order: 1; }
  .toolbar:has(.list-toggle) .voice-picker { order: 2; flex: 0 1 auto; gap: var(--space-2); }
  .toolbar:has(.list-toggle) .voice-picker select { flex: 0 1 auto; width: auto; max-width: 240px; }
}
.app-layout .main-toolbar { grid-template-columns: minmax(0, 1fr) auto auto; gap: var(--space-2); padding: var(--space-3); }
.app-layout .search, .app-layout .tag-toggle-btn, .app-layout .action-btn { min-height: var(--control-height); }

/* Common panel rhythm; quiz and review keep their own content, not new spacing rules. */
.app .list, .app-layout .list { gap: var(--space-3); }
.app .card, .app-layout .card { border-radius: var(--radius-card); }
.app #list > .card, .app-layout #list > .card { padding: var(--space-4); gap: var(--space-3); }
.app .card-head, .app-layout .card-head { gap: var(--space-3); }
.app .card-head > *, .app-layout .card-head > * { min-width: 0; }
.app .actions, .app-layout .card-actions { flex-wrap: wrap; gap: var(--space-2); }
.app .actions .action, .app-layout .card-actions .action-btn { min-height: var(--control-height); display: inline-flex; align-items: center; justify-content: center; }
.app #list .card .title, .app-layout #list .card .title { overflow-wrap: anywhere; }
.settings-app .settings-panel { padding: var(--space-5); border-radius: var(--radius-card); }
.settings-app .settings-layout { gap: var(--space-5); }
.settings-app .settings-controls { gap: var(--space-4); }

/* ── Filter panels (标签筛选): label left, summary + chevron together on the right ── */
.category-toggle, .filter-toggle, .tag-toggle { display: flex; align-items: center; gap: 10px; min-height: 48px; }
.app :is(.category-panel, .filter-panel, .tag-panel) { margin-bottom: var(--space-4); }
.app :is(.category-toggle, .filter-toggle, .tag-toggle) { padding: var(--space-3); gap: var(--space-2); }
.category-toggle > span:first-child, .filter-toggle > span:first-child, .tag-toggle > span:first-child { margin-right: auto; }
.category-toggle .chevron, .filter-toggle .chevron, .tag-toggle .chevron { display: inline-grid; place-items: center; width: 24px; height: 24px; font-size: 1.1rem; }

/* ── Inputs: one style. Search, text, select and textarea on study, review and settings pages ── */
html :is(.app, .app-layout, .content-area, .settings-app) :is(input:is([type="search"], [type="text"], [type="email"], [type="password"], [type="url"], :not([type])), select, textarea) {
  min-height: var(--control-height); border: 1px solid var(--color-line-strong); border-radius: var(--radius-input); background-color: var(--surface); color: var(--ink); font: inherit; box-shadow: none;
}
html :is(.app, .app-layout, .content-area, .settings-app) :is(input, select, textarea):focus-visible { outline: 2px solid var(--accent-focus); outline-offset: 2px; box-shadow: none; }
html :is(.app, .app-layout, .content-area, .settings-app) :is(input, textarea)::placeholder { color: var(--muted); opacity: 1; }

/* ── Disclosures: one +/− indicator for every fold ──
   <details> summaries (使用说明, 用文章生成词汇, 看解析, 看答案, word rows) and the toggle buttons (标签筛选) all show the
   same 24px soft circle after the label: + closed, − open. The glyph is --ink-2 on --tint-3 (AA); the label carries the
   name, so the circle is decoration. Native markers and the older ▸ / ⌄ glyphs are hidden. */
:is(.study-help, .reveal, .star-row, .word-row, .feedback, .ai-panel, .disclosure) > summary { list-style: none; }
:is(.study-help, .reveal, .star-row, .word-row, .feedback, .ai-panel, .disclosure) > summary::-webkit-details-marker { display: none; }
html :is(.study-help, .reveal, .star-row, .word-row, .feedback, .ai-panel, .disclosure) > summary::after,
html :is(.category-toggle, .filter-toggle) .chevron::before {
  content: "+"; display: inline-grid; place-items: center; flex: 0 0 auto; width: 24px; height: 24px; margin-left: 8px; border-radius: var(--radius-pill);
  background: var(--tint-3); color: var(--ink-2); font-family: var(--font-body); font-size: 1rem; font-weight: 500; line-height: 1; transform: none;
}
html :is(.study-help, .reveal, .star-row, .word-row, .feedback, .ai-panel, .disclosure)[open] > summary::after,
html :is(.category-toggle, .filter-toggle)[aria-expanded="true"] .chevron::before { content: "\2212"; }
/* the toggle buttons keep their .chevron span for layout; only its circle shows */
html :is(.category-toggle, .filter-toggle) .chevron { display: inline-grid; width: auto; height: auto; font-size: 0; transform: none; transition: none; }
html :is(.category-toggle, .filter-toggle) .chevron::before { margin-left: 0; }
/* full-width rows push the circle to the right edge */
html :is(.feedback, .ai-panel, .disclosure) > summary::after { margin-left: auto; }
/* 收藏 / word rows keep their circle at the right edge, centred on the row */
html :is(.star-row, .word-row) > summary::after { margin-left: 0; transform: translateY(-50%); }
/* in long lists the circle is unfilled (glyph only, --muted) so a column of 200 rows stays quiet; it fills on hover/open */
html :is(.star-row, .word-row):not([open]) > summary:not(:hover)::after { background: transparent; color: var(--muted); }
html .reveal > summary::before, html .ai-chevron { display: none; }
/* labels: ink, not a status or link colour */
html :is(.reveal, .feedback) > summary { color: var(--ink-2); font-weight: 500; }
:is(.study-help, .reveal, .star-row, .word-row, .feedback, .ai-panel, .disclosure) > summary:hover::after,
:is(.category-toggle, .filter-toggle):hover .chevron::before { background: var(--blue-200); }

/* ── Touch targets (≥44px) ── */
.favorite-button { min-width: 44px; min-height: 44px; }
.wrongbook-clear, .wrongbook-link { display: inline-flex; align-items: center; min-height: 44px; padding: 10px 8px; }
.wrongbook-link { margin-left: auto; color: var(--color-link); font-size: .82rem; font-weight: 500; text-decoration: none; white-space: nowrap; }
.wrongbook-link:hover { text-decoration: underline; }
.app .wrongbook { padding: var(--space-4); border-radius: var(--radius-card); }
.app .wrongbook-head { flex-wrap: wrap; gap: var(--space-2); }
.app .wrongbook-head > * { min-width: 0; }
@media (max-width: 600px) {
  .app .wrongbook-head h2 { flex: 1 1 100%; }
  .app .wrongbook-link { flex: 1 1 0; margin-left: 0; white-space: normal; }
  .app .wrongbook-clear { flex: 0 0 auto; }
}

/* ── Phone toolbar on list pages: search, then one row of buttons, then the voice picker ── */
@media (max-width: 600px) {
  .toolbar { display: flex !important; flex-wrap: wrap; gap: 8px; }
  .toolbar .search { flex: 1 1 100%; }
  .toolbar .sound-toggle, .toolbar .favorite-filter, .toolbar .scroll-toggle, .toolbar .auto-toggle, .toolbar .refresh {
    flex: 1 1 0; min-width: 0; min-height: 44px; padding: 6px; font-size: .8rem; line-height: 1.2; white-space: normal; text-wrap: balance;
  }
  .toolbar .voice-picker { order: 1; flex: 1 1 100%; justify-content: space-between; font-size: .78rem; }
  .settings-app .settings-panel { padding: var(--space-4); }
  .app-layout .main-toolbar { grid-template-columns: minmax(0, 1fr); }
  .app .card-head, .app-layout .card-head { flex-wrap: wrap; }
}

/* ── Respect the system "reduce motion" setting everywhere ── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

/* ── Rest moment: empty and finish states (assets/rest-moment.js) ──
   The chosen companion asleep on a faint paper patch, one gentle line, an optional quiet link. Static; no motion. */
.rest-moment { display: grid; justify-items: center; gap: 6px; margin: 8px auto; padding: 20px 16px 16px; max-width: 360px; text-align: center; }
.rest-moment-art { width: 160px; height: auto; aspect-ratio: 560 / 452; object-fit: contain; }
.rest-moment-line { margin: 4px 0 0; color: var(--ink-2); font-size: var(--text-base, 1rem); line-height: 1.7; }
.rest-moment-link { min-height: 44px; display: inline-flex; align-items: center; }
