:root {
  --color-bg: #f5f0e8;
  --color-surface: #fefcf7;
  --color-surface-alt: #faf6ec;
  --color-ink: #3d4a3f;
  --color-ink-soft: #5a6a5d;
  --color-ink-muted: #8a948a;
  --color-soft-accent: #e6ecd9;
  --color-soft-accent2: #e2e9d3;
  --color-accent: #c9a85a;
  --color-accent-soft: #f1e6c8;
  --color-yellow: #c9a85a;
  --color-yellow-dark: #b8944d;
  --color-tag-bg: #3d4a3f;
  --color-tag-text: #fefcf7;
  --color-pastel-pink: #e6ecd9;
  --color-pastel-green: #e6ecd9;
  --color-pastel-blue: #e6ecd9;
  --color-chat-ai-bg: #eef1e4;
  --color-chat-ai-text: #3d4a3f;
  --color-chat-user-bg: #ffffff;
  --color-chat-user-text: #3d4a3f;
  --color-border: rgba(61, 74, 63, 0.10);
  --color-border-strong: rgba(61, 74, 63, 0.18);
  --color-overlay: rgba(40, 36, 28, 0.32);
  --color-soft-accent-strong: #4c6b3e;
  --color-on-accent: #ffffff;
  --color-error-fg: #e53e3e;
  --color-error-fg-strong: #c53030;
  --color-error-bg: #fee2e2;
  --color-error-bg-soft: #fef2f2;
  --color-danger-fg: #b91c1c;
  --color-danger-border: rgba(185, 28, 28, 0.3);
  --color-danger-bg-soft: rgba(185, 28, 28, 0.03);
  --color-danger-muted-fg: #b27269;
  --color-danger-muted-border: #e8c7c2;
  --color-warn-fg: #92400e;
  --color-warn-bg: #fef3c7;
  --color-warn-border: #fcd34d;
  --color-badge-contrast-bg: #f4e0e0;
  --color-badge-contrast-fg: #7a3030;
  --color-badge-contrast-border: #e6c2c2;
  --color-success-fg: #5e7a52;
  --color-success-fg-strong: #3d5a32;
  --color-success-dot: #6aab7c;
  --color-code-bg: rgba(60, 70, 60, 0.06);
  --color-glass: rgba(255, 255, 255, 0.72);
  --color-glass-border: rgba(61, 74, 63, 0.12);
  --color-ribbon-a: rgba(230, 236, 217, 0.92);
  --color-ribbon-b: rgba(247, 241, 224, 0.92);
  --color-ribbon-stripe: rgba(61, 74, 63, 0.08);
  --status-wishlist-bg: #e6ecd9;
  --status-wishlist-border: #cfdbb8;
  --status-wishlist-fg: #516148;
  --status-wishlist-dot: #7e9a64;
  --status-reading-bg: #f3e6c7;
  --status-reading-border: #e2d09a;
  --status-reading-fg: #7a6230;
  --status-reading-dot: #c2a25a;
  --status-finished-bg: #dde4ec;
  --status-finished-border: #c4cdda;
  --status-finished-fg: #4f5a68;
  --status-finished-dot: #7e8d9f;
  --status-paused-bg: #eadfe4;
  --status-paused-border: #dcc4ce;
  --status-paused-fg: #6d4f5a;
  --status-paused-dot: #9b7784;
  --font-sans: "PingFang SC", "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;
  --font-serif: "Songti SC", "STSong", "Noto Serif CJK SC", "Source Han Serif SC", "SimSun", serif;
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 36px;
  --space-2xl: 56px;
  --radius-sm: 8px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-pill: 999px;
  --shadow-card: 0 8px 24px rgba(17, 17, 17, 0.07);
  --shadow-panel: 0 20px 56px rgba(17, 17, 17, 0.1);
  --shadow-dialog: 0 32px 80px rgba(17, 17, 17, 0.18);
}

/* ── Dark mode (system-following, option B: no manual toggle) ──
   Overrides only color tokens; spacing/radius/typography stay shared.
   Values are tuned so body text keeps WCAG AA contrast (>= 4.5:1) on
   the dark surfaces. */
@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #181a17;
    --color-surface: #22251f;
    --color-surface-alt: #2a2e26;
    --color-ink: #e9eadf;
    --color-ink-soft: #b9bdae;
    --color-ink-muted: #9aa091;
    --color-soft-accent: #353b2c;
    --color-soft-accent2: #3c4232;
    --color-soft-accent-strong: #b7cf9a;
    --color-accent: #d8bd78;
    --color-accent-soft: #4a4124;
    --color-yellow: #d8bd78;
    --color-yellow-dark: #c2a25a;
    --color-tag-bg: #d8bd78;
    --color-tag-text: #20231c;
    --color-pastel-pink: #353b2c;
    --color-pastel-green: #353b2c;
    --color-pastel-blue: #353b2c;
    --color-chat-ai-bg: #2d3228;
    --color-chat-ai-text: #e9eadf;
    --color-chat-user-bg: #383d31;
    --color-chat-user-text: #f1f2e9;
    --color-border: rgba(233, 234, 223, 0.12);
    --color-border-strong: rgba(233, 234, 223, 0.22);
    --color-overlay: rgba(0, 0, 0, 0.55);
    --color-on-accent: #20231c;
    --color-glass: rgba(34, 37, 31, 0.72);
    --color-glass-border: rgba(233, 234, 223, 0.16);
    --color-code-bg: rgba(233, 234, 223, 0.08);

    --status-wishlist-bg: #313a26;
    --status-wishlist-border: #46552f;
    --status-wishlist-fg: #b8cf95;
    --status-wishlist-dot: #8fae6c;
    --status-reading-bg: #423718;
    --status-reading-border: #5c4d22;
    --status-reading-fg: #e2c277;
    --status-reading-dot: #d0ad5e;
    --status-finished-bg: #2a323d;
    --status-finished-border: #3c4756;
    --status-finished-fg: #aebed4;
    --status-finished-dot: #8ea0b8;
    --status-paused-bg: #3a2c33;
    --status-paused-border: #523c47;
    --status-paused-fg: #d6aebe;
    --status-paused-dot: #b98aa0;

    --color-error-fg: #f08a8a;
    --color-error-fg-strong: #f5a3a3;
    --color-error-bg: #3a2020;
    --color-error-bg-soft: #2e1c1c;
    --color-danger-fg: #f08a8a;
    --color-danger-border: rgba(240, 138, 138, 0.4);
    --color-danger-bg-soft: rgba(240, 138, 138, 0.08);
    --color-danger-muted-fg: #e0a39c;
    --color-danger-muted-border: #6a4843;
    --color-warn-fg: #f0c87a;
    --color-warn-bg: #3a2f17;
    --color-warn-border: #5c4a22;
    --color-badge-contrast-bg: #4a2e2e;
    --color-badge-contrast-fg: #e7b3b3;
    --color-badge-contrast-border: #6a4444;
    --color-success-fg: #9bc488;
    --color-success-fg-strong: #b2d6a0;
    --color-success-dot: #6aab7c;
    --color-ribbon-a: rgba(53, 59, 44, 0.92);
    --color-ribbon-b: rgba(66, 55, 24, 0.55);
    --color-ribbon-stripe: rgba(233, 234, 223, 0.06);

    --shadow-card: 0 8px 24px rgba(0, 0, 0, 0.45);
    --shadow-panel: 0 20px 56px rgba(0, 0, 0, 0.55);
    --shadow-dialog: 0 32px 80px rgba(0, 0, 0, 0.6);
  }
}

