Files
reader/web/src/styles/notifications.css
T
Kiro Agent 858a7479bf feat(theme): V3.1 semantic tokens, four themes and a reading theme
Implements docs/prototypes/Reader V3 主题语义令牌.md (v3.1):

- 暖陶 (default), 雾蓝, 青绿 app themes plus the reading-only 黑白灰, each
  light and dark. Components read --color-* tokens from
  styles/theme-tokens.css, selected by data-theme + data-mode; the
  TypeScript mirror lives in shared/theme/theme.ts.
- Brand is split per the spec: brand/ch-* only fill (with on-brand/on-ch on
  top), brand-text/ch-*-text for text. --reader-accent/--media-accent are now
  brand text; --reader-fill/--media-fill are brand fills. Selected segmented
  controls use brand-soft + brand-text.
- One preference per server+account (reader.theme.v2): app theme, mode
  (system/light/dark), the follow-system light/dark pair, and the reading
  theme. V3 choices migrate per spec §8 (rose falls back to 暖陶 light).
- 外观与主题 rebuilt from prototype 23: follow-system switch with the
  light/dark pair, app-theme cards with light/dark previews, and the
  reading theme (跟随应用 / 黑白灰).
- Reader: 黑白灰 is set on the reader container only; the appearance panel
  offers 跟随应用/黑白灰 and 明暗; day/night sets the mode; the e-ink preset
  uses 黑白灰 light.
- Video and music players wear the current theme's dark values (§4.7).
- Removed the legacy light/sepia/green/dark palettes and the
  <html data-theme> writes from reader settings, which would now collide
  with data-theme="green".
- Tests: theme-tokens.test.ts keeps CSS and TS values identical and checks
  the §5 contrast pairs for all 8 palettes; theme.test.tsx covers migration,
  resolution, the controller and the settings page.
2026-10-20 04:05:35 +00:00

44 lines
2.3 KiB
CSS

/* Notyf owns the global stack; the app supplies its palette and compact sizing. */
body .notyf {
padding: max(1rem, env(safe-area-inset-top)) max(1rem, env(safe-area-inset-right)) max(1rem, env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left));
gap: .5rem;
font: inherit;
}
.notyf .global-notice {
width: fit-content;
max-width: min(28rem, calc(100vw - 2rem));
max-height: min(16rem, calc(100dvh - 2rem));
overflow: auto;
margin: 0;
padding: .65rem .8rem .65rem 1rem;
border: 1px solid var(--reader-line);
border-radius: .85rem;
color: var(--reader-ink);
box-shadow: 0 6px 24px #00000014;
font-size: .82rem;
text-align: start;
pointer-events: none;
animation-duration: .15s;
}
.global-notice .notyf__wrapper { gap: .65rem; padding: 0; }
.global-notice .notyf__message { min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; animation: none; opacity: 1; }
.global-notice .notyf__dismiss { position: relative; width: 32px; height: 32px; margin: 0; flex: none; animation: none; opacity: 1; }
.global-notice .notyf__dismiss-btn { padding: 0; border-radius: .5rem; color: var(--reader-muted); background: transparent; opacity: 1; pointer-events: auto; }
.global-notice .notyf__dismiss-btn::before, .global-notice .notyf__dismiss-btn::after { background: currentColor; }
.global-notice .notyf__dismiss-btn:hover { background: var(--reader-line); }
.global-notice .notyf__dismiss-btn:focus-visible { outline: 2px solid var(--reader-accent); outline-offset: 2px; }
.global-notice[data-kind='error'] { color: #a32c22; }
[data-mode='dark'] .global-notice[data-kind='error'] { color: #ffaaa0; }
.global-notice[data-kind='success'] { color: #326c46; }
[data-mode='dark'] .global-notice[data-kind='success'] { color: #9dd9ac; }
.global-notice[data-kind='loading'] .notyf__wrapper::before {
content: ''; width: 14px; height: 14px; flex: none; border: 2px solid var(--reader-line);
border-top-color: var(--reader-accent); border-radius: 50%; animation: notice-spin .8s linear infinite;
}
.notyf .notyf__toast--disappear { pointer-events: none; animation-delay: 0s; }
@keyframes notice-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
.notyf .global-notice { animation-duration: .001ms; }
.global-notice[data-kind='loading'] .notyf__wrapper::before { animation: none; }
}