/* ── Reduced motion (OPT-018, WCAG 2.1 SC 2.2.2 Level A) ──
   The infinite `chat-dot-pulse` loading animation plays for the entire
   5–30s of an AI response with no pause control — a Level A violation when
   the user has iOS "Reduce Motion" / Android "Remove animations" enabled.
   Collapse all animations and transitions to a near-zero duration. We use
   0.01ms (not 0) so any JS awaiting `transitionend`/`animationend` still
   fires. `animation-iteration-count: 1` stops infinite loops outright. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
}

body {
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.6;
  color: var(--color-ink);
  background: var(--color-bg);
}

body::before {
  display: none;
}

a {
  color: var(--color-ink);
}

button,
input,
select,
textarea {
  font: inherit;
}

.app-shell {
  width: min(1200px, calc(100vw - 32px));
  margin: var(--space-lg) auto calc(var(--space-xl) + env(safe-area-inset-bottom));
}

.hero {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: var(--space-lg);
  padding: var(--space-xl);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel);
}

.eyebrow,
h1,
h2,
h3,
h4 {
  font-family: var(--font-serif);
  color: var(--color-ink);
}

.eyebrow {
  margin: 0 0 var(--space-sm);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

h1 {
  margin: 0;
  font-size: clamp(36px, 8vw, 60px);
  line-height: 1.05;
  font-weight: 900;
  max-width: 12ch;
}

h2 {
  font-size: 28px;
  line-height: 1.15;
  font-weight: 600;
}

h3 {
  font-size: 20px;
  line-height: 1.2;
  font-weight: 700;
}

h4 {
  margin: 0;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 700;
}

.hero-copy,
.section-head p,
.subpanel-head p,
.book-meta,
.book-details,
.book-notes,
.progress-copy,
label span,
.timeline-note,
.chat-config-note,
.helper-text,
.profile-subtitle,
.entry-card-meta,
.entry-card-tags,
.book-grid-author,
.book-grid-meta,
.books-meta-row,
.logs-collapse-indicator,
.search-empty-combined,
.search-empty-section {
  color: var(--color-ink-muted);
}

.hero-copy {
  margin: var(--space-lg) 0 0;
  max-width: 54ch;
}

.hero-panel,
.stack-form,
.dialog-form,
.search-results,
.search-results-section,
.search-book-list,
.search-quote-list,
.book-detail-quotes {
  display: grid;
  gap: 14px;
}

.hero-stat,
.stat-card,
.profile-stat-card {
  padding: var(--space-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}

.hero-stat:nth-child(1),
.stat-card:nth-child(1),
.profile-stat-card:nth-child(1) {
  border-left: 4px solid var(--color-pastel-pink);
}

.hero-stat:nth-child(2),
.stat-card:nth-child(2),
.profile-stat-card:nth-child(2) {
  border-left: 4px solid var(--color-pastel-green);
}

.hero-stat:nth-child(3),
.stat-card:nth-child(3),
.profile-stat-card:nth-child(3) {
  border-left: 4px solid var(--color-pastel-blue);
}

.hero-stat:nth-child(4),
.stat-card:nth-child(4),
.profile-stat-card:nth-child(4) {
  border-left: 4px solid var(--color-yellow);
}

.hero-stat span,
.stat-card strong {
  display: block;
  font-size: clamp(30px, 5vw, 42px);
  line-height: 1.05;
  font-weight: 800;
  color: var(--color-ink);
}

.hero-stat label,
.stat-card span {
  color: var(--color-ink-muted);
}

.layout {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 20px;
  margin-top: 22px;
}

.panel {
  min-width: 0;
  padding: var(--space-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-panel);
}

.books-panel,
.quotes-panel,
.me-panel {
  grid-column: span 12;
}

.session-panel,
.chat-panel {
  grid-column: span 6;
}

.section-head h2,
.subpanel-head h3 {
  margin: 0;
}

.section-head p,
.subpanel-head p {
  margin: 6px 0 0;
}

.row-head,
.toolbar,
.book-card-head,
.quote-card-head,
.quote-photo-tools,
.progress-panel-head,
.dialog-actions,
.chat-panel-header,
.chat-input-inline,
.book-details,
.quote-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.toolbar {
  justify-content: flex-start;
}

.books-search-row {
  margin-top: var(--space-md);
  display: flex;
  align-items: center;
  gap: 10px;
}

.books-search-row input,
.books-search-row select {
  flex: 1;
  margin: 0;
}

.chip-strip,
.tag-filter-strip {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  margin-top: var(--space-md);
  padding-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}

.chip-strip::-webkit-scrollbar,
.tag-filter-strip::-webkit-scrollbar {
  display: none;
}

.filter-chip,
.tag-chip,
.book-tag-chip,
.status-pill,
.quote-kind,
.quote-badge,
.quote-badge-muted,
.book-status-chip,
.entry-type-chip,
.profile-status {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  padding: 7px 12px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  line-height: 1;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.filter-chip {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-ink-muted);
  white-space: nowrap;
  cursor: pointer;
  transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
}

.filter-chip.active {
  background: var(--color-tag-bg);
  color: var(--color-tag-text);
  border-color: var(--color-tag-bg);
}

.tag-chip,
.book-tag-chip {
  background: var(--color-soft-accent2);
  color: var(--color-ink);
  border-color: var(--color-soft-accent2);
}

.quote-tag-picker {
  gap: 8px;
}

.quote-tag-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.tag-chip-pick {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-ink-muted);
  border-radius: var(--radius-pill);
  padding: 7px 12px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
}

.tag-chip-pick--active {
  background: var(--color-tag-bg);
  border-color: var(--color-tag-bg);
  color: var(--color-tag-text);
}

/* Status-specific inactive chip colors */
.filter-chip[data-status-filter="reading"] { color: var(--status-reading-fg); }
.filter-chip[data-status-filter="wishlist"] { color: var(--status-wishlist-fg); }
.filter-chip[data-status-filter="finished"] { color: var(--status-finished-fg); }

/* Status-specific active chip colors */
.filter-chip[data-status-filter="reading"].active {
  background: var(--status-reading-bg);
  color: var(--status-reading-fg);
  border-color: var(--status-reading-border);
}
.filter-chip[data-status-filter="wishlist"].active {
  background: var(--status-wishlist-bg);
  color: var(--status-wishlist-fg);
  border-color: var(--status-wishlist-border);
}
.filter-chip[data-status-filter="finished"].active {
  background: var(--status-finished-bg);
  color: var(--status-finished-fg);
  border-color: var(--status-finished-border);
}

/* Chip dot indicators */
.chip-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-right: 6px;
  flex-shrink: 0;
}
.chip-dot--reading { background: var(--status-reading-dot); }
.chip-dot--wishlist { background: var(--status-wishlist-dot); }
.chip-dot--finished { background: var(--status-finished-dot); }
.chip-dot--paused { background: var(--status-paused-dot); }

/* Book status badge colors via data-status */
.book-status-chip[data-status="reading"] {
  background: var(--status-reading-bg);
  color: var(--status-reading-fg);
  border: 1px solid var(--status-reading-border);
}
.book-status-chip[data-status="wishlist"] {
  background: var(--status-wishlist-bg);
  color: var(--status-wishlist-fg);
  border: 1px solid var(--status-wishlist-border);
}
.book-status-chip[data-status="finished"] {
  background: var(--status-finished-bg);
  color: var(--status-finished-fg);
  border: 1px solid var(--status-finished-border);
}
.book-status-chip[data-status="paused"] {
  background: var(--status-paused-bg);
  color: var(--status-paused-fg);
  border: 1px solid var(--status-paused-border);
}

.book-tag-more {
  background: transparent;
  color: var(--color-ink-muted);
  border-color: var(--color-border);
}

.book-tag-row {
  display: flex;
  gap: 6px;
  overflow: hidden;
  flex-wrap: nowrap;
}

.book-tag-row .book-tag-chip {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.books-meta-row {
  margin-top: 12px;
  font-size: 14px;
}

.input-grid,
.auth-grid,
.stats-grid {
  display: grid;
  gap: 14px;
}

.input-grid,
.auth-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.stats-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.compact-stats,
.profile-card,
.subpanel,
.book-list,
.timeline,
.quote-list,
.logs-list,
.book-detail-dialog-body {
  margin-top: var(--space-md);
}

label {
  display: grid;
  gap: var(--space-sm);
}

label span {
  font-size: 13px;
  font-weight: 700;
}

input,
select,
textarea {
  width: 100%;
  background: var(--color-surface);
  color: var(--color-ink);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 13px 14px;
  font-family: var(--font-sans);
  appearance: none;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-ink);
  box-shadow: 0 0 0 3px rgba(17, 17, 17, 0.1);
}

/* Keyboard focus indicator for all clickable controls (OPT-013,
   WCAG 2.1 SC 2.4.7 Level AA). Buttons and role/anchor controls had zero
   focus style, leaving Tab-key users with no visible focus. `:focus-visible`
   shows the ring for keyboard navigation only, not on mouse click. Uses
   var(--color-ink) so it adapts to dark mode automatically. */
button:focus-visible,
[role="button"]:focus-visible,
a:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 2px;
}

textarea {
  min-height: 96px;
  resize: vertical;
}

.button {
  border: none;
  border-radius: var(--radius-pill);
  padding: 12px 18px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 160ms ease, background 160ms ease, color 160ms ease, border-color 160ms ease, opacity 160ms ease;
}

.button:hover {
  transform: translateY(-1px);
}

.button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

.button-primary {
  background: var(--color-yellow);
  color: var(--color-ink);
}

.button-primary:hover {
  background: var(--color-yellow-dark);
}

.button-accent {
  background: var(--color-ink);
  color: var(--color-surface);
}

.button-ghost {
  background: var(--color-surface);
  color: var(--color-ink);
  border: 1px solid var(--color-border);
}

.button-small {
  padding: 9px 14px;
  font-size: 14px;
}

.button-danger {
  background: var(--color-error-fg);
  color: var(--color-on-accent);
  border: none;
}
.button-danger:hover {
  background: var(--color-error-fg-strong);
}

.delete-confirm-dialog {
  max-width: 340px;
  width: calc(100% - 40px);
}
.delete-confirm-title {
  margin: 0 0 12px;
  font-size: 17px;
}
.delete-confirm-body {
  margin: 0 0 8px;
  font-weight: 600;
}
.delete-confirm-warning {
  margin: 0 0 20px;
  font-size: 13px;
  color: var(--color-error-fg);
  line-height: 1.5;
}

/* Import result dialog (OPT-041) */
.import-result {
  max-width: 320px;
  width: calc(100% - 40px);
  text-align: center;
}
.import-result-title {
  margin: 0 0 4px;
  font-size: 19px;
  color: var(--color-success-fg-strong);
}
.import-result-sub {
  margin: 0 0 14px;
  font-size: 14px;
  color: var(--color-ink-soft);
}
.import-result-list {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  gap: 8px;
  text-align: left;
}
.import-result-list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 14px;
  background: var(--color-soft-accent);
  border: 1px solid var(--color-soft-accent2);
  border-radius: var(--radius-md);
  font-size: 15px;
}
.import-result-count {
  font-weight: 700;
  color: var(--color-ink);
}

.circle-action {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--color-soft-accent2);
  border-radius: 50%;
  background: var(--color-soft-accent);
  color: var(--color-ink);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 1px 2px var(--color-border);
  flex-shrink: 0;
}

.file-button {
  position: relative;
  overflow: hidden;
}

.file-button input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.empty-state {
  padding: 28px;
  background: var(--color-surface-alt);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
}


.filter-select {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-ink);
  font-size: var(--text-sm);
}

.session-stats {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  padding: 8px 12px;
  background: var(--color-surface);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--color-primary);
  margin-bottom: 4px;
}

.book-list,
.timeline,
.quote-list,
.logs-list {
  display: grid;
  gap: 14px;
}

.book-list,
.timeline,
.quote-list {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  grid-auto-rows: max-content;
}

.book-list,
.quote-list {
  align-items: stretch;
}

.book-card,
.timeline-item,
.quote-card,
.log-card,
.subpanel {
  padding: 20px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}

.subpanel {
  margin-top: 18px;
}

.logs-collapsible > summary {
  list-style: none;
  cursor: pointer;
}

.logs-collapsible > summary::-webkit-details-marker {
  display: none;
}

.logs-collapsible[open] .logs-collapse-indicator::before {
  content: "收起";
}

.logs-collapsible:not([open]) .logs-collapse-indicator::before {
  content: "展开";
}

.logs-collapsible .logs-collapse-indicator {
  font-size: 0;
}

.logs-collapsible .toolbar {
  margin-top: 4px;
}

.profile-card {
  padding: 20px 22px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
}

.profile-title {
  font-size: 21px;
  line-height: 1.2;
  font-weight: 700;
  color: var(--color-ink);
}

.profile-subtitle {
  margin-top: 6px;
  font-size: 14px;
  word-break: break-all;
}

.profile-status {
  justify-self: end;
  background: var(--color-pastel-green);
  color: var(--color-ink);
  white-space: nowrap;
}

.profile-stat-card {
  text-align: center;
  padding: 22px 14px 18px;
}

.profile-stat-icon {
  font-size: 24px;
  margin-bottom: 10px;
}

.progress-panel-head {
  font-weight: 700;
}

.profile-progress-track,
.progress-track {
  height: 10px;
  background: rgba(17, 17, 17, 0.08);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.profile-progress-track {
  margin-top: 16px;
}

.profile-progress-fill,
.progress-fill {
  height: 100%;
  width: 0;
  background: var(--color-yellow);
  border-radius: var(--radius-pill);
}

.book-grid-card,
.session-grid-card,
.quote-grid-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}

.book-grid-card,
.quote-grid-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* OPT-027: all three card types anchor their absolutely-positioned `⋯` menu. */
.book-grid-card,
.session-grid-card,
.quote-grid-card {
  position: relative;
}

.session-grid-card {
  align-self: start;
  min-height: max-content;
  overflow: hidden;
}

.session-card-ribbon {
  min-height: 82px;
  /* right padding clears the top-right `⋯` menu button (OPT-027) */
  padding: 14px 48px 14px 14px;
  background:
    linear-gradient(135deg, var(--color-ribbon-a), var(--color-ribbon-b)),
    repeating-linear-gradient(0deg, transparent 0 13px, var(--color-ribbon-stripe) 13px 14px);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  position: relative;
}

.session-card-ribbon::after {
  content: "";
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 12px;
  height: 5px;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--color-ink) 0 28%, rgba(61, 74, 63, 0.16) 28% 100%);
  opacity: 0.42;
}

.session-card-ribbon strong {
  display: block;
  margin-top: 4px;
  color: var(--color-ink);
  font-size: 18px;
  line-height: 1.15;
}

.session-ribbon-label {
  color: var(--color-ink-muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
}

.session-ribbon-duration {
  flex-shrink: 0;
  padding: 5px 9px;
  border-radius: var(--radius-pill);
  background: var(--color-glass);
  border: 1px solid var(--color-glass-border);
  color: var(--color-ink);
  font-size: 12px;
  font-weight: 700;
}

.book-card-cover,
.entry-card-cover {
  position: relative;
  overflow: hidden;
}

.book-card-cover {
  aspect-ratio: 1.18 / 1;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}

.entry-card-cover {
  aspect-ratio: 3 / 1;
}

.book-card-cover {
  background: var(--color-pastel-green);
}

.timeline .entry-card-cover,
.session-grid-card .entry-card-cover {
  background: var(--color-pastel-blue);
}

.quote-grid-card .entry-card-cover {
  background: var(--color-pastel-pink);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}

.book-card-cover img,
.entry-card-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.book-card-cover:not(.has-default-cover) img {
  object-position: center 74%;
}

.book-card-cover.is-landscape-cover:not(.has-default-cover) img {
  object-position: center 74%;
}

.book-cover-fallback,
.entry-cover-fallback {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  padding: 18px;
  text-align: center;
  font-family: var(--font-serif);
  font-size: 36px;
  font-weight: 600;
  color: var(--color-ink);
  letter-spacing: -0.01em;
}

.entry-card-cover .entry-cover-fallback {
  padding: 4px;
  font-size: 16px;
}

.entry-type-chip,
.status-pill,
.quote-kind,
.quote-badge {
  background: var(--color-tag-bg);
  color: var(--color-tag-text);
}

.book-status-chip {
  background: var(--color-surface-alt);
  color: var(--color-ink-muted);
  border: 1px solid var(--color-border);
}

.quote-badge-muted {
  background: var(--color-surface-alt);
  color: var(--color-ink-muted);
  border: 1px solid var(--color-border);
}

.quote-ocr-badge {
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: 700;
  vertical-align: middle;
  background: var(--color-surface-alt);
  color: var(--color-ink-muted);
  border: 1px solid var(--color-border);
}

.quote-ocr-badge--pending {
  background: var(--status-reading-bg);
  color: var(--status-reading-fg);
  border-color: var(--status-reading-border);
}

.quote-ocr-badge--done {
  background: var(--status-finished-bg);
  color: var(--status-finished-fg);
  border-color: var(--status-finished-border);
}

.quote-ocr-badge--failed {
  background: var(--color-badge-contrast-bg);
  color: var(--color-badge-contrast-fg);
  border-color: var(--color-badge-contrast-border);
}

.book-status-chip,
.entry-card-body .entry-type-chip {
  position: static;
  display: inline-block;
  vertical-align: middle;
  font-size: 11px;
  margin-left: 4px;
}

.book-card-cover .book-status-chip {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 1;
  display: inline-flex;
  margin-left: 0;
}

.entry-type-chip-overlay {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 1;
  font-size: 11px;
  padding: 4px 8px;
}

.book-delete-corner {
  position: absolute;
  /* shift by 7px so the 44px button's visual center stays at the old 30px position */
  right: 3px;
  top: 3px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.96);
  color: var(--color-ink);
  cursor: pointer;
  box-shadow: var(--shadow-card);
}

/* Delete button on session/quote cards — same 44×44 tap target as book-delete-corner */
.card-delete-btn {
  position: absolute;
  right: 3px;
  top: 3px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.90);
  color: var(--color-ink);
  cursor: pointer;
  box-shadow: var(--shadow-card);
  opacity: 0;
  transition: opacity 150ms ease;
  font-size: 12px;
  z-index: 2;
}
.entry-card-cover:hover .card-delete-btn,
.entry-card-cover:focus-within .card-delete-btn {
  opacity: 1;
}

/* OPT-027: removed dead .entry-card-actions / .card-action-* rules — session &
   quote cards no longer use inline action buttons; actions moved to the unified
   ⋯ menu and the detail dialogs. */

.book-grid-body,
.entry-card-body {
  padding: 14px;
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}


.book-grid-body h3,
.entry-card-body h3,
.book-card h3,
.quote-card h3 {
  margin: 0;
}

.book-grid-body h3,
.entry-card-body h3 {
  display: -webkit-box;
  overflow: hidden;
  line-clamp: 2;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.book-grid-author,
.book-grid-meta,
.entry-card-meta,
.entry-card-tags,
.entry-card-note,
.book-detail-quote-meta {
  font-size: 14px;
}

/* OPT-026 + OPT-027: the card overflow trigger (horizontal `⋯`) is the single
   unified action entry across book / session / quote cards. Light treatment:
   bare dots by default — but a surface-coloured text-shadow halo keeps them
   legible over both cover images and plain card surfaces (OPT-026). The circular
   chip only materialises on hover / focus / while the menu is open. */
.card-menu-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  width: 30px;
  height: 30px;
  border: 1px solid transparent;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
  color: var(--color-ink);
  text-shadow: 0 0 3px var(--color-surface), 0 0 6px var(--color-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
}

.card-menu-btn:hover,
.card-menu-btn[aria-expanded="true"] {
  background: var(--color-surface);
  border-color: var(--color-border);
  box-shadow: 0 1px 4px rgba(50, 45, 35, 0.18);
  text-shadow: none;
}

.card-menu-btn:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 2px;
}

.card-context-menu {
  position: absolute;
  top: 44px;
  right: 8px;
  z-index: 300;
  list-style: none;
  margin: 0;
  padding: 4px 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 20px rgba(50, 45, 35, 0.14);
  min-width: 110px;
}

.card-context-menu li button {
  display: block;
  width: 100%;
  padding: 9px 16px;
  border: none;
  background: none;
  cursor: pointer;
  text-align: left;
  font-size: 14px;
  color: var(--color-ink);
  font-family: inherit;
}

.card-context-menu li button:hover {
  background: var(--color-bg);
}

.menu-item-danger {
  border-top: 1px solid var(--color-border);
  margin-top: 4px;
  padding-top: 4px;
}

.menu-item-danger button {
  color: var(--color-danger-muted-fg) !important;
}

.entry-card-note {
  color: var(--color-ink);
}

/* OPT-015: the excerpt is the quote card's focal point — give it more size,
   weight, and leading than the surrounding meta/tags so it reads clearly.
   Scoped to the quote card so session cards, book-detail quotes, and timeline
   notes keep their compact 14px treatment. */
.quote-grid-card .entry-card-note {
  font-size: 15px;
  line-height: 1.7;
  font-weight: 500;
  margin: var(--space-xs) 0 var(--space-sm);
}

.entry-card-note-clamp {
  display: -webkit-box;
  line-clamp: 5;
  -webkit-line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.entry-card-tags {
  color: var(--color-ink-muted);
}

.book-grid-author,
.book-grid-meta,
.entry-card-meta,
.entry-card-tags {
  overflow: hidden;
  text-overflow: ellipsis;
}

.book-grid-author,
.book-grid-meta,
.entry-card-meta {
  white-space: nowrap;
}

.search-section-header {
  margin: 0;
  font-size: 15px;
  line-height: 1.4;
  letter-spacing: 0.08em;
  color: var(--color-ink-muted);
}

.subpanel-head {
  margin-bottom: 14px;
}

.book-card {
  display: grid;
  gap: 14px;
}

.status-pill,
.quote-kind,
.quote-badge,
.quote-badge-muted {
  padding: 6px 10px;
}

.quote-content {
  margin: 0;
  padding: 18px 20px;
  border-left: 4px solid var(--color-yellow);
  background: var(--color-surface-alt);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-family: var(--font-serif);
  font-size: 18px;
  line-height: 1.8;
  white-space: pre-wrap;
}

.quote-reflection {
  margin: 0;
}

.book-combobox {
  position: relative;
}

.book-combobox-list {
  position: fixed;
  z-index: 500;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card);
  max-height: 220px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  list-style: none;
  margin: 0;
  padding: 4px 0;
  display: none;
}

.book-combobox-list.is-open {
  display: block;
}

.book-combobox-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--color-ink);
  gap: 8px;
  line-height: 1.4;
}

.book-combobox-item:active,
.book-combobox-item.is-selected {
  background: var(--color-bg);
}

.book-combobox-badge {
  flex-shrink: 0;
  font-size: 0.72rem;
  color: var(--color-ink-muted);
  background: var(--color-bg);
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border);
}

.book-combobox-empty {
  padding: 10px 14px;
  font-size: 0.9rem;
  color: var(--color-ink-muted);
}

.quote-detail-content {
  white-space: pre-wrap;
  line-height: 1.7;
  font-size: var(--text-md);
  color: var(--color-ink);
}

.quote-detail-reflection {
  white-space: pre-wrap;
  line-height: 1.6;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  padding: 12px;
  background: var(--color-surface);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--color-primary);
}

.quote-detail-tags {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.quote-grid-card {
  cursor: pointer;
}

.quote-image-wrap,
.image-preview {
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
}

.quote-image-wrap img,
.image-preview img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}

.ocr-line-selector {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  padding: 0.5rem 0.75rem 0.25rem;
  margin-top: 0.5rem;
  /* 不要在这里加 max-height + overflow：本元素是 .dialog-form（CSS Grid）的
     grid 子项，带 overflow 的 grid 子项会被网格行塌成 ~0 高（offsetHeight=14
     而 scrollHeight=383，内容被裁成一条缝，面板看似消失）。.dialog-form 自身
     已 overflow-y:auto 可滚动，面板按内容自然撑开即可。 */
}

.ocr-line-selector__hint {
  font-size: 0.75rem;
  color: var(--color-ink-light, var(--color-ink));
  opacity: 0.7;
  margin: 0 0 0.4rem;
}

.ocr-line-selector__row {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--color-border);
}

.ocr-line-selector__row:last-child {
  border-bottom: none;
}

/* font-size 16px：iPhone 上输入框 <16px 聚焦会触发缩放，这里保持 16px 避开。
   改用 textarea：长行自动换行并按内容撑高，整句可见，不再被水平裁掉。 */
.ocr-line-selector__input {
  flex: 1;
  min-width: 0;
  width: auto;
  font-size: 16px;
  line-height: 1.4;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm, 4px);
  background: var(--color-bg, #fff);
  color: var(--color-ink);
  font-family: inherit;
  resize: none;
  overflow: hidden;
  white-space: pre-wrap;
  word-break: break-word;
  box-sizing: border-box;
}

.ocr-line-selector__input:focus {
  outline: none;
  border-color: var(--color-danger, #c0392b);
}

.ocr-line-selector__del {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-ink);
  opacity: 0.45;
  font-size: 0.8rem;
  padding: 0.15rem 0.35rem;
  border-radius: var(--radius-sm, 4px);
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ocr-line-selector__del:hover,
.ocr-line-selector__del:focus-visible {
  opacity: 1;
  background: var(--color-danger-bg, #fde8e8);
  color: var(--color-danger, #c0392b);
}

.chat-panel {
  display: flex;
  flex-direction: column;
  min-height: 560px;
  height: min(860px, calc(100vh - 64px));
  height: min(860px, calc(100dvh - 64px));
  overflow: hidden;
}

.chat-panel-header {
  padding-bottom: 12px;
  flex-shrink: 0;
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.chat-panel-header h2 {
  margin: 0;
}

.chat-book-select {
  flex: 1;
}

.chat-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.chat-header-row h2 {
  margin: 0;
}

.icon-btn {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--color-ink-muted);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.icon-btn:hover {
  background: var(--color-bg);
  color: var(--color-ink);
}

.book-picker {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0;
}

.book-picker-input {
  flex: 1;
  padding: 8px 36px 8px 12px;
  font-size: 16px;
  font-family: inherit;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-ink);
  outline: none;
  min-width: 0;
}

.book-picker-input:focus {
  border-color: var(--color-ink-muted);
}

.book-picker-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  border: none;
  background: transparent;
  cursor: pointer;
  font-size: 13px;
  color: var(--color-ink-muted);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.book-picker-clear:hover {
  background: var(--color-border);
  color: var(--color-ink);
}

.book-picker-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 300;
  list-style: none;
  margin: 0;
  padding: 4px 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 6px 24px rgba(50, 45, 35, 0.14);
  max-height: 220px;
  overflow-y: auto;
}

.book-picker-dropdown li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  cursor: pointer;
}

.book-picker-dropdown li:hover {
  background: var(--color-bg);
}

.book-picker-empty {
  cursor: default;
  color: var(--color-ink-muted);
}

.book-picker-empty:hover {
  background: transparent;
}

.chat-book-context {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  width: 100%;
}

.chat-book-context[hidden] {
  display: none;
}

.chat-quote-pin {
  margin-top: 6px;
  padding: 5px 10px;
  border-left: 3px solid var(--color-accent, #a8956e);
  background: var(--color-surface);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: 0.78rem;
  width: 100%;
}

.chat-quote-pin[hidden] {
  display: none;
}

.chat-quote-pin-book {
  color: var(--color-ink-muted);
  font-size: 0.7rem;
  margin-bottom: 2px;
}

.chat-quote-pin-text {
  color: var(--color-ink);
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.chat-quote-pin-text.is-expanded {
  display: block;
  overflow: visible;
  -webkit-line-clamp: unset;
  -webkit-box-orient: unset;
  max-height: none;
}

.chat-quote-pin-toggle {
  background: none;
  border: none;
  padding: 0;
  margin-top: 2px;
  font-size: 0.7rem;
  color: var(--color-ink-soft);
  cursor: pointer;
}

.chat-quote-pin-toggle[hidden] {
  display: none;
}

.chat-book-context strong {
  display: block;
  min-width: 0;
  flex: 1;
  color: var(--color-ink);
  font-size: 13px;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-context-label {
  flex-shrink: 0;
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-ink-soft);
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
}

.chat-context-meta {
  flex-shrink: 0;
  max-width: 44%;
  color: var(--color-ink-soft);
  font-size: 11px;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-context-clear {
  flex-shrink: 0;
  border: 0;
  background: transparent;
  color: var(--color-accent);
  font-size: 11px;
  font-weight: 800;
  cursor: pointer;
  padding: 4px 0;
}

.picker-book-spine {
  width: 6px;
  height: 32px;
  border-radius: 2px;
  background: var(--color-soft-accent);
  flex-shrink: 0;
}

.picker-book-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.picker-book-title {
  font-size: 14px;
  color: var(--color-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.picker-book-author {
  font-size: 12px;
  color: var(--color-ink-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chat-messages-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.chat-messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
  padding-right: 4px;
}

.chat-welcome {
  flex: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.chat-welcome-content {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 8px;
  justify-items: center;
  text-align: center;
  width: min(330px, 82%);
  padding: 16px;
}

.chat-welcome-title {
  color: var(--color-ink);
  font-weight: 800;
  font-size: 15px;
  line-height: 1.4;
}

.chat-welcome-subtitle {
  color: var(--color-ink-soft);
  font-size: 13px;
  line-height: 1.6;
}

.chat-deco {
  position: absolute;
  pointer-events: none;
}

.chat-deco--1 {
  width: 148px; height: 44px;
  background: var(--color-chat-ai-bg);
  top: 12%; left: 6%;
  opacity: 0.85;
  border-radius: 999px 999px 999px 8px;
  transform: rotate(-2deg);
}

.chat-deco--2 {
  width: 108px; height: 38px;
  background: var(--color-soft-accent);
  top: 26%; right: 8%;
  opacity: 0.75;
  border-radius: 999px 999px 8px 999px;
  transform: rotate(2.5deg);
}

.chat-deco--3 {
  width: 172px; height: 48px;
  background: var(--color-chat-ai-bg);
  top: 43%; left: 10%;
  opacity: 0.65;
  border-radius: 999px 999px 999px 8px;
  transform: rotate(-1deg);
}

.chat-deco--4 {
  width: 96px; height: 36px;
  background: var(--color-soft-accent);
  top: 58%; right: 12%;
  opacity: 0.55;
  border-radius: 999px 999px 8px 999px;
  transform: rotate(1.5deg);
}

.chat-deco--5 {
  width: 130px; height: 42px;
  background: var(--color-chat-ai-bg);
  top: 72%; left: 18%;
  opacity: 0.4;
  border-radius: 999px 999px 999px 8px;
  transform: rotate(-1.5deg);
}

.chat-bubble {
  max-width: 82%;
  padding: 10px 14px;
  border-radius: 18px;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}

.chat-bubble-user {
  align-self: flex-end;
  background: var(--color-chat-user-bg);
  color: var(--color-chat-user-text);
  border: 1px solid var(--color-border);
  border-radius: 18px 18px 4px 18px;
}

.chat-bubble-assistant {
  align-self: flex-start;
  background: var(--color-chat-ai-bg);
  color: var(--color-chat-ai-text);
  border-radius: 18px 18px 18px 4px;
}

.chat-bubble-content {
  white-space: normal;
  word-break: break-word;
}

.chat-bubble-content h1,
.chat-bubble-content h2,
.chat-bubble-content h3 {
  font-weight: 600;
  margin: 0.5em 0 0.2em;
  line-height: 1.3;
}

.chat-bubble-content h3 { font-size: 0.95em; }
.chat-bubble-content h2 { font-size: 1em; }
.chat-bubble-content h1 { font-size: 1.05em; }

.chat-bubble-content ul,
.chat-bubble-content ol {
  padding-left: 1.3em;
  margin: 0.3em 0;
}

.chat-bubble-content li { margin: 0.1em 0; }

.chat-bubble-content code {
  background: var(--color-code-bg);
  padding: 1px 5px;
  border-radius: 4px;
  font-family: monospace;
  font-size: 0.875em;
}

.chat-bubble-content pre {
  background: var(--color-code-bg);
  padding: 10px 12px;
  border-radius: 8px;
  overflow-x: auto;
  margin: 0.4em 0;
}

.chat-bubble-content pre code {
  background: none;
  padding: 0;
  font-size: 0.85em;
  white-space: pre;
}

.chat-bubble-actions {
  display: flex;
  gap: 2px;
  margin-top: 2px;
  padding-left: 4px;
}

.chat-action-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--color-ink-muted);
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.15s, background 0.15s;
}

.chat-action-btn:hover {
  opacity: 1;
  background: var(--color-surface);
}

.chat-action-btn:active {
  background: var(--color-border);
}

/* 超时/出错气泡里的「重试」是带文字的按钮，不能沿用 28×28 图标按钮尺寸
   （否则「重试」两字塞不下会竖排成「重／试」且发灰）。覆盖为自适应宽度的文字按钮。 */
.chat-retry-btn {
  width: auto;
  height: auto;
  padding: 5px 14px;
  margin-top: 8px;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
  opacity: 1;
  color: var(--color-danger-fg);
  border: 1px solid var(--color-danger-fg);
  border-radius: var(--radius-sm);
}

.chat-retry-btn:hover {
  opacity: 1;
  background: var(--color-surface);
}

.chat-error {
  background: var(--color-error-bg);
  color: var(--color-danger-fg);
}

.chat-rate-limited {
  background: var(--color-warn-bg);
  color: var(--color-warn-fg);
  border: 1px solid var(--color-warn-border);
}

.chat-bubble-loading::after {
  content: '· · ·';
  display: inline-block;
  letter-spacing: 3px;
  animation: chat-dot-pulse 1.2s ease-in-out infinite;
}

@keyframes chat-dot-pulse {
  0%, 100% { opacity: 0.2; }
  50%       { opacity: 1; }
}

.chat-bubble-system {
  align-self: center;
  max-width: 92%;
  padding: 6px 12px;
  background: transparent;
  color: var(--color-ink-muted);
  font-size: 12px;
  border-radius: var(--radius-pill);
  border: 1px dashed var(--color-border);
  text-align: center;
}

.chat-scroll-btn-row {
  position: absolute;
  bottom: 8px;
  right: 8px;
  z-index: 2;
}

.chat-scroll-btn-row[hidden] {
  display: none;
}

.chat-scroll-btn {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 20px;
  padding: 5px 12px;
  font-size: 13px;
  color: var(--color-ink-secondary);
  cursor: pointer;
  box-shadow: 0 1px 4px rgba(0,0,0,.08);
}

.chat-composer {
  margin-top: 8px;
  padding-top: 8px;
  flex-shrink: 0;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}

.chat-prompt-chips {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 8px;
  scrollbar-width: none;
}

.chat-prompt-chips::-webkit-scrollbar {
  display: none;
}

.chat-prompt-chips button {
  flex: 0 0 auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-bg);
  color: var(--color-ink-soft);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  padding: 7px 11px;
  white-space: nowrap;
}

.chat-prompt-chips button:hover {
  background: var(--color-soft-accent);
  color: var(--color-ink);
}

.auth-tabs {
  display: flex;
  gap: 0;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--color-border);
  width: fit-content;
  margin-bottom: 16px;
}

.auth-tab-btn {
  flex: 1;
  padding: 8px 24px;
  background: var(--color-surface);
  color: var(--color-ink-muted);
  border: none;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 140ms, color 140ms;
}

.auth-tab-btn.active {
  background: var(--color-ink);
  color: var(--color-surface);
}

.auth-form-panel {
  display: none;
}

.auth-form-panel.active {
  display: contents;
}

.chat-input-inline {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.chat-input-inline textarea {
  flex: 1;
  min-height: 34px;
  max-height: 72px;
  padding: 8px 10px;
  font-size: 16px; /* ≥16px prevents iOS Safari auto-zoom on focus */
  line-height: 1.4;
  resize: none;
}

.chat-icon-btn {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-ink);
  border-radius: 12px;
  padding: 9px 10px;
  cursor: pointer;
}

.log-card summary {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  cursor: pointer;
}

.log-card summary strong {
  display: block;
}

.compact-status-select {
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  min-height: 38px;
}

.log-body {
  margin-top: 14px;
}

.log-body p {
  margin: 12px 0 6px;
}

.log-body pre {
  margin: 0;
  padding: 12px;
  border-radius: var(--radius-md);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
}

.log-state-ok {
  color: var(--color-ink);
}

.log-state-error {
  color: var(--color-danger-fg);
}

dialog {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 0;
  width: min(560px, calc(100vw - 24px));
  max-height: calc(100vh - 24px);
  max-height: calc(100dvh - 24px);
  background: var(--color-surface);
  color: var(--color-ink);
  box-shadow: var(--shadow-dialog);
}

dialog::backdrop {
  background: var(--color-overlay);
  backdrop-filter: blur(4px);
}

.dialog-form {
  padding: var(--space-lg);
  max-height: calc(100vh - 24px);
  max-height: calc(100dvh - 24px);
  overflow-y: auto;
  /* OPT-049 ②: never allow horizontal scroll/swipe inside a dialog. */
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

.dialog-actions {
  justify-content: flex-end;
}

/* OPT-027: detail dialogs are the action center — stack their full action set
   vertically with one clear primary, so hierarchy reads at any width instead of
   wrapping into a row of equal-weight blocks. */
.dialog-actions-stack {
  flex-direction: column;
  align-items: stretch;
}

.book-detail-dialog-body {
  /* OPT-049 ②: was `min-width: min(720px, …)`, wider than the dialog's 560px,
     causing the body to overflow horizontally (swipeable left/right). Let it
     follow the dialog width instead. */
  width: 100%;
  min-width: 0;
}

/* OPT-049 ② follow-up (bug-344): .dialog-form / .book-detail-quotes are CSS grids;
   grid items default to `min-width: auto` and refuse to shrink below their content,
   so a long quote/connection line pushed the body wider than the dialog. Combined
   with `overflow-x: hidden` that no longer swiped — it just clipped ("显示不全").
   Letting every grid child shrink makes the text wrap within the dialog width. */
.dialog-form > *,
.book-detail-quotes > *,
.book-detail-quote {
  min-width: 0;
}

.book-detail-intro,
.book-detail-question,
.book-detail-quote-content,
.book-detail-quote-meta,
.book-detail-quote-reflection,
.conn-mini-text,
.connection-side-sub {
  overflow-wrap: anywhere;
}

.book-detail-intro {
  padding: 14px;
  border-radius: var(--radius-md);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  line-height: 1.7;
  white-space: pre-wrap;
}

/* OPT-074: reading dates line under the book detail meta */
.book-detail-dates {
  margin: -4px 0 2px;
  font-size: 0.85rem;
  color: var(--color-ink-muted);
}

.book-detail-question {
  padding: 14px;
  border-radius: var(--radius-md);
  background: var(--color-chat-ai-bg);
  border: 1px solid var(--color-border);
  color: var(--color-ink);
  line-height: 1.75;
  white-space: pre-wrap;
}

.book-detail-quote {
  width: 100%;
  padding: 12px;
  border-radius: var(--radius-md);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  color: inherit;
  cursor: pointer;
  display: grid;
  gap: 6px;
  text-align: left;
}

.book-detail-quote-meta,
.book-detail-quote-reflection {
  color: var(--color-ink-muted);
  font-size: 0.88rem;
}

.book-detail-quote-content,
.book-detail-quote-reflection {
  white-space: pre-wrap;
  line-height: 1.65;
}

.book-detail-quote-reflection {
  margin-top: 8px;
}

.detail-empty-text {
  margin: 0;
  color: var(--color-ink-muted);
  font-size: 0.92rem;
}

.detail-link-btn {
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-ink);
  cursor: pointer;
  font-weight: 700;
  padding: 10px 12px;
  text-align: center;
}

.detail-link-btn:hover {
  background: var(--color-bg);
}

.toast {
  position: fixed;
  right: 20px;
  bottom: calc(20px + env(safe-area-inset-bottom));
  padding: 12px 18px;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 500;
  color: var(--color-ink);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  box-shadow: 0 8px 24px rgba(50, 45, 35, 0.14);
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
  transition: opacity 180ms ease, transform 180ms ease;
  z-index: 1200;
}

.toast.visible {
  opacity: 1;
  transform: translateY(0);
}

.mobile-tabs {
  display: none;
}


.agent-confirm {
  padding: 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}

.is-hidden {
  display: none !important;
}

/* Fallback notice for browsers too old to parse the ES2020 app JS (iOS 12).
   Injected by the ES5 detection script in index.html <head>. CSS parses fine
   on those browsers, so the notice stays on-brand. */
.browser-unsupported {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 99999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--color-bg);
  color: var(--color-ink);
  text-align: center;
  font-family: var(--font-sans);
}
.browser-unsupported-card {
  max-width: 420px;
}
.browser-unsupported-emoji {
  font-size: 44px;
  margin-bottom: 16px;
}
.browser-unsupported h1 {
  font-family: var(--font-serif);
  font-size: 22px;
  margin: 0 0 12px;
}
.browser-unsupported p {
  font-size: 15px;
  line-height: 1.7;
  margin: 0 0 8px;
  color: var(--color-ink-soft);
}
.browser-unsupported p.sub {
  font-size: 14px;
  margin: 0;
  color: var(--color-ink-muted);
}

@media (max-width: 980px) {
  .session-panel,
  .chat-panel {
    grid-column: span 12;
  }

  .stats-grid,
  .auth-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Mobile/touch layout: phones (≤768px) OR any touch device regardless of size.
   `(pointer: coarse)` pulls in touch tablets (iPad) so they get this proven
   bottom-tab layout instead of the mouse-oriented desktop sidebar — iOS Safari
   has repeated dialog/fixed-positioning bugs with the desktop layout. */
@media (max-width: 768px), (pointer: coarse) {
  body {
    background-color: var(--color-bg);
  }

  /* Touch devices have no hover — always show delete buttons */
  .card-delete-btn {
    opacity: 1;
  }

  .desktop-only {
    display: none !important;
  }

  html,
  body {
    height: 100vh;
    height: 100svh;
    overflow: hidden;
  }

  .app-shell {
    width: 100%;
    margin: 0;
    height: 100vh;
    height: 100svh;
    overflow: hidden;
  }

  .layout {
    display: block;
    margin-top: 0;
    padding: 0;
    height: calc(100vh - 72px - env(safe-area-inset-bottom));
    height: calc(100svh - 72px - env(safe-area-inset-bottom));
    overflow: hidden;
  }

  .panel {
    padding: 12px 14px 0;
    border-radius: var(--radius-md);
  }

  .input-grid,
  .auth-grid {
    grid-template-columns: 1fr;
  }

  .stats-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .book-list,
  .timeline,
  .quote-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
  }

  .row-head,
  .book-card-head,
  .quote-card-head,
  .quote-photo-tools,
  .dialog-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .chat-input-inline {
    flex-direction: row;
    align-items: flex-end;
    gap: 8px;
  }

  .chat-input-inline textarea {
    flex: 1;
  }

  .chat-input-inline .button-primary {
    flex-shrink: 0;
    width: auto;
    padding: 10px 18px;
    white-space: nowrap;
  }

  .layout [data-tab-section] {
    display: none;
  }

  .layout [data-tab-section].tab-active {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
  }

  /* Only the card lists scroll; everything above stays fixed */
  .layout [data-tab-section].tab-active .book-list,
  .layout [data-tab-section].tab-active .timeline,
  .layout [data-tab-section].tab-active .quote-list,
  .layout [data-tab-section].tab-active .connections-list {
    flex: 1;
    display: grid;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 16px;
    align-items: start;
    align-content: start;
    grid-auto-rows: max-content;
    margin-top: 10px;
  }

  /* Me panel has no dedicated list — scroll the whole thing */
  .layout [data-tab-section="me"].tab-active {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(20px + env(safe-area-inset-bottom));
  }

  .chat-panel {
    min-height: 0;
    flex: 1;
    overflow: hidden;
    border-radius: var(--radius-lg) var(--radius-lg) var(--radius-md) var(--radius-md);
  }

  .mobile-tabs {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    height: calc(72px + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    box-shadow: 0 -8px 20px rgba(50, 45, 35, 0.06);
  }

  /* Toast must clear the 72px nav bar + safe area */
  .toast {
    bottom: calc(20px + 72px + env(safe-area-inset-bottom));
  }

  .mobile-tab {
    flex: 1;
    border: 0;
    background: transparent;
    color: var(--color-ink-muted);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 6px 0;
  }

  .mobile-tab.active {
    color: var(--color-ink);
  }

  .mobile-tab-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
  }

  .mobile-tab-icon svg {
    fill: none;
    transition: fill 140ms ease;
  }

  .mobile-tab.active .mobile-tab-icon svg {
    fill: var(--color-soft-accent);
  }

  .mobile-tab-label {
    font-size: 11px;
    font-weight: 400;
  }

  .mobile-tab.active .mobile-tab-label {
    font-weight: 600;
  }

  .me-panel .subpanel {
    border-radius: var(--radius-md);
  }

  .profile-stat-card {
    min-height: 136px;
  }

  .profile-card {
    grid-template-columns: 1fr;
    align-items: flex-start;
  }

  .profile-status {
    justify-self: start;
  }

  /* ── Compact mobile headers ── */
  h2 {
    font-size: 18px;
  }

  .section-head,
  .subpanel-head {
    margin-bottom: 0;
  }

  .books-search-row {
    margin-top: 8px;
  }

  /* iOS auto-zooms any input < 16px — keep all inputs at 16px on mobile */
  input,
  select,
  textarea {
    font-size: 16px;
  }

  .books-search-row input,
  .books-search-row select {
    padding: 7px 10px;
  }

  .chip-strip,
  .tag-filter-strip {
    margin-top: 6px;
    padding-bottom: 2px;
  }

  .filter-chip {
    padding: 4px 10px;
    font-size: 11px;
  }

  .books-meta-row {
    margin-top: 4px;
    font-size: 12px;
  }
}

/* ── Connections ─────────────────────────────────── */
.connections-list {
  display: grid;
  gap: var(--space-md);
  margin-top: var(--space-md);
}

.connections-list.empty-state {
  color: var(--color-ink-muted);
  font-size: 0.9rem;
  padding: var(--space-lg) 0;
}

.connection-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.connection-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.conn-card-actions {
  display: flex;
  gap: 2px;
}

.conn-nav-side {
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 0.15s;
  padding: 4px 6px;
  margin: -4px -6px;
}
.conn-nav-side:hover {
  background: var(--color-soft-accent);
}

.connection-kind-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.02em;
}
.connection-kind-badge[data-kind="异曲同工"] { background: var(--status-reading-bg); color: var(--status-reading-fg); }
.connection-kind-badge[data-kind="引用"]     { background: var(--status-wishlist-bg); color: var(--status-wishlist-fg); }
.connection-kind-badge[data-kind="对比"]     { background: var(--color-badge-contrast-bg); color: var(--color-badge-contrast-fg); }
.connection-kind-badge[data-kind="影响"]     { background: var(--status-finished-bg); color: var(--status-finished-fg); }
.connection-kind-badge[data-kind="延伸"]     { background: var(--color-soft-accent); color: var(--color-ink); }

.connection-sides {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: var(--space-sm);
}

.connection-arrow {
  color: var(--color-ink-muted);
  font-size: 1.1rem;
  padding-top: 2px;
  text-align: center;
}

.connection-side-label {
  font-family: var(--font-serif);
  font-size: 0.9rem;
  color: var(--color-ink);
  word-break: break-all;
  line-height: 1.5;
}

.connection-side-sub {
  font-size: 0.78rem;
  color: var(--color-ink-muted);
  margin-top: 2px;
}

.connection-thought {
  font-size: 0.88rem;
  color: var(--color-ink-soft);
  line-height: 1.6;
  border-left: 3px solid var(--color-accent-soft);
  padding-left: var(--space-sm);
}

.connection-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.connection-meta {
  font-size: 0.75rem;
  color: var(--color-ink-muted);
}

.button-icon {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-ink-muted);
  padding: 4px;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
}
.button-icon:hover {
  color: var(--color-ink);
  background: var(--color-surface-alt);
}

/* Connection dialog sides */
.conn-side {
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.conn-side-label {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Mini connection cards inside book/quote detail dialogs */
.book-detail-connections,
.quote-detail-connections {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-top: var(--space-sm);
}

.conn-mini-card {
  width: 100%;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-sm) var(--space-md);
  font-size: 0.85rem;
  color: var(--color-ink-soft);
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
}

button.conn-mini-card {
  cursor: pointer;
  font-family: inherit;
}

button.conn-mini-card:hover {
  background: var(--color-bg);
}

.conn-mini-kind {
  display: inline-flex;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  font-size: 0.72rem;
  font-weight: 500;
  width: fit-content;
}
.conn-mini-kind[data-kind="异曲同工"] { background: var(--status-reading-bg); color: var(--status-reading-fg); }
.conn-mini-kind[data-kind="引用"]     { background: var(--status-wishlist-bg); color: var(--status-wishlist-fg); }
.conn-mini-kind[data-kind="对比"]     { background: var(--color-badge-contrast-bg); color: var(--color-badge-contrast-fg); }
.conn-mini-kind[data-kind="影响"]     { background: var(--status-finished-bg); color: var(--status-finished-fg); }
.conn-mini-kind[data-kind="延伸"]     { background: var(--color-soft-accent); color: var(--color-ink); }

.conn-mini-header {
  display: flex;
  align-items: center;
}

.conn-mini-text {
  color: var(--color-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.conn-mini-thought {
  font-size: 0.78rem;
  color: var(--color-ink-soft);
  line-height: 1.5;
  border-left: 2px solid var(--color-accent-soft);
  padding-left: 6px;
  margin-top: 2px;
}

.conn-mini-nav {
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.conn-mini-nav:hover {
  background: var(--color-soft-accent);
  border-color: var(--color-accent-soft);
}

.quote-conn-badge {
  display: inline-flex;
  align-items: center;
  font-size: 0.75rem;
  color: var(--color-ink-muted);
  margin-left: 4px;
}

/* ── Me panel header & avatar ── */
.me-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}

.me-panel-header h2 {
  margin: 0;
}

.me-avatar-btn {
  position: relative;
  width: 40px;
  height: 40px;
  border: 1.5px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-ink-muted);
  flex-shrink: 0;
}

.me-avatar-btn:hover {
  background: var(--color-bg);
  color: var(--color-ink);
}

.me-avatar-dot {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--color-success-dot);
  border: 2px solid var(--color-surface);
}

/* ── Me drawer ── */
.me-drawer-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 1050;
  background: rgba(50, 45, 35, 0.35);
}

.me-drawer-overlay.is-open {
  display: block;
}

.me-drawer {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1100;
  background: var(--color-surface);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 12px 20px calc(24px + env(safe-area-inset-bottom));
  max-height: 85dvh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  box-shadow: 0 -8px 32px rgba(50, 45, 35, 0.14);
}

.me-drawer.is-open {
  display: block;
}

.me-drawer-handle {
  width: 36px;
  height: 4px;
  border-radius: 2px;
  background: var(--color-border);
  margin: 0 auto 20px;
}

.me-drawer-section {
  border: none;
  padding: 0;
}

.me-drawer-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

.me-drawer-section-head h3 {
  margin: 0;
}

.me-drawer-username {
  font-size: 18px;
  font-weight: 700;
  color: var(--color-ink);
}

.me-drawer-user-meta {
  font-size: 13px;
  color: var(--color-ink-muted);
  margin-top: 3px;
}

.me-drawer-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

/* Settings-row style list for the Me drawer actions. Each row carries a
   title + 1-line description so users know what each button actually does
   (regression: users couldn't tell 导出数据 vs 完整账号导出 apart). */
.me-action-list {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 14px;
  overflow: hidden;
  background: var(--color-surface);
}
.me-action {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--color-border);
}
.me-action:last-child { border-bottom: none; }
.me-action-info {
  flex: 1 1 auto;
  min-width: 0;
}
.me-action-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--color-ink);
  line-height: 1.35;
}
.me-action-desc {
  font-size: 12px;
  color: var(--color-ink-muted);
  margin-top: 4px;
  line-height: 1.55;
}
.me-action-desc code {
  background: var(--color-code-bg);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 11px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.me-action .button-small {
  flex: 0 0 auto;
  align-self: center;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
}
.me-action.me-action--danger {
  background: var(--color-danger-bg-soft);
}

/* Admin-only sections are hidden unless the logged-in user is marked
   is_admin by the backend (controlled via ADMIN_USERNAMES env var). The
   class toggle happens after /api/session resolves. */
.admin-only { display: none; }
body.is-admin .admin-only { display: revert; }

.danger-text {
  color: var(--color-danger-fg);
  border-color: var(--color-danger-border);
}
.danger-text:hover {
  background: var(--color-error-bg-soft);
}

.terms-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
  color: var(--color-ink-muted, #6b7280);
  line-height: 1.5;
  padding: 4px 0;
}
/* Override the global `input { width: 100%; padding: 13px 14px;
   appearance: none; border-radius: ... }` rule that would otherwise turn
   the checkbox into a full-width text-field-looking box and force the
   disclaimer span to wrap one CJK character per line. */
.terms-check input[type="checkbox"] {
  width: 18px;
  height: 18px;
  min-width: 18px;
  padding: 0;
  margin: 1px 0 0;
  border-radius: 4px;
  appearance: auto;
  -webkit-appearance: checkbox;
  background: var(--color-surface);
  flex: 0 0 auto;
}
/* Defeat the global `label span { font-weight: 700 }`; the disclaimer
   should read like body copy, not a form-field label. */
.terms-check span {
  font-weight: 400;
  font-size: 13px;
  flex: 1 1 auto;
  min-width: 0;
}
.terms-check a {
  color: var(--color-soft-accent-strong, #4c6b3e);
  text-decoration: underline;
}

.auth-landing-link {
  font-size: 13px;
  color: var(--color-ink-muted, #6b7280);
  text-decoration: none;
  white-space: nowrap;
}
.auth-landing-link:hover {
  color: var(--color-ink, #3d4a3f);
}

.auth-forgot-link {
  background: none;
  border: none;
  padding: 4px 0 0;
  margin: 0;
  font-size: 13px;
  color: var(--color-ink-muted, #6b7280);
  text-align: center;
  cursor: pointer;
  text-decoration: underline;
}
.auth-forgot-link:hover {
  color: var(--color-ink, #3d4a3f);
}

.plan-summary {
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, rgba(60,70,60,.12));
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 14px;
}
.plan-summary[hidden] { display: none; }

.plan-summary .plan-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.plan-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}
.plan-badge--free {
  background: var(--color-soft-accent);
  color: var(--color-soft-accent-strong);
}
.plan-badge--plus {
  background: var(--color-warn-bg);
  color: var(--color-warn-fg);
}
.plan-summary .plan-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  font-size: 12px;
  color: var(--color-ink-muted, #6b7280);
}
.plan-summary .plan-stats strong {
  display: block;
  color: var(--color-ink, #3d4a3f);
  font-weight: 500;
  margin-bottom: 2px;
}
@media (max-width: 480px) {
  .plan-summary .plan-stats { grid-template-columns: 1fr; }
}

/* ── OPT-003: small phones (≤374px — iPhone SE 1st-gen, small Android) ──
   Tighten the compact mobile layout so 2-col cards don't get cramped.
   Must sit after the max-width:768px block to override it (equal specificity). */
@media (max-width: 374px) {
  .panel {
    padding: 10px 10px 0;
  }

  .book-list,
  .timeline,
  .quote-list {
    gap: 8px;
  }

  .book-grid-body,
  .entry-card-body {
    padding: 10px;
  }

  .book-grid-author,
  .book-grid-meta,
  .entry-card-meta,
  .entry-card-note,
  .book-detail-quote-meta {
    font-size: 13px;
  }

  .filter-chip,
  .tag-chip {
    padding: 6px 10px;
  }

  .profile-stat-card {
    min-height: 110px;
  }
}

/* ── OPT-003: large phones / foldables (431–768px) ──
   Use the extra width — card grids flow to more columns automatically
   (2-up ~431px → 3-up ~560px → 4-up ~720px) instead of a fixed 2 columns. */
@media (min-width: 431px) and (max-width: 768px) {
  .panel {
    padding: 16px 18px 0;
  }

  .book-list,
  .timeline,
  .quote-list {
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 16px;
  }
}

/* The chat book rail is a desktop-only master-detail nav; hidden on mobile. */
.chat-book-rail {
  display: none;
}

/* ── Desktop: adaptive layout — left sidebar nav + fluid content ──
   Gated on `(pointer: fine)` so only mouse-driven large screens get this
   layout. Touch tablets (iPad) fall through to the mobile bottom-tab layout
   above, avoiding iOS Safari's desktop-layout dialog/fixed bugs. */
@media (min-width: 769px) and (pointer: fine) {
  html {
    height: 100vh;
    overflow: hidden;
  }

  /* IMPORTANT: do NOT make <body> a flex container here. The modal <dialog>
     elements are body-level children; with `display:flex` on body, iOS Safari
     lays out the closed dialogs as flex items (ignoring the UA
     `dialog:not([open]){display:none}`), showing all of them at once and
     blocking clicks. Instead the sidebar is position:fixed and .app-shell gets
     a left margin — body stays block-flow so closed dialogs stay hidden. */
  body {
    height: 100vh;
    overflow: hidden;
  }

  body::before {
    display: none;
  }

  /* App content column — fills the space beside the fixed sidebar.
     width:auto overrides the base `.app-shell { width: min(1200px, …) }` so
     the column actually fills 100vw − 84px instead of staying capped. */
  .app-shell {
    width: auto;
    margin: 0 0 0 84px;
    max-width: none;
    height: 100vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--color-bg);
  }

  .hero.desktop-only {
    display: none;
  }

  .desktop-only {
    display: none !important;
  }

  /* Touch-style delete buttons always visible (no hover affordance reliance) */
  .card-delete-btn {
    opacity: 1;
  }

  /* ── Left sidebar nav (the former bottom tab bar, rotated vertical) ──
     position:fixed (not a body flex item) so it never interferes with the
     body-level <dialog> elements; .app-shell reserves 84px via margin-left. */
  .mobile-tabs {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: 84px;
    z-index: 1000;
    padding-top: 18px;
    gap: 2px;
    background: var(--color-surface);
    border-right: 1px solid var(--color-border);
    box-shadow: none;
  }

  .mobile-tab {
    position: relative;
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: var(--color-ink-muted);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 12px 0;
    cursor: pointer;
  }

  .mobile-tab.active {
    color: var(--color-ink);
  }

  /* Active indicator: a short bar on the left edge */
  .mobile-tab.active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 10px;
    bottom: 10px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--color-ink);
  }

  .mobile-tab-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
  }

  .mobile-tab-icon svg {
    fill: none;
    transition: fill 140ms ease;
  }

  .mobile-tab.active .mobile-tab-icon svg {
    fill: var(--color-soft-accent);
  }

  .mobile-tab-label {
    font-size: 11px;
    font-weight: 400;
  }

  .mobile-tab.active .mobile-tab-label {
    font-weight: 600;
  }

  /* ── Main content column — fills the app-shell height beside the nav ── */
  .layout {
    display: block;
    flex: 1;
    min-width: 0;
    min-height: 0;
    margin-top: 0;
    overflow: hidden;
  }

  .layout [data-tab-section] {
    display: none;
  }

  .layout [data-tab-section].tab-active {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
  }

  /* Content panels: cap reading width and center; chat overrides below */
  .panel {
    padding: 22px 28px 0;
    border: none;
    border-radius: 0;
    box-shadow: none;
    max-width: 1100px;
    width: 100%;
    margin: 0 auto;
  }

  /* Fluid card grids — fill the available width, no fixed column count */
  .layout [data-tab-section].tab-active .book-list,
  .layout [data-tab-section].tab-active .timeline,
  .layout [data-tab-section].tab-active .quote-list,
  .layout [data-tab-section].tab-active .connections-list {
    flex: 1;
    display: grid;
    min-height: 0;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
    overflow-y: auto;
    overflow-x: hidden;
    padding-bottom: 24px;
    align-items: start;
    align-content: start;
    grid-auto-rows: max-content;
    margin-top: 14px;
  }

  /* Me tab scrolls as a whole */
  .layout [data-tab-section="me"].tab-active {
    overflow-y: auto;
    padding-bottom: 24px;
  }

  /* Two-up form fields and a responsive stat grid on the wider canvas */
  .input-grid,
  .auth-grid {
    grid-template-columns: 1fr 1fr;
  }

  .stats-grid {
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  }

  .chat-input-inline {
    flex-direction: row;
    align-items: flex-end;
    gap: 8px;
  }

  .chat-input-inline textarea {
    flex: 1;
  }

  .chat-input-inline .button-primary {
    flex-shrink: 0;
    width: auto;
    padding: 10px 18px;
    white-space: nowrap;
  }

  /* ── 探讨 master-detail: book rail (left) + conversation (right) ──
     Selector must out-specify `.layout [data-tab-section].tab-active`
     (0,3,0) which sets display:flex — so we qualify with .chat-panel too. */
  .layout [data-tab-section].chat-panel.tab-active {
    display: grid;
    grid-template-columns: 220px 1fr;
    grid-template-rows: auto 1fr auto;
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
  }

  .chat-book-rail {
    grid-column: 1;
    grid-row: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-height: 0;
    overflow-y: auto;
    padding: 18px 10px;
    border-right: 1px solid var(--color-border);
  }

  .chat-rail-head {
    font-size: 12px;
    font-weight: 600;
    color: var(--color-ink-muted);
    padding: 0 12px 10px;
  }

  .chat-rail-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: 100%;
    padding: 10px 12px;
    border: 1px solid transparent;
    border-radius: 10px;
    background: transparent;
    color: var(--color-ink);
    text-align: left;
    cursor: pointer;
  }

  .chat-rail-item:hover {
    background: var(--color-soft-accent);
  }

  .chat-rail-item.active {
    background: var(--color-soft-accent);
    border-color: var(--color-border);
  }

  .chat-rail-title {
    font-size: 13px;
    font-weight: 600;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .chat-rail-author {
    font-size: 11px;
    color: var(--color-ink-muted);
  }

  .chat-rail-empty {
    font-size: 12px;
    color: var(--color-ink-muted);
    padding: 8px 12px;
  }

  /* The text-input book picker is redundant on desktop — the rail replaces it */
  .chat-panel .book-picker {
    display: none;
  }

  .chat-panel-header {
    grid-column: 2;
    grid-row: 1;
    padding: 18px 22px 0;
  }

  .chat-messages-wrap {
    grid-column: 2;
    grid-row: 2;
    min-height: 0;
  }

  .chat-composer {
    grid-column: 2;
    grid-row: 3;
  }

  /* Toast bottom-right, clear of the sidebar */
  .toast {
    left: auto;
    right: 24px;
    bottom: 24px;
    transform: none;
  }

  /* ── Me drawer: slide in from the right ── */
  .me-drawer {
    position: fixed;
    top: 0;
    right: 0;
    left: auto;
    bottom: 0;
    width: 360px;
    max-height: none;
    border-radius: var(--radius-lg) 0 0 var(--radius-lg);
    padding: 24px 20px;
    transform: translateX(110%);
    transition: transform 0.28s ease;
  }

  .me-drawer.is-open {
    display: block;
    transform: translateX(0);
  }

  .me-drawer-handle {
    display: none;
  }
}

/* 示例内容横幅:新用户注册即种入示例，顶部提示可一键清除 */
.sample-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 12px;
  padding: 10px 14px;
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-md);
  background: var(--color-accent-soft);
  font-size: 13px;
  color: var(--color-ink);
}

/* display:flex 会压过 [hidden] 的 display:none，必须显式恢复，否则横幅永远显示。 */
.sample-banner[hidden] {
  display: none;
}

.sample-banner-text {
  line-height: 1.4;
}

.sample-banner-clear {
  flex-shrink: 0;
  padding: 5px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-ink);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  cursor: pointer;
}

.sample-banner-clear:hover {
  background: var(--color-border);
}

/* 空状态里的文字链接按钮(如「载入示例看看」) */
.link-btn {
  padding: 0;
  font: inherit;
  color: var(--color-accent);
  background: none;
  border: none;
  text-decoration: underline;
  cursor: pointer;
}
