@xingwangzhe/stalux 1.39.4 → 1.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,9 +18,9 @@ Standalone images written as `![Image description](url)` receive a `figure` and
18
18
 
19
19
  Code blocks default to the single `dark-plus` theme, with system color-scheme switching and theme selectors disabled. To opt into another theme or switching behavior, explicitly override `themes`, `useDarkModeMediaQuery`, and `themeCssSelector` through `expressiveCode`. This only changes generated code styles and adds no telemetry.
20
20
 
21
- Route changes automatically show a 2px accent-colored progress bar at the top of the viewport, with no configuration. Its length follows actual milestones, with slow visual growth toward a bounded ceiling while waiting: loading begins, document/font preparation finishes, the DOM swaps, and page scripts finish; completion waits for the visual transition as well. It only reaches the end when loading and the transition both complete, and does not represent download/time percentages. It handles superseded or canceled navigation, history traversal, and reduced motion without additional requests or telemetry.
21
+ Route changes use native CSS View Transitions for one visible semantic heading in the incoming page. The policy covers every theme route category: normal effects take 100–180ms, with short 100–120ms fades on mobile. Entering an article, returning to a list, filtering categories or tags, explicit previous/next article controls, and returning home receive hints that follow reading intent. History traversal restores the existing scroll position; offscreen headings remain out of view. Reduced motion, browser-provided history gestures and same-page anchors add no visible VT animation. Standalone HTML keeps native navigation. See the [1.40.0 transition policy](https://github.com/xingwangzhe/stalux/blob/v1.40.0/docs/view-transitions-1.40.0.md).
22
22
 
23
- The sticky header stays at the top while the body grows with long content. Route transitions use a 100ms native Web Animations API fade on the new content, with the persisted header and footer stationary. Page-sized View Transition snapshots and geometry interpolation are disabled; Astro still handles document preparation, history, scroll restoration and scripts. Progress and background updates wait for the real content animation to finish. Reduced motion and browser-provided history gestures skip this extra animation. Navigation batches layout reads in one frame and carries the persisted header's measured dimensions across swaps, reducing style recalculation, rasterization and compositing work on mobile devices. Content, lightboxes, search, comments and analytics keep their existing behavior.
23
+ The sticky header stays at the top while the body grows with long content; the persisted header and footer stay in place during navigation. Text is immediately clear, and the incoming heading is measured once after Astro swaps the document and restores scrolling. Astro continues to own document/font preparation, history, scrolling and page-script lifecycle. Shared motion state settles when the native transition finishes or is canceled. CSS animation duration is reported separately from total navigation time, which includes networking, layout and browser settlement.
24
24
 
25
25
  ---
26
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xingwangzhe/stalux",
3
- "version": "1.39.4",
3
+ "version": "1.40.0",
4
4
  "description": "A powerful, modern Astro blog theme — use as template or install as plugin",
5
5
  "keywords": [
6
6
  "astro",
@@ -10,7 +10,7 @@ const { heading, description } = Astro.props;
10
10
  <>
11
11
  <h1
12
12
  class="stalux-page-title stalux-u-text-center"
13
- transition:name="stalux-page-title"
13
+ data-stalux-motion-focus
14
14
  transition:animate="none"
15
15
  >
16
16
  {heading}
@@ -50,7 +50,7 @@ const mdSourceUrl = exportMd ? `${Astro.url.pathname.replace(/\/$/, "")}.md` : "
50
50
  transition:name={`${transitionPrefix}-header`}
51
51
  transition:animate="fade"
52
52
  >
53
- <h1 class="stalux-post-title" transition:name={props.titleTransitionName}>
53
+ <h1 class="stalux-post-title" data-stalux-motion-focus>
54
54
  {props.title}
55
55
  </h1>
56
56
  <div
@@ -24,6 +24,7 @@ const { t } = createTranslator((siteConfig.lang as string) || "zh-CN");
24
24
  {props.prev ? (
25
25
  <a
26
26
  href={props.prev.url}
27
+ data-stalux-motion="previous"
27
28
  class="stalux-pagination-link stalux-pagination-prev-post"
28
29
  rel="prev"
29
30
  data-astro-prefetch
@@ -77,6 +78,7 @@ const { t } = createTranslator((siteConfig.lang as string) || "zh-CN");
77
78
  {props.next ? (
78
79
  <a
79
80
  href={props.next.url}
81
+ data-stalux-motion="next"
80
82
  class="stalux-pagination-link stalux-pagination-next-post"
81
83
  rel="next"
82
84
  data-astro-prefetch
@@ -32,7 +32,7 @@ if (typeKey === "category" || typeKey === "categories" || typeKey === "分类")
32
32
  transition:name="stalux-taxonomy-page-header-shell"
33
33
  transition:animate="none"
34
34
  >
35
- <h1 class="stalux-tag-page-title">
35
+ <h1 class="stalux-tag-page-title" data-stalux-motion-focus>
36
36
  <span class="stalux-tag-category-icon">
37
37
  <svg
38
38
  aria-hidden="true"
@@ -287,52 +287,50 @@ export const styleNames: { classes: Record<string, string>; variables: Record<st
287
287
  "--stalux-bg-color": "--s1n",
288
288
  "--stalux-bg-filter": "--s1o",
289
289
  "--stalux-nav-offset": "--s1p",
290
- "--stalux-side-in-x": "--s1q",
291
- "--stalux-side-out-x": "--s1r",
292
- "--stalux-site-header-height": "--s1s",
293
- "--stalux-site-header-min-height": "--s1t",
294
- "--stalux-text-shadow": "--s1u",
295
- "--surface-glass": "--s1v",
296
- "--surface-glass-shadow": "--s1w",
297
- "--tag-bg": "--s1x",
298
- "--tag-bg-hover": "--s1y",
299
- "--tl-line": "--s1z",
300
- "--tl-pad": "--s20",
301
- "--transition-fast": "--s21",
302
- "--transition-medium": "--s22",
303
- "--transition-normal": "--s23",
304
- "--transition-slow": "--s24",
305
- "--transition-slower": "--s25",
306
- "--transition-slowest": "--s26",
307
- "--un-rotate": "--s27",
308
- "--un-rotate-x": "--s28",
309
- "--un-rotate-y": "--s29",
310
- "--un-rotate-z": "--s2a",
311
- "--un-scale-x": "--s2b",
312
- "--un-scale-y": "--s2c",
313
- "--un-scale-z": "--s2d",
314
- "--un-skew-x": "--s2e",
315
- "--un-skew-y": "--s2f",
316
- "--un-translate-x": "--s2g",
317
- "--un-translate-y": "--s2h",
318
- "--un-translate-z": "--s2i",
319
- "--updated-bg": "--s2j",
320
- "--updated-border": "--s2k",
321
- "--white-05p": "--s2l",
322
- "--white-10p": "--s2m",
323
- "--white-15p": "--s2n",
324
- "--white-20p": "--s2o",
325
- "--white-30p": "--s2p",
326
- "--white-50p": "--s2q",
327
- "--white-60p": "--s2r",
328
- "--white-70p": "--s2s",
329
- "--white-75p": "--s2t",
330
- "--white-78p": "--s2u",
331
- "--white-80p": "--s2v",
332
- "--white-85p": "--s2w",
333
- "--white-90p": "--s2x",
334
- "--white-95p": "--s2y",
335
- "--white-full": "--s2z"
290
+ "--stalux-site-header-height": "--s1q",
291
+ "--stalux-site-header-min-height": "--s1r",
292
+ "--stalux-text-shadow": "--s1s",
293
+ "--surface-glass": "--s1t",
294
+ "--surface-glass-shadow": "--s1u",
295
+ "--tag-bg": "--s1v",
296
+ "--tag-bg-hover": "--s1w",
297
+ "--tl-line": "--s1x",
298
+ "--tl-pad": "--s1y",
299
+ "--transition-fast": "--s1z",
300
+ "--transition-medium": "--s20",
301
+ "--transition-normal": "--s21",
302
+ "--transition-slow": "--s22",
303
+ "--transition-slower": "--s23",
304
+ "--transition-slowest": "--s24",
305
+ "--un-rotate": "--s25",
306
+ "--un-rotate-x": "--s26",
307
+ "--un-rotate-y": "--s27",
308
+ "--un-rotate-z": "--s28",
309
+ "--un-scale-x": "--s29",
310
+ "--un-scale-y": "--s2a",
311
+ "--un-scale-z": "--s2b",
312
+ "--un-skew-x": "--s2c",
313
+ "--un-skew-y": "--s2d",
314
+ "--un-translate-x": "--s2e",
315
+ "--un-translate-y": "--s2f",
316
+ "--un-translate-z": "--s2g",
317
+ "--updated-bg": "--s2h",
318
+ "--updated-border": "--s2i",
319
+ "--white-05p": "--s2j",
320
+ "--white-10p": "--s2k",
321
+ "--white-15p": "--s2l",
322
+ "--white-20p": "--s2m",
323
+ "--white-30p": "--s2n",
324
+ "--white-50p": "--s2o",
325
+ "--white-60p": "--s2p",
326
+ "--white-70p": "--s2q",
327
+ "--white-75p": "--s2r",
328
+ "--white-78p": "--s2s",
329
+ "--white-80p": "--s2t",
330
+ "--white-85p": "--s2u",
331
+ "--white-90p": "--s2v",
332
+ "--white-95p": "--s2w",
333
+ "--white-full": "--s2x"
336
334
  },
337
335
  "animations": {
338
336
  "fadeInUpComment": "k0",
@@ -340,25 +338,29 @@ export const styleNames: { classes: Record<string, string>; variables: Record<st
340
338
  "stalux-article-enter": "k2",
341
339
  "stalux-article-enter-back": "k3",
342
340
  "stalux-cursor-blink": "k4",
343
- "stalux-link-avatar-spin": "k5",
344
- "stalux-random-spin": "k6",
345
- "stalux-sidebar-left-back-in": "k7",
346
- "stalux-sidebar-left-back-out": "k8",
347
- "stalux-sidebar-left-in": "k9",
348
- "stalux-sidebar-left-out": "ka",
349
- "stalux-sidebar-right-back-in": "kb",
350
- "stalux-sidebar-right-back-out": "kc",
351
- "stalux-sidebar-right-in": "kd",
352
- "stalux-sidebar-right-out": "ke",
353
- "stalux-social-stalux-social-arrive": "kf",
354
- "stalux-taxonomy-enter": "kg",
355
- "stalux-taxonomy-enter-back": "kh",
356
- "stalux-vt-new-route": "ki",
357
- "stalux-vt-old-route": "kj",
358
- "stalux-vt-side-in": "kk",
359
- "stalux-vt-side-out": "kl",
360
- "stalux-vt-title-swap-new": "km",
361
- "stalux-vt-title-swap-old": "kn",
362
- "stalux-word-word-glow": "ko"
341
+ "stalux-focus-enter": "k5",
342
+ "stalux-focus-fade": "k6",
343
+ "stalux-focus-home": "k7",
344
+ "stalux-focus-next": "k8",
345
+ "stalux-focus-previous": "k9",
346
+ "stalux-focus-restore": "ka",
347
+ "stalux-focus-up": "kb",
348
+ "stalux-link-avatar-spin": "kc",
349
+ "stalux-page-enter": "kd",
350
+ "stalux-page-enter-back": "ke",
351
+ "stalux-page-exit": "kf",
352
+ "stalux-random-spin": "kg",
353
+ "stalux-sidebar-left-back-in": "kh",
354
+ "stalux-sidebar-left-back-out": "ki",
355
+ "stalux-sidebar-left-in": "kj",
356
+ "stalux-sidebar-left-out": "kk",
357
+ "stalux-sidebar-right-back-in": "kl",
358
+ "stalux-sidebar-right-back-out": "km",
359
+ "stalux-sidebar-right-in": "kn",
360
+ "stalux-sidebar-right-out": "ko",
361
+ "stalux-social-stalux-social-arrive": "kp",
362
+ "stalux-taxonomy-enter": "kq",
363
+ "stalux-taxonomy-enter-back": "kr",
364
+ "stalux-word-word-glow": "ks"
363
365
  }
364
366
  };
@@ -120,7 +120,7 @@ const routeKind = getRouteKind(Astro.url.pathname);
120
120
  transition:persist="stalux-bg-b"
121
121
  aria-hidden="true"
122
122
  ></div>
123
- <main class="stalux-main" data-stalux-route={routeKind} transition:name="stalux-page">
123
+ <main class="stalux-main" data-stalux-route={routeKind}>
124
124
  <slot />
125
125
  </main>
126
126
  <Footer />
@@ -18,7 +18,7 @@ const { t } = createTranslator(siteConfig.lang || "zh-CN");
18
18
  data-pagefind-ignore
19
19
  >
20
20
  <div class="stalux-404-error-content">
21
- <h1>404</h1>
21
+ <h1 data-stalux-motion-focus>404</h1>
22
22
  <p>{t("page404.pageNotFound")}</p>
23
23
  <p class="agent-recovery">
24
24
  This URL does not exist. Continue at the <a href="/">home page</a>, browse the
@@ -22,8 +22,8 @@ import { getSiteData } from "@utils/config-utils";
22
22
  <div class="stalux-home-body stalux-u-flex stalux-u-items-center stalux-u-flex-col">
23
23
  <h1
24
24
  class="stalux-home-title stalux-u-text-center"
25
- transition:name="stalux-home-title"
26
- transition:animate="fade"
25
+ data-stalux-motion-focus
26
+ transition:animate="none"
27
27
  >
28
28
  {siteTitle}
29
29
  </h1>
@@ -1,7 +1,9 @@
1
1
  import { getRouteKind } from "@utils/public-routes";
2
+ import { getRouteMotionPreset, type RouteMotionPreset } from "@utils/route-motion-policy";
2
3
  import { installBackToTop } from "./back-to-top";
3
4
  import { createClientLogger } from "./logger";
4
5
  import { prepareNavigationFont } from "./navigation-font";
6
+ import { prepareRouteMotion, type RouteMotion } from "./route-motion";
5
7
 
6
8
  const logger = createClientLogger("view-transitions");
7
9
 
@@ -29,14 +31,20 @@ interface NavigationEvent {
29
31
  newDocument: Document;
30
32
  signal: AbortSignal;
31
33
  viewTransition?: ViewTransition;
34
+ sourceElement?: Element;
32
35
  }
33
36
 
34
- function setNavigationState(event: NavigationEvent, html = document.documentElement): void {
37
+ function setNavigationState(
38
+ event: NavigationEvent,
39
+ preset: RouteMotionPreset,
40
+ html = document.documentElement,
41
+ ): void {
35
42
  const from = getRouteKind(new URL(event.from, window.location.href).pathname);
36
43
  const to = getRouteKind(new URL(event.to, window.location.href).pathname);
37
44
  html.dataset.staluxVtFrom = from;
38
45
  html.dataset.staluxVtTo = to;
39
46
  html.dataset.staluxVtDirection = event.direction;
47
+ html.dataset.staluxVtPreset = preset;
40
48
  }
41
49
 
42
50
  function clearNavigationState(): void {
@@ -44,6 +52,30 @@ function clearNavigationState(): void {
44
52
  delete html.dataset.staluxVtFrom;
45
53
  delete html.dataset.staluxVtTo;
46
54
  delete html.dataset.staluxVtDirection;
55
+ delete html.dataset.staluxVtPreset;
56
+ clearFocusVisibility();
57
+ }
58
+
59
+ function clearFocusVisibility(): void {
60
+ document
61
+ .querySelector("[data-stalux-motion-focus]")
62
+ ?.removeAttribute?.("data-stalux-motion-visible");
63
+ }
64
+
65
+ /** At most one bounded title is considered, never an entire article or list. */
66
+ function updateFocusVisibility(): void {
67
+ const focus = document.querySelector<HTMLElement>("[data-stalux-motion-focus]");
68
+ if (!focus || typeof focus.getBoundingClientRect !== "function") return;
69
+ const rect = focus.getBoundingClientRect();
70
+ const visible =
71
+ rect.width > 0 &&
72
+ rect.height > 0 &&
73
+ rect.height <= window.innerHeight / 2 &&
74
+ rect.bottom > 0 &&
75
+ rect.top < window.innerHeight &&
76
+ rect.right > 0 &&
77
+ rect.left < window.innerWidth;
78
+ focus.dataset.staluxMotionVisible = String(visible);
47
79
  }
48
80
 
49
81
  function preserveHeaderMetrics(nextDocument: Document): void {
@@ -63,10 +95,47 @@ const transitionWindow = window as TransitionWindow;
63
95
  if (!transitionWindow.__STALUX_VT_LISTENER__) {
64
96
  transitionWindow.__STALUX_VT_LISTENER__ = true;
65
97
 
98
+ // A current-page link is not a page replacement. Intercept before Astro's
99
+ // delegated handler, but keep propagation for menu cleanup and click tracking.
100
+ // Hash changes, explicit reloads, downloads and modified/new-tab clicks keep
101
+ // their native behavior.
102
+ document.addEventListener(
103
+ "click",
104
+ (event) => {
105
+ if (
106
+ event.defaultPrevented ||
107
+ event.button !== 0 ||
108
+ event.metaKey ||
109
+ event.ctrlKey ||
110
+ event.shiftKey ||
111
+ event.altKey
112
+ )
113
+ return;
114
+ const anchor =
115
+ event.target instanceof Element
116
+ ? event.target.closest<HTMLAnchorElement>("a[href]")
117
+ : null;
118
+ if (
119
+ !anchor ||
120
+ anchor.href !== window.location.href ||
121
+ anchor.href.includes("#") ||
122
+ anchor.hasAttribute("download") ||
123
+ anchor.hasAttribute("data-astro-reload") ||
124
+ anchor.relList.contains("external")
125
+ )
126
+ return;
127
+ const target =
128
+ anchor.getAttribute("target") ??
129
+ document.querySelector("base[target]")?.getAttribute("target");
130
+ if (!target || target === "_self") event.preventDefault();
131
+ },
132
+ { capture: true },
133
+ );
134
+
66
135
  let generation = 0;
67
136
  let pendingBrowserMotion = false;
68
- let _browserMotion = false;
69
- let _routeMotionActive = false;
137
+ let preset: RouteMotionPreset = "none";
138
+ let motion: RouteMotion | undefined;
70
139
  window.addEventListener(
71
140
  "popstate",
72
141
  (event) => {
@@ -79,10 +148,24 @@ if (!transitionWindow.__STALUX_VT_LISTENER__) {
79
148
  document.addEventListener("astro:before-preparation", (event) => {
80
149
  const navigation = event as unknown as NavigationEvent;
81
150
  const current = ++generation;
82
- _routeMotionActive = false;
83
- _browserMotion = pendingBrowserMotion && navigation.navigationType === "traverse";
151
+ motion?.cancel();
152
+ // Only the incoming heading animates. Drop any prior marker without
153
+ // measuring/capturing a hidden outgoing title or flushing its layout.
154
+ clearFocusVisibility();
155
+ preset = getRouteMotionPreset({
156
+ from: new URL(navigation.from, window.location.href),
157
+ to: new URL(navigation.to, window.location.href),
158
+ navigationType: navigation.navigationType,
159
+ intent:
160
+ navigation.sourceElement
161
+ ?.closest("[data-stalux-motion]")
162
+ ?.getAttribute("data-stalux-motion") ?? undefined,
163
+ reducedMotion: window.matchMedia?.("(prefers-reduced-motion: reduce)").matches,
164
+ browserMotion: pendingBrowserMotion && navigation.navigationType === "traverse",
165
+ hidden: document.hidden,
166
+ });
84
167
  pendingBrowserMotion = false;
85
- setNavigationState(navigation);
168
+ setNavigationState(navigation, preset);
86
169
  navigation.signal.addEventListener(
87
170
  "abort",
88
171
  () => {
@@ -95,9 +178,14 @@ if (!transitionWindow.__STALUX_VT_LISTENER__) {
95
178
  });
96
179
  const loader = navigation.loader;
97
180
  navigation.loader = async () => {
98
- await loader();
99
- if (!event.defaultPrevented) {
100
- await prepareNavigationFont(navigation.newDocument, navigation.signal);
181
+ try {
182
+ await loader();
183
+ if (!event.defaultPrevented) {
184
+ await prepareNavigationFont(navigation.newDocument, navigation.signal);
185
+ }
186
+ } catch (error) {
187
+ if (current === generation) clearNavigationState();
188
+ throw error;
101
189
  }
102
190
  };
103
191
  });
@@ -107,28 +195,27 @@ if (!transitionWindow.__STALUX_VT_LISTENER__) {
107
195
  if (navigation.signal.aborted) return;
108
196
  const current = generation;
109
197
  preserveHeaderMetrics(navigation.newDocument);
110
- _routeMotionActive = true;
111
198
  // Astro replaces the root attributes during swap. Carry state into the
112
199
  // new document; CSS keyframes read these data-* attributes to pick their
113
200
  // own direction rather than letting Astro's default `fade` pair apply.
114
- setNavigationState(navigation, navigation.newDocument.documentElement);
201
+ setNavigationState(navigation, preset, navigation.newDocument.documentElement);
202
+ // This release uses CSS/native VT only. Settle the existing installation
203
+ // gate without starting a second WAAPI effect; analytics/background keep
204
+ // the same shared ready/finished semantics and their existing listeners.
205
+ motion = prepareRouteMotion(navigation);
206
+ motion.start(null, { skip: true });
115
207
  const finish = () => {
116
208
  if (current === generation) clearNavigationState();
117
209
  };
118
- // ViewTransition.ready fires when pseudo-elements are painted out; we
119
- // use it as the handoff boundary so our WAAPI for new content starts
120
- // *after* the native swap has painted its snapshot.
121
- const native = navigation.viewTransition;
122
- Promise.resolve(native?.ready)
123
- .then(
124
- () => undefined,
125
- () => undefined,
126
- )
127
- .then(finish);
210
+ // Native ready starts the animation. Keep selectors until it finishes,
211
+ // including fallback/skip and abort; an older navigation cannot clear a
212
+ // newer one's state.
213
+ void motion.finished.then(finish, finish);
128
214
  });
129
215
 
130
216
  document.addEventListener("astro:after-swap", () => {
131
217
  setRouteState(window.location.pathname);
218
+ if (preset !== "none") updateFocusVisibility();
132
219
  });
133
220
 
134
221
  document.addEventListener("astro:page-load", () => {
@@ -1,3 +1,3 @@
1
1
  @layer theme, base, components, utilities;
2
- @layer components{.stalux-404-home-btn{background:var(--black-20p);border:var(--border-thin) solid var(--white-20p);transition:background-color var(--transition-normal), transform var(--transition-normal), box-shadow var(--transition-normal);border-radius:var(--radius-md);padding:var(--space-md) var(--space-lg);color:var(--white-90p);font-size:var(--font-size-base);text-decoration:none;display:inline-block}.stalux-ai-prompt{clip-path:inset(50%);white-space:pre-wrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.stalux-badge-group{border:none}.stalux-badge-group-arrow{font-size:.65rem;transition:transform .2s;display:inline-block}.stalux-badge-group-summary{user-select:none;cursor:pointer;color:var(--white-70p);gap:.4rem;padding:.2rem 0;font-size:.85rem;list-style-type:none;transition:color .2s}.stalux-beian-public-security-beian{color:#ffffffb3;gap:5px;font-size:.9rem;text-decoration:none;transition:color .3s;display:inline-flex}.stalux-card-post-categories,.stalux-card-post-tags{gap:.4rem}.stalux-card-post-category{background:var(--category-bg);color:#fff;border-radius:6px;padding:.18rem .5rem;font-size:.84rem;line-height:1;display:inline-block}.stalux-card-post-description{overflow-wrap:anywhere;color:var(--white-70p);line-height:1.6}.stalux-card-post-meta{gap:.6rem}.stalux-card-post-tag{background:var(--tag-bg);color:#fff;border-radius:9999px;padding:.22rem .7rem;font-size:.85rem;line-height:1;display:inline-block}.stalux-card-post-title{overflow-wrap:anywhere;margin:0;line-height:1.35}.stalux-card-read-more{align-self:flex-start;margin-top:.6rem}.stalux-card-time{gap:.45rem;display:inline-flex}.stalux-copyright{color:var(--white-70p);gap:.3em;font-weight:500}.stalux-footer{backdrop-filter:blur(10px);color:var(--white-full);background-color:#0000001a;margin-top:auto;padding:1.5rem 0;font-size:.9rem}.stalux-footer-content{gap:.8rem;max-width:1200px;margin:0 auto;padding:0 1rem}.stalux-nav-list{transform:scale(var(--nav-scale,1));transform-origin:50%;box-sizing:border-box;gap:2rem;max-width:100%;transition:transform .22s cubic-bezier(.22,.72,.22,1);overflow:visible}.stalux-nav-overlay{pointer-events:none;z-index:999;opacity:0;background:#0009;height:100%;transition:opacity .3s;display:none;position:fixed;top:0;left:0}.stalux-nav-scroll-btn{background:var(--black-30p);backdrop-filter:blur(8px);box-shadow:var(--shadow-md);pointer-events:none;z-index:10;cursor:pointer;width:36px;height:36px;color:var(--white-full);opacity:0;border:none;border-radius:9999px;padding:0;transition:opacity .25s;display:none;position:absolute;top:50%;transform:translateY(-50%)}.stalux-nav-toggle{z-index:998;cursor:pointer;min-width:48px;min-height:48px;color:inherit;background:0 0;border:none;padding:.75rem;display:none}.stalux-post-card{box-sizing:border-box;cursor:pointer;gap:var(--space-lg);border-radius:var(--radius-lg);background-color:var(--card-bg);height:100%;padding:var(--space-lg);box-shadow:var(--card-box-shadow);transition:transform .22s cubic-bezier(.22,.72,.22,1)}.stalux-stats-site-build-time{color:#fffc;margin-top:.5rem;font-size:.9rem}.stalux-stats-stats-separator{color:#ffffff80}.stalux-theme-info{color:var(--white-70p);gap:.3em;font-size:.85rem}.stalux-home-body{min-height:calc(100vh - var(--stalux-site-header-height));padding-bottom:var(--space-3xl);position:relative}.stalux-nav-container{box-sizing:border-box;max-width:100%;position:relative;overflow:hidden}.stalux-author{margin-top:4em}.stalux-card-post-cover{border-radius:var(--radius-md);flex-shrink:0;height:180px;margin-bottom:.5rem;overflow:hidden}.stalux-home-title{color:var(--white-full);text-shadow:var(--stalux-text-shadow);margin-top:1.5em;font-size:4em}.stalux-nav-item{text-shadow:var(--stalux-text-shadow);flex-shrink:0;margin-left:1em;margin-right:1em;font-size:1.3em}.stalux-page-description{color:var(--white-60p);margin-bottom:1.5em;font-size:1.2em}.stalux-page-title{text-shadow:var(--stalux-text-shadow);margin-top:1.5em;font-size:2.5em}.stalux-typewriter{min-height:2em;text-shadow:var(--stalux-text-shadow);margin-top:1.5em;font-size:2.5em}.stalux-404-error-container{min-height:60vh;padding:2rem}.stalux-badge,.stalux-badges-wrapper .stalux-badge{width:auto}.stalux-u-min-w-0{min-width:0}.stalux-u-w-full{width:100%}.stalux-u-flex{display:flex}.stalux-u-flex-col{flex-direction:column}.stalux-u-flex-wrap{flex-wrap:wrap}.stalux-u-items-center{align-items:center}.stalux-u-justify-center{justify-content:center}.stalux-badges,.stalux-badges-wrapper{gap:.5rem}.stalux-beian-beian-info{gap:1rem}.stalux-stats-site-stats{gap:.5rem;font-size:.9rem}.stalux-nav-text{white-space:nowrap;color:var(--white-full)}.stalux-badge-group-items{padding-top:.35rem}.stalux-u-text-center{text-align:center}.stalux-badge-group-hint{color:var(--white-70p);font-size:.7rem}.stalux-badge-group-title{color:var(--white-80p)}#stalux-home-show-post-list{cursor:pointer;text-shadow:var(--stalux-text-shadow);margin-top:3em;font-size:1.5em}.stalux-post-list-container{width:100%;height:auto;margin:5px 0}.stalux-post-list-container ul{flex-wrap:wrap;gap:2rem;margin:3em;padding:0;list-style-type:none;display:flex}.stalux-post-list-container ul>li{flex:min(22rem,100%);min-width:0;margin:0}.stalux-card-post-title a{color:inherit;text-decoration:none}.stalux-post-card>a:first-child{width:100%;min-width:0;display:block}.stalux-card-post-cover img{object-fit:cover;width:100%;max-width:100%;height:100%;transition:transform var(--transition-fast)}.stalux-card-post-date,.stalux-card-post-updated{color:#e8f2ff;border-radius:10px;align-items:center;gap:.35rem;width:fit-content;padding:.28rem .6rem;font-size:.9rem;line-height:1.1;display:inline-flex}.stalux-card-post-date{background:var(--date-bg);border:1px solid var(--date-border);color:#e8f2ff}.stalux-card-post-updated{background:var(--updated-bg);border:1px solid var(--updated-border);color:#fff7de}.stalux-card-post-tags a,.stalux-card-post-categories a{text-decoration:none}.stalux-card-post-tags a:focus-visible .stalux-card-post-tag{background:var(--tag-bg-hover)}.stalux-card-post-categories a:focus-visible .stalux-card-post-category{background:var(--category-bg-hover)}.stalux-social{margin-top:3em}.stalux-social ul{flex-wrap:wrap;justify-content:center;gap:1em;margin:0;padding:0;display:flex}.stalux-social ul li{box-sizing:border-box;text-align:center;background-color:var(--white-15p);border-radius:9999px;justify-content:center;align-items:center;width:2.5em;height:2.5em;font-size:large;display:inline-flex;overflow:hidden}.stalux-social ul a,.stalux-social ul .stalux-social-icon-container,.stalux-social ul .stalux-social-custom-icon{justify-content:center;align-items:center;width:100%;height:100%;line-height:1;display:inline-flex}.stalux-social[data-stalux-social-animate=true] li{animation:.28s cubic-bezier(.2,.8,.2,1) both stalux-social-stalux-social-arrive}.stalux-social[data-stalux-social-animate=true] li:nth-child(2){animation-delay:30ms}.stalux-social[data-stalux-social-animate=true] li:nth-child(3){animation-delay:60ms}.stalux-social[data-stalux-social-animate=true] li:nth-child(4){animation-delay:90ms}.stalux-social[data-stalux-social-animate=true] li:nth-child(5){animation-delay:.12s}.stalux-social[data-stalux-social-animate=true] li:nth-child(6){animation-delay:.15s}.stalux-social[data-stalux-social-animate=true] li:nth-child(n+7){animation-delay:.18s}nav{width:100%;min-width:0;max-width:100%}html{scroll-padding-top:var(--stalux-nav-offset,var(--stalux-site-header-height))}.stalux-site-header{z-index:990;width:100%;min-height:var(--stalux-site-header-min-height);isolation:isolate;justify-content:center;align-items:center;display:flex;position:sticky;top:0}.stalux-nav-scroll-btn[data-visible]{pointer-events:auto;opacity:1}.stalux-nav-scroll-btn[data-side=left]{left:4px}.stalux-nav-scroll-btn[data-side=right]{right:4px}.stalux-nav-scroll-btn svg{stroke:currentColor;stroke-width:2px;fill:none;width:20px;height:20px}.stalux-nav-link,.stalux-nav-link:visited{cursor:pointer;width:100%;color:inherit;min-height:44px;font:inherit;background:0 0;border:none;align-items:center;gap:.5rem;padding:.5rem .75rem;text-decoration:none;display:flex}.stalux-nav-link .nav-icon{stroke:var(--white-full)}.stalux-nav-toggle svg{width:32px;height:32px}.stalux-nav-overlay[data-state=show]{pointer-events:auto;opacity:1;display:block}#stalux-to-archive-archs{margin-top:2em}#stalux-date-date-time{text-shadow:var(--stalux-text-shadow);color:var(--white-full);flex-direction:column;align-items:center;margin-top:2em;display:flex}#stalux-date-date-time #stalux-date-date{min-height:1.25em;margin-bottom:.5em;font-size:2em;line-height:1.25}#stalux-date-date-time #stalux-date-time{font-variant-numeric:tabular-nums;min-height:1.25em;font-size:3em;line-height:1.25}.stalux-author-figure{justify-content:center;align-items:center;display:flex}.stalux-author-figure img{box-shadow:0 0 10px var(--stalux-accent-color);border-radius:9999px;transition:transform .65s ease-in-out}.stalux-author-figure figcaption{text-shadow:var(--stalux-text-shadow);color:var(--white-full);margin-left:1em;font-size:2.5em;font-weight:700}.stalux-author-figure-column figcaption{text-align:center;margin-top:.5em;margin-left:0}.agent-home-summary{clip-path:inset(50%);white-space:normal;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.stalux-404-error-content h1{color:var(--white-90p);margin:0;font-size:6rem;font-weight:700}.stalux-404-error-content p{color:var(--white-70p);margin:1rem 0 2rem;font-size:1.5rem}.stalux-404-countdown-text{color:var(--white-50p)!important;margin:-.5rem 0 1.5rem!important;font-size:.95rem!important}.agent-recovery{max-width:42rem;line-height:1.7;margin:0 auto 1.5rem!important;font-size:1rem!important}.agent-recovery a{color:inherit;text-decoration-line:underline}.stalux-theme-info span,.stalux-copyright span{margin:0}.stalux-theme-info a{color:#fffc;margin:0 .2em;text-decoration:none;transition:color .3s}.stalux-beian-beian-info a{color:#ffffffb3;font-size:.9rem;text-decoration:none;transition:color .3s}.stalux-beian-public-security-beian img{width:15px;height:15px;display:inline-block}.stalux-badge-group-summary::-webkit-details-marker,.stalux-badge-group[open] .stalux-badge-group-hint[data-hint=collapsed],.stalux-badge-group:not([open]) .stalux-badge-group-hint[data-hint=expanded]{display:none}.stalux-badge-group[open] .stalux-badge-group-arrow{transform:rotate(90deg)}@media (hover:hover) and (pointer:fine){.stalux-card-post-tags a:hover .stalux-card-post-tag{background:var(--tag-bg-hover)}.stalux-card-post-categories a:hover .stalux-card-post-category{background:var(--category-bg-hover)}.stalux-post-card-shell:hover .stalux-post-card .stalux-card-post-cover img{transform:scale(1.025)}.stalux-post-card-shell:hover .stalux-post-card{box-shadow:var(--card-box-shadow-hover)}.stalux-nav-scroll-btn:hover{background:0 0}.stalux-nav-container:hover .stalux-nav-scroll-btn[data-visible]{opacity:1}.stalux-nav-link:hover .nav-icon,.stalux-nav-link:hover .stalux-nav-text{stroke:var(--stalux-accent-color);color:var(--stalux-accent-color)}.stalux-author-figure>a:hover img{animation:.65s ease-in-out stalux-link-avatar-spin}.stalux-404-home-btn:hover{background:var(--accent-20p);box-shadow:0 4px 12px var(--shadow-dark)}.stalux-theme-info a:hover{color:#fff;text-decoration:none}.stalux-beian-beian-info a:hover,.stalux-beian-public-security-beian:hover{color:#ffffffe6;text-decoration:none}.stalux-badge-group-summary:hover{color:var(--white-70p)}}@media (width>=601px){.stalux-site-nav{isolation:isolate;border-radius:0 0 16px 16px;transition:background-color .18s,box-shadow .18s}.stalux-site-nav[data-scrolled]{backdrop-filter:blur(20px)saturate(140%);box-shadow:0 1px 0 var(--white-10p), 0 8px 24px #0000001f;background:#181818c7}}@media (width<=1100px){.stalux-nav-list{gap:1rem}.stalux-nav-item{margin-left:.6em;margin-right:.6em;font-size:1em}}@media (width<=900px){.stalux-nav-item{margin-left:.25em;margin-right:.25em;font-size:.95em}.stalux-nav-list{gap:.5rem}}@media (width<=768px){.stalux-home-body{box-sizing:border-box;width:100%;max-width:95vw;height:auto;padding:2rem .5rem 1.5rem}.stalux-home-title{word-break:break-all;margin-top:1em;font-size:2em}#stalux-home-show-post-list{margin-top:2em;font-size:1.1em}.stalux-post-list-container ul{margin:1rem}.stalux-footer{padding:1.2rem 0;font-size:.8rem}.stalux-footer-content{gap:.6rem;padding:0 .8rem}.stalux-author{box-sizing:border-box;width:100%;max-width:95vw;margin-top:2em;padding:1em .5em}.stalux-author-figure{gap:.5em;flex-direction:column!important}.stalux-author-figure img{max-width:20vw;max-height:20vw;width:64px!important;height:64px!important}.stalux-author-figure figcaption{text-align:center;word-break:break-all;overflow-wrap:break-word;white-space:normal;max-width:90vw;margin-top:.5em;margin-left:0;font-size:1.5em}.stalux-404-error-content h1{font-size:4rem}.stalux-404-error-content p{font-size:1.2rem}.stalux-badges{gap:.3rem}.stalux-badge{width:auto}}@media (width<=600px){html{--stalux-site-header-min-height:4rem}.stalux-nav-toggle[data-state=open]{visibility:hidden;pointer-events:none}.stalux-nav-toggle[data-scrolled]{backdrop-filter:blur(20px)saturate(140%);box-shadow:0 1px 0 var(--white-10p), 0 8px 24px #0000001f;background:#181818c7;border-radius:12px}.stalux-nav-toggle{display:block;position:fixed;top:.75rem;left:.75rem}.stalux-nav-container{overflow:visible}nav{width:auto}.stalux-nav-list{pointer-events:none;z-index:1000;background:var(--black-20p);backdrop-filter:blur(20px);flex-direction:column;justify-content:flex-start;align-items:flex-start;gap:0;width:min(220px,100vw - 1rem);height:100vh;padding:.5rem 1rem 2rem;position:fixed;top:0;left:0;right:auto;overflow-y:auto;transform:translate(-100%)}.stalux-nav-list[data-state=open]{pointer-events:auto;transform:translate(0)}.stalux-nav-item{border-bottom:1px solid var(--white-10p);flex-shrink:0;width:100%;margin:0;font-size:.9em}.stalux-nav-text{display:inline}.stalux-nav-link{width:100%;min-height:44px;font-size:inherit;padding:.45rem .75rem}.stalux-nav-link .nav-icon{width:18px;height:18px}}@media (width<=480px){.stalux-footer{padding:1rem 0;font-size:.8rem}.stalux-footer-content{gap:.6rem;padding:0 .8rem}}@media (prefers-reduced-motion:reduce){.stalux-social[data-stalux-social-animate=true] li{animation:none}}.stalux-main,.stalux-post-page,.stalux-post-layout>*,.stalux-link-card-content,.stalux-word-list-item,.stalux-word-card{box-sizing:border-box;min-width:0;max-width:100%}.stalux-main{overflow-wrap:anywhere}.stalux-link-shell{min-width:0;max-width:100%;display:block}.stalux-link-card{box-sizing:border-box;width:100%;max-width:100%}.stalux-category-shell{width:100%;min-width:0}.stalux-author-figure>a{flex-shrink:0;display:inline-block}.stalux-author-figure img{display:block}.stalux-post-card-shell,.stalux-category-shell,.stalux-link-shell{position:relative}.stalux-post-card,.stalux-category-card,.stalux-link-card,.stalux-word-card{transition:transform .2s,background-color .2s,border-color .2s,box-shadow .2s}:is(.stalux-post-card-shell,.stalux-category-shell):focus-within>*,.stalux-link-shell:focus-visible>*{box-shadow:var(--card-box-shadow-hover)}:is(button,summary,[role=button]):focus-visible{outline:2px solid var(--stalux-accent-color);outline-offset:3px}@media (prefers-reduced-motion:reduce){.stalux-main *,.stalux-main :before,.stalux-main :after{transition-duration:0s!important;animation:none!important}.stalux-post-card,.stalux-category-card,.stalux-link-card,.stalux-link-card-content,.stalux-card-post-cover img,.stalux-category-icon,.stalux-author-figure img,.stalux-link-card-avatar img{transform:none!important}}@keyframes stalux-social-stalux-social-arrive{0%{opacity:0;transform:translateY(.75rem)rotate(-12deg)}to{opacity:1;transform:translateY(0)rotate(0)}}@keyframes stalux-random-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes stalux-link-avatar-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes stalux-word-word-glow{0%{box-shadow:0 0 30px var(--accent-50p), 0 0 80px var(--accent-30p), var(--shadow-lg);transform:scale(1.02)}to{box-shadow:0 0 20px var(--accent-40p), 0 0 60px var(--accent-20p), var(--shadow-lg);transform:scale(1)}}}@layer utilities{.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.visible{visibility:visible}.absolute{position:absolute}.static{position:static}.grid{display:grid}.block{display:block}.inline-block{display:inline-block}.hidden{display:none}.h-full{height:100%}.flex{display:flex}.flex-shrink{flex-shrink:1}.flex-wrap{flex-wrap:wrap}.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}.b,.border{border-width:1px}.text-inherit{color:inherit}.no-underline{text-decoration:none}.outline{outline-style:solid}}@layer theme;@layer base{html,body{color:#fff;width:100%;height:100%;margin:0;& main{flex:1}scrollbar-color:#4a4a4a #2a2a2a;font-family:var(--font-body), "Noto Sans SC", "Noto Sans CJK SC", system-ui, -apple-system, sans-serif;text-rendering:optimizelegibility;line-height:1.25;display:block}body{height:auto;min-height:100%}html{scrollbar-gutter:stable;background-color:var(--stalux-bg-color,#202020)}html[data-clarity-id]{opacity:1!important}a{color:inherit;cursor:pointer;text-decoration-skip-ink:auto;background-color:#0000;text-decoration:none;transition:color .2s,text-shadow .2s;position:relative}.a-none{cursor:pointer;text-decoration-skip-ink:auto;background-color:#0000;color:inherit!important;text-decoration:none!important}.a-none:after{display:none!important}a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):after{content:"";background:linear-gradient(90deg, var(--stalux-accent-color), var(--accent-50p));transform-origin:0;pointer-events:none;width:100%;height:1px;transition:transform .25s cubic-bezier(.25,.9,.2,1);position:absolute;bottom:-2px;left:0;transform:scaleX(0)}a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):focus-visible:after,a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):active:after{transform:scaleX(1)}@media (hover:hover) and (pointer:fine){a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):hover:after{transform:scaleX(1)}}a:active,a:focus-visible{text-decoration:none}@media (hover:hover) and (pointer:fine){a:hover{text-decoration:none}}a:focus{outline:none}a:focus-visible{outline:2px solid var(--stalux-accent-color);outline-offset:2px}ul{margin:0;padding:0;list-style:none}.none{display:none}.stalux-root{color:#fff;min-height:100vh}.stalux-main{min-height:calc(100vh - var(--stalux-site-header-height,3rem))}:root{--stalux-bg-color:#202020;--stalux-bg-filter:none;--stalux-site-header-min-height:3.75rem;--stalux-site-header-height:var(--stalux-site-header-min-height);--stalux-text-shadow:var(--stalux-accent-color) .08rem .08rem .18rem;--stalux-accent-color:#eab308;--stalux-accent-rgb:234 179 8;--surface-glass:var(--black-05p);--surface-glass-shadow:var(--shadow-sidebar);--card-bg:var(--surface-glass);--card-border:#ffffff1a;--card-box-shadow:0 10px 24px #00000014;--card-box-shadow-hover:0 14px 28px #0000001f;--tag-bg:#ffffff1f;--tag-bg-hover:#ffffff2e;--category-bg:#ffffff14;--category-bg-hover:#ffffff24;--date-bg:#42a0ff2e;--date-border:#42a0ff40;--updated-bg:#ffc94733;--updated-border:#ffc9474d;--white-full:#fff;--white-95p:#fffffff2;--white-90p:#ffffffe6;--white-85p:#ffffffd9;--white-80p:#ffffffe6;--white-78p:#ffffffc7;--white-75p:#ffffffbf;--white-70p:#ffffffdb;--white-60p:#fff9;--white-50p:#ffffff80;--white-30p:#ffffff4d;--white-20p:#fff3;--white-15p:#ffffff26;--white-10p:#ffffff1a;--white-05p:#ffffff0d;--black-30p:#0000004d;--black-20p:#0003;--black-15p:#00000026;--black-10p:#0000001a;--black-05p:#0000000d;--accent-90p:rgb(var(--stalux-accent-rgb) / .9);--accent-85p:rgb(var(--stalux-accent-rgb) / .85);--accent-80p:rgb(var(--stalux-accent-rgb) / .8);--accent-70p:rgb(var(--stalux-accent-rgb) / .7);--accent-60p:rgb(var(--stalux-accent-rgb) / .6);--accent-50p:rgb(var(--stalux-accent-rgb) / .5);--accent-40p:rgb(var(--stalux-accent-rgb) / .4);--accent-30p:rgb(var(--stalux-accent-rgb) / .3);--accent-20p:rgb(var(--stalux-accent-rgb) / .2);--transition-fast:.18s ease;--transition-medium:.2s ease;--transition-normal:.25s ease;--transition-slow:.3s ease;--transition-slower:.5s ease;--transition-slowest:.6s ease;--easing-bounce:cubic-bezier(.175, .885, .32, 1.275);--space-2xs:.25rem;--space-xs:.75rem;--space-sm:.5rem;--space-md:1rem;--space-lg:1.5rem;--space-xl:2rem;--space-2xl:3rem;--space-3xl:4rem;--radius-sm:4px;--radius-md:6px;--radius-lg:8px;--radius-full:9999px;--shadow-sm:0 2px 5px #0000001a;--shadow-md:0 6px 16px #0003;--shadow-lg:0 8px 20px #0000004d;--shadow-xl:0 12px 26px #00000047;--shadow-sidebar:0 16px 20px -12px #000000d6, 10px 4px 16px -12px #00000094, -10px 4px 16px -12px #00000094;--shadow-raised-hover:0 20px 24px -13px #000000e6, 12px 5px 18px -13px #000000ad, -12px 5px 18px -13px #000000ad;--shadow-dark:#000000c0;--muted-text:#bbb;--font-body:"Noto Sans SC", "Noto Sans CJK SC", system-ui, sans-serif;--font-size-subtitle:1.35rem;--font-size-base:1.1rem;--font-size-small:.95rem;--font-size-smaller:.9rem;--font-size-tiny:.85rem;--border-thin:1px;--border-medium:2px;--border-thick:3px}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:#2a2a2a;border-radius:4px}::-webkit-scrollbar-thumb{background:#4a4a4a;border-radius:4px;transition:background .3s ease-out}@media (hover:hover) and (pointer:fine){::-webkit-scrollbar-thumb:hover{background:#5a5a5a}}::-webkit-scrollbar-corner{background:#2a2a2a}.bg-layer{z-index:-10;background-position:50%;background-repeat:repeat;background-size:auto;background-color:var(--stalux-bg-color,transparent);filter:var(--stalux-bg-filter,none);pointer-events:none;opacity:0;forced-color-adjust:none;color-scheme:light only;transition:opacity .65s ease-in-out;position:fixed;inset:0}@media (prefers-reduced-motion:reduce){.bg-layer{transition-duration:0s}}footer{padding:var(--space-lg) var(--space-md);text-align:center;color:var(--muted-text);border-top:1px solid var(--white-10p);backdrop-filter:blur(16px);background:linear-gradient(#0c0e122e,#0c0e12b8)}}@media print{[data-stalux-offscreen-code],[data-stalux-offscreen-svg]{content-visibility:visible!important;contain-intrinsic-block-size:none!important}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.stagger-children>:first-child{animation-delay:.1s}.stagger-children>:nth-child(2){animation-delay:.15s}.stagger-children>:nth-child(3){animation-delay:.2s}.stagger-children>:nth-child(4){animation-delay:.25s}.stagger-children>:nth-child(5){animation-delay:.3s}.stagger-children>:nth-child(n+6){animation-delay:.35s}@keyframes stalux-vt-title-swap-old{to{opacity:0;filter:blur(2px);transform:scale(.94)}}@keyframes stalux-vt-title-swap-new{0%{opacity:0;filter:blur(2px);transform:scale(1.05)}70%{filter:blur();transform:scale(.98)}to{opacity:1;filter:blur();transform:scale(1)}}@keyframes stalux-vt-old-route{0%{opacity:1;transform:translate(0,0)}45%{opacity:.5}to{opacity:0;transform:translate(-6%)}}@keyframes stalux-vt-new-route{0%{opacity:0;filter:blur(1.2px);transform:translate(6%)scale(.985)}60%{opacity:.9;filter:blur();transform:translate(-.8%)scale(1)}to{opacity:1;filter:blur();transform:translate(0,0)}}::view-transition-old(stalux-page){animation:.38s cubic-bezier(.22,.72,.22,1) both stalux-vt-old-route}::view-transition-new(stalux-page){animation:.46s cubic-bezier(.22,.72,.22,1) both stalux-vt-new-route}::view-transition-old(stalux-post-title){animation:.26s cubic-bezier(.22,.72,.22,1) both stalux-vt-title-swap-old}::view-transition-new(stalux-post-title){animation:.32s cubic-bezier(.22,.72,.22,1) both stalux-vt-title-swap-new}@keyframes stalux-vt-side-out{to{opacity:0;transform:translate3d(var(--stalux-side-out-x,-14px), 0, 0)}}@keyframes stalux-vt-side-in{0%{opacity:0;transform:translate3d(var(--stalux-side-in-x,14px), 0, 0)}to{opacity:1;transform:translate(0,0)}}html,.stalux-main,.stalux-main *,[data-astro-transition-persist],[data-stalux-site-header],[data-stalux-site-header] *,.bg-layer,.bg-layer *,[data-stalux-scroll-sentinel],[data-stalux-scroll-sentinel] *,[data-stalux-back-to-top],[data-stalux-back-to-top] *{view-transition-name:none!important}[data-stalux-scroll-sentinel]{visibility:hidden;pointer-events:none;width:1px;height:1px;position:absolute;top:240px;left:0}@keyframes stalux-taxonomy-enter{0%{opacity:0;transform:translate(12px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-taxonomy-enter-back{0%{opacity:0;transform:translate(-12px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-article-enter{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes stalux-article-enter-back{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}@keyframes stalux-sidebar-left-in{0%{opacity:0;transform:translate(-14px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-sidebar-left-out{to{opacity:0;transform:translate(-10px)}}@keyframes stalux-sidebar-left-back-in{0%{opacity:0;transform:translate(14px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-sidebar-left-back-out{to{opacity:0;transform:translate(10px)}}@keyframes stalux-sidebar-right-in{0%{opacity:0;transform:translate(14px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-sidebar-right-out{to{opacity:0;transform:translate(10px)}}@keyframes stalux-sidebar-right-back-in{0%{opacity:0;transform:translate(-14px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-sidebar-right-back-out{to{opacity:0;transform:translate(-10px)}}@media (prefers-reduced-motion:reduce){::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){filter:none!important;animation-duration:1ms!important;animation-delay:0s!important;transform:none!important}.stalux-main,.stalux-main *,.postLayout *{scroll-behavior:auto!important;transition-duration:1ms!important;animation-duration:1ms!important;animation-iteration-count:1!important}}
2
+ @layer components{.stalux-404-home-btn{background:var(--black-20p);border:var(--border-thin) solid var(--white-20p);transition:background-color var(--transition-normal), transform var(--transition-normal), box-shadow var(--transition-normal);border-radius:var(--radius-md);padding:var(--space-md) var(--space-lg);color:var(--white-90p);font-size:var(--font-size-base);text-decoration:none;display:inline-block}.stalux-ai-prompt{clip-path:inset(50%);white-space:pre-wrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.stalux-badge-group{border:none}.stalux-badge-group-arrow{font-size:.65rem;transition:transform .2s;display:inline-block}.stalux-badge-group-summary{user-select:none;cursor:pointer;color:var(--white-70p);gap:.4rem;padding:.2rem 0;font-size:.85rem;list-style-type:none;transition:color .2s}.stalux-beian-public-security-beian{color:#ffffffb3;gap:5px;font-size:.9rem;text-decoration:none;transition:color .3s;display:inline-flex}.stalux-card-post-categories,.stalux-card-post-tags{gap:.4rem}.stalux-card-post-category{background:var(--category-bg);color:#fff;border-radius:6px;padding:.18rem .5rem;font-size:.84rem;line-height:1;display:inline-block}.stalux-card-post-description{overflow-wrap:anywhere;color:var(--white-70p);line-height:1.6}.stalux-card-post-meta{gap:.6rem}.stalux-card-post-tag{background:var(--tag-bg);color:#fff;border-radius:9999px;padding:.22rem .7rem;font-size:.85rem;line-height:1;display:inline-block}.stalux-card-post-title{overflow-wrap:anywhere;margin:0;line-height:1.35}.stalux-card-read-more{align-self:flex-start;margin-top:.6rem}.stalux-card-time{gap:.45rem;display:inline-flex}.stalux-copyright{color:var(--white-70p);gap:.3em;font-weight:500}.stalux-footer{backdrop-filter:blur(10px);color:var(--white-full);background-color:#0000001a;margin-top:auto;padding:1.5rem 0;font-size:.9rem}.stalux-footer-content{gap:.8rem;max-width:1200px;margin:0 auto;padding:0 1rem}.stalux-nav-list{transform:scale(var(--nav-scale,1));transform-origin:50%;box-sizing:border-box;gap:2rem;max-width:100%;transition:transform .22s cubic-bezier(.22,.72,.22,1);overflow:visible}.stalux-nav-overlay{pointer-events:none;z-index:999;opacity:0;background:#0009;height:100%;transition:opacity .3s;display:none;position:fixed;top:0;left:0}.stalux-nav-scroll-btn{background:var(--black-30p);backdrop-filter:blur(8px);box-shadow:var(--shadow-md);pointer-events:none;z-index:10;cursor:pointer;width:36px;height:36px;color:var(--white-full);opacity:0;border:none;border-radius:9999px;padding:0;transition:opacity .25s;display:none;position:absolute;top:50%;transform:translateY(-50%)}.stalux-nav-toggle{z-index:998;cursor:pointer;min-width:48px;min-height:48px;color:inherit;background:0 0;border:none;padding:.75rem;display:none}.stalux-post-card{box-sizing:border-box;cursor:pointer;gap:var(--space-lg);border-radius:var(--radius-lg);background-color:var(--card-bg);height:100%;padding:var(--space-lg);box-shadow:var(--card-box-shadow);transition:transform .22s cubic-bezier(.22,.72,.22,1)}.stalux-stats-site-build-time{color:#fffc;margin-top:.5rem;font-size:.9rem}.stalux-stats-stats-separator{color:#ffffff80}.stalux-theme-info{color:var(--white-70p);gap:.3em;font-size:.85rem}.stalux-home-body{min-height:calc(100vh - var(--stalux-site-header-height));padding-bottom:var(--space-3xl);position:relative}.stalux-nav-container{box-sizing:border-box;max-width:100%;position:relative;overflow:hidden}.stalux-author{margin-top:4em}.stalux-card-post-cover{border-radius:var(--radius-md);flex-shrink:0;height:180px;margin-bottom:.5rem;overflow:hidden}.stalux-home-title{color:var(--white-full);text-shadow:var(--stalux-text-shadow);margin-top:1.5em;font-size:4em}.stalux-nav-item{text-shadow:var(--stalux-text-shadow);flex-shrink:0;margin-left:1em;margin-right:1em;font-size:1.3em}.stalux-page-description{color:var(--white-60p);margin-bottom:1.5em;font-size:1.2em}.stalux-page-title{text-shadow:var(--stalux-text-shadow);margin-top:1.5em;font-size:2.5em}.stalux-typewriter{min-height:2em;text-shadow:var(--stalux-text-shadow);margin-top:1.5em;font-size:2.5em}.stalux-404-error-container{min-height:60vh;padding:2rem}.stalux-badge,.stalux-badges-wrapper .stalux-badge{width:auto}.stalux-u-min-w-0{min-width:0}.stalux-u-w-full{width:100%}.stalux-u-flex{display:flex}.stalux-u-flex-col{flex-direction:column}.stalux-u-flex-wrap{flex-wrap:wrap}.stalux-u-items-center{align-items:center}.stalux-u-justify-center{justify-content:center}.stalux-badges,.stalux-badges-wrapper{gap:.5rem}.stalux-beian-beian-info{gap:1rem}.stalux-stats-site-stats{gap:.5rem;font-size:.9rem}.stalux-nav-text{white-space:nowrap;color:var(--white-full)}.stalux-badge-group-items{padding-top:.35rem}.stalux-u-text-center{text-align:center}.stalux-badge-group-hint{color:var(--white-70p);font-size:.7rem}.stalux-badge-group-title{color:var(--white-80p)}#stalux-home-show-post-list{cursor:pointer;text-shadow:var(--stalux-text-shadow);margin-top:3em;font-size:1.5em}.stalux-post-list-container{width:100%;height:auto;margin:5px 0}.stalux-post-list-container ul{flex-wrap:wrap;gap:2rem;margin:3em;padding:0;list-style-type:none;display:flex}.stalux-post-list-container ul>li{flex:min(22rem,100%);min-width:0;margin:0}.stalux-card-post-title a{color:inherit;text-decoration:none}.stalux-post-card>a:first-child{width:100%;min-width:0;display:block}.stalux-card-post-cover img{object-fit:cover;width:100%;max-width:100%;height:100%;transition:transform var(--transition-fast)}.stalux-card-post-date,.stalux-card-post-updated{color:#e8f2ff;border-radius:10px;align-items:center;gap:.35rem;width:fit-content;padding:.28rem .6rem;font-size:.9rem;line-height:1.1;display:inline-flex}.stalux-card-post-date{background:var(--date-bg);border:1px solid var(--date-border);color:#e8f2ff}.stalux-card-post-updated{background:var(--updated-bg);border:1px solid var(--updated-border);color:#fff7de}.stalux-card-post-tags a,.stalux-card-post-categories a{text-decoration:none}.stalux-card-post-tags a:focus-visible .stalux-card-post-tag{background:var(--tag-bg-hover)}.stalux-card-post-categories a:focus-visible .stalux-card-post-category{background:var(--category-bg-hover)}.stalux-social{margin-top:3em}.stalux-social ul{flex-wrap:wrap;justify-content:center;gap:1em;margin:0;padding:0;display:flex}.stalux-social ul li{box-sizing:border-box;text-align:center;background-color:var(--white-15p);border-radius:9999px;justify-content:center;align-items:center;width:2.5em;height:2.5em;font-size:large;display:inline-flex;overflow:hidden}.stalux-social ul a,.stalux-social ul .stalux-social-icon-container,.stalux-social ul .stalux-social-custom-icon{justify-content:center;align-items:center;width:100%;height:100%;line-height:1;display:inline-flex}.stalux-social[data-stalux-social-animate=true] li{animation:.28s cubic-bezier(.2,.8,.2,1) both stalux-social-stalux-social-arrive}.stalux-social[data-stalux-social-animate=true] li:nth-child(2){animation-delay:30ms}.stalux-social[data-stalux-social-animate=true] li:nth-child(3){animation-delay:60ms}.stalux-social[data-stalux-social-animate=true] li:nth-child(4){animation-delay:90ms}.stalux-social[data-stalux-social-animate=true] li:nth-child(5){animation-delay:.12s}.stalux-social[data-stalux-social-animate=true] li:nth-child(6){animation-delay:.15s}.stalux-social[data-stalux-social-animate=true] li:nth-child(n+7){animation-delay:.18s}nav{width:100%;min-width:0;max-width:100%}html{scroll-padding-top:var(--stalux-nav-offset,var(--stalux-site-header-height))}.stalux-site-header{z-index:990;width:100%;min-height:var(--stalux-site-header-min-height);isolation:isolate;justify-content:center;align-items:center;display:flex;position:sticky;top:0}.stalux-nav-scroll-btn[data-visible]{pointer-events:auto;opacity:1}.stalux-nav-scroll-btn[data-side=left]{left:4px}.stalux-nav-scroll-btn[data-side=right]{right:4px}.stalux-nav-scroll-btn svg{stroke:currentColor;stroke-width:2px;fill:none;width:20px;height:20px}.stalux-nav-link,.stalux-nav-link:visited{cursor:pointer;width:100%;color:inherit;min-height:44px;font:inherit;background:0 0;border:none;align-items:center;gap:.5rem;padding:.5rem .75rem;text-decoration:none;display:flex}.stalux-nav-link .nav-icon{stroke:var(--white-full)}.stalux-nav-toggle svg{width:32px;height:32px}.stalux-nav-overlay[data-state=show]{pointer-events:auto;opacity:1;display:block}#stalux-to-archive-archs{margin-top:2em}#stalux-date-date-time{text-shadow:var(--stalux-text-shadow);color:var(--white-full);flex-direction:column;align-items:center;margin-top:2em;display:flex}#stalux-date-date-time #stalux-date-date{min-height:1.25em;margin-bottom:.5em;font-size:2em;line-height:1.25}#stalux-date-date-time #stalux-date-time{font-variant-numeric:tabular-nums;min-height:1.25em;font-size:3em;line-height:1.25}.stalux-author-figure{justify-content:center;align-items:center;display:flex}.stalux-author-figure img{box-shadow:0 0 10px var(--stalux-accent-color);border-radius:9999px;transition:transform .65s ease-in-out}.stalux-author-figure figcaption{text-shadow:var(--stalux-text-shadow);color:var(--white-full);margin-left:1em;font-size:2.5em;font-weight:700}.stalux-author-figure-column figcaption{text-align:center;margin-top:.5em;margin-left:0}.agent-home-summary{clip-path:inset(50%);white-space:normal;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.stalux-404-error-content h1{color:var(--white-90p);margin:0;font-size:6rem;font-weight:700}.stalux-404-error-content p{color:var(--white-70p);margin:1rem 0 2rem;font-size:1.5rem}.stalux-404-countdown-text{color:var(--white-50p)!important;margin:-.5rem 0 1.5rem!important;font-size:.95rem!important}.agent-recovery{max-width:42rem;line-height:1.7;margin:0 auto 1.5rem!important;font-size:1rem!important}.agent-recovery a{color:inherit;text-decoration-line:underline}.stalux-theme-info span,.stalux-copyright span{margin:0}.stalux-theme-info a{color:#fffc;margin:0 .2em;text-decoration:none;transition:color .3s}.stalux-beian-beian-info a{color:#ffffffb3;font-size:.9rem;text-decoration:none;transition:color .3s}.stalux-beian-public-security-beian img{width:15px;height:15px;display:inline-block}.stalux-badge-group-summary::-webkit-details-marker,.stalux-badge-group[open] .stalux-badge-group-hint[data-hint=collapsed],.stalux-badge-group:not([open]) .stalux-badge-group-hint[data-hint=expanded]{display:none}.stalux-badge-group[open] .stalux-badge-group-arrow{transform:rotate(90deg)}@media (hover:hover) and (pointer:fine){.stalux-card-post-tags a:hover .stalux-card-post-tag{background:var(--tag-bg-hover)}.stalux-card-post-categories a:hover .stalux-card-post-category{background:var(--category-bg-hover)}.stalux-post-card-shell:hover .stalux-post-card .stalux-card-post-cover img{transform:scale(1.025)}.stalux-post-card-shell:hover .stalux-post-card{box-shadow:var(--card-box-shadow-hover)}.stalux-nav-scroll-btn:hover{background:0 0}.stalux-nav-container:hover .stalux-nav-scroll-btn[data-visible]{opacity:1}.stalux-nav-link:hover .nav-icon,.stalux-nav-link:hover .stalux-nav-text{stroke:var(--stalux-accent-color);color:var(--stalux-accent-color)}.stalux-author-figure>a:hover img{animation:.65s ease-in-out stalux-link-avatar-spin}.stalux-404-home-btn:hover{background:var(--accent-20p);box-shadow:0 4px 12px var(--shadow-dark)}.stalux-theme-info a:hover{color:#fff;text-decoration:none}.stalux-beian-beian-info a:hover,.stalux-beian-public-security-beian:hover{color:#ffffffe6;text-decoration:none}.stalux-badge-group-summary:hover{color:var(--white-70p)}}@media (width>=601px){.stalux-site-nav{isolation:isolate;border-radius:0 0 16px 16px;transition:background-color .18s,box-shadow .18s}.stalux-site-nav[data-scrolled]{backdrop-filter:blur(20px)saturate(140%);box-shadow:0 1px 0 var(--white-10p), 0 8px 24px #0000001f;background:#181818c7}}@media (width<=1100px){.stalux-nav-list{gap:1rem}.stalux-nav-item{margin-left:.6em;margin-right:.6em;font-size:1em}}@media (width<=900px){.stalux-nav-item{margin-left:.25em;margin-right:.25em;font-size:.95em}.stalux-nav-list{gap:.5rem}}@media (width<=768px){.stalux-home-body{box-sizing:border-box;width:100%;max-width:95vw;height:auto;padding:2rem .5rem 1.5rem}.stalux-home-title{word-break:break-all;margin-top:1em;font-size:2em}#stalux-home-show-post-list{margin-top:2em;font-size:1.1em}.stalux-post-list-container ul{margin:1rem}.stalux-footer{padding:1.2rem 0;font-size:.8rem}.stalux-footer-content{gap:.6rem;padding:0 .8rem}.stalux-author{box-sizing:border-box;width:100%;max-width:95vw;margin-top:2em;padding:1em .5em}.stalux-author-figure{gap:.5em;flex-direction:column!important}.stalux-author-figure img{max-width:20vw;max-height:20vw;width:64px!important;height:64px!important}.stalux-author-figure figcaption{text-align:center;word-break:break-all;overflow-wrap:break-word;white-space:normal;max-width:90vw;margin-top:.5em;margin-left:0;font-size:1.5em}.stalux-404-error-content h1{font-size:4rem}.stalux-404-error-content p{font-size:1.2rem}.stalux-badges{gap:.3rem}.stalux-badge{width:auto}}@media (width<=600px){html{--stalux-site-header-min-height:4rem}.stalux-nav-toggle[data-state=open]{visibility:hidden;pointer-events:none}.stalux-nav-toggle[data-scrolled]{backdrop-filter:blur(20px)saturate(140%);box-shadow:0 1px 0 var(--white-10p), 0 8px 24px #0000001f;background:#181818c7;border-radius:12px}.stalux-nav-toggle{display:block;position:fixed;top:.75rem;left:.75rem}.stalux-nav-container{overflow:visible}nav{width:auto}.stalux-nav-list{pointer-events:none;z-index:1000;background:var(--black-20p);backdrop-filter:blur(20px);flex-direction:column;justify-content:flex-start;align-items:flex-start;gap:0;width:min(220px,100vw - 1rem);height:100vh;padding:.5rem 1rem 2rem;position:fixed;top:0;left:0;right:auto;overflow-y:auto;transform:translate(-100%)}.stalux-nav-list[data-state=open]{pointer-events:auto;transform:translate(0)}.stalux-nav-item{border-bottom:1px solid var(--white-10p);flex-shrink:0;width:100%;margin:0;font-size:.9em}.stalux-nav-text{display:inline}.stalux-nav-link{width:100%;min-height:44px;font-size:inherit;padding:.45rem .75rem}.stalux-nav-link .nav-icon{width:18px;height:18px}}@media (width<=480px){.stalux-footer{padding:1rem 0;font-size:.8rem}.stalux-footer-content{gap:.6rem;padding:0 .8rem}}@media (prefers-reduced-motion:reduce){.stalux-social[data-stalux-social-animate=true] li{animation:none}}.stalux-main,.stalux-post-page,.stalux-post-layout>*,.stalux-link-card-content,.stalux-word-list-item,.stalux-word-card{box-sizing:border-box;min-width:0;max-width:100%}.stalux-main{overflow-wrap:anywhere}.stalux-link-shell{min-width:0;max-width:100%;display:block}.stalux-link-card{box-sizing:border-box;width:100%;max-width:100%}.stalux-category-shell{width:100%;min-width:0}.stalux-author-figure>a{flex-shrink:0;display:inline-block}.stalux-author-figure img{display:block}.stalux-post-card-shell,.stalux-category-shell,.stalux-link-shell{position:relative}.stalux-post-card,.stalux-category-card,.stalux-link-card,.stalux-word-card{transition:transform .2s,background-color .2s,border-color .2s,box-shadow .2s}:is(.stalux-post-card-shell,.stalux-category-shell):focus-within>*,.stalux-link-shell:focus-visible>*{box-shadow:var(--card-box-shadow-hover)}:is(button,summary,[role=button]):focus-visible{outline:2px solid var(--stalux-accent-color);outline-offset:3px}@media (prefers-reduced-motion:reduce){.stalux-main *,.stalux-main :before,.stalux-main :after{transition-duration:0s!important;animation:none!important}.stalux-post-card,.stalux-category-card,.stalux-link-card,.stalux-link-card-content,.stalux-card-post-cover img,.stalux-category-icon,.stalux-author-figure img,.stalux-link-card-avatar img{transform:none!important}}@keyframes stalux-social-stalux-social-arrive{0%{opacity:0;transform:translateY(.75rem)rotate(-12deg)}to{opacity:1;transform:translateY(0)rotate(0)}}@keyframes stalux-random-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes stalux-link-avatar-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes stalux-word-word-glow{0%{box-shadow:0 0 30px var(--accent-50p), 0 0 80px var(--accent-30p), var(--shadow-lg);transform:scale(1.02)}to{box-shadow:0 0 20px var(--accent-40p), 0 0 60px var(--accent-20p), var(--shadow-lg);transform:scale(1)}}}@layer utilities{.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.visible{visibility:visible}.absolute{position:absolute}.static{position:static}.grid{display:grid}.block{display:block}.inline-block{display:inline-block}.hidden{display:none}.h-full{height:100%}.flex{display:flex}.flex-shrink{flex-shrink:1}.flex-wrap{flex-wrap:wrap}.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}.b,.border{border-width:1px}.text-inherit{color:inherit}.no-underline{text-decoration:none}.outline{outline-style:solid}}@layer theme;@layer base{html,body{color:#fff;width:100%;height:100%;margin:0;& main{flex:1}scrollbar-color:#4a4a4a #2a2a2a;font-family:var(--font-body), "Noto Sans SC", "Noto Sans CJK SC", system-ui, -apple-system, sans-serif;text-rendering:optimizelegibility;line-height:1.25;display:block}body{height:auto;min-height:100%}html{scrollbar-gutter:stable;background-color:var(--stalux-bg-color,#202020)}html[data-clarity-id]{opacity:1!important}a{color:inherit;cursor:pointer;text-decoration-skip-ink:auto;background-color:#0000;text-decoration:none;transition:color .2s,text-shadow .2s;position:relative}.a-none{cursor:pointer;text-decoration-skip-ink:auto;background-color:#0000;color:inherit!important;text-decoration:none!important}.a-none:after{display:none!important}a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):after{content:"";background:linear-gradient(90deg, var(--stalux-accent-color), var(--accent-50p));transform-origin:0;pointer-events:none;width:100%;height:1px;transition:transform .25s cubic-bezier(.25,.9,.2,1);position:absolute;bottom:-2px;left:0;transform:scaleX(0)}a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):focus-visible:after,a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):active:after{transform:scaleX(1)}@media (hover:hover) and (pointer:fine){a:not(.a-none):not([data-stalux-card]):not(.stalux-nav-link):hover:after{transform:scaleX(1)}}a:active,a:focus-visible{text-decoration:none}@media (hover:hover) and (pointer:fine){a:hover{text-decoration:none}}a:focus{outline:none}a:focus-visible{outline:2px solid var(--stalux-accent-color);outline-offset:2px}ul{margin:0;padding:0;list-style:none}.none{display:none}.stalux-root{color:#fff;min-height:100vh}.stalux-main{min-height:calc(100vh - var(--stalux-site-header-height,3rem))}:root{--stalux-bg-color:#202020;--stalux-bg-filter:none;--stalux-site-header-min-height:3.75rem;--stalux-site-header-height:var(--stalux-site-header-min-height);--stalux-text-shadow:var(--stalux-accent-color) .08rem .08rem .18rem;--stalux-accent-color:#eab308;--stalux-accent-rgb:234 179 8;--surface-glass:var(--black-05p);--surface-glass-shadow:var(--shadow-sidebar);--card-bg:var(--surface-glass);--card-border:#ffffff1a;--card-box-shadow:0 10px 24px #00000014;--card-box-shadow-hover:0 14px 28px #0000001f;--tag-bg:#ffffff1f;--tag-bg-hover:#ffffff2e;--category-bg:#ffffff14;--category-bg-hover:#ffffff24;--date-bg:#42a0ff2e;--date-border:#42a0ff40;--updated-bg:#ffc94733;--updated-border:#ffc9474d;--white-full:#fff;--white-95p:#fffffff2;--white-90p:#ffffffe6;--white-85p:#ffffffd9;--white-80p:#ffffffe6;--white-78p:#ffffffc7;--white-75p:#ffffffbf;--white-70p:#ffffffdb;--white-60p:#fff9;--white-50p:#ffffff80;--white-30p:#ffffff4d;--white-20p:#fff3;--white-15p:#ffffff26;--white-10p:#ffffff1a;--white-05p:#ffffff0d;--black-30p:#0000004d;--black-20p:#0003;--black-15p:#00000026;--black-10p:#0000001a;--black-05p:#0000000d;--accent-90p:rgb(var(--stalux-accent-rgb) / .9);--accent-85p:rgb(var(--stalux-accent-rgb) / .85);--accent-80p:rgb(var(--stalux-accent-rgb) / .8);--accent-70p:rgb(var(--stalux-accent-rgb) / .7);--accent-60p:rgb(var(--stalux-accent-rgb) / .6);--accent-50p:rgb(var(--stalux-accent-rgb) / .5);--accent-40p:rgb(var(--stalux-accent-rgb) / .4);--accent-30p:rgb(var(--stalux-accent-rgb) / .3);--accent-20p:rgb(var(--stalux-accent-rgb) / .2);--transition-fast:.18s ease;--transition-medium:.2s ease;--transition-normal:.25s ease;--transition-slow:.3s ease;--transition-slower:.5s ease;--transition-slowest:.6s ease;--easing-bounce:cubic-bezier(.175, .885, .32, 1.275);--space-2xs:.25rem;--space-xs:.75rem;--space-sm:.5rem;--space-md:1rem;--space-lg:1.5rem;--space-xl:2rem;--space-2xl:3rem;--space-3xl:4rem;--radius-sm:4px;--radius-md:6px;--radius-lg:8px;--radius-full:9999px;--shadow-sm:0 2px 5px #0000001a;--shadow-md:0 6px 16px #0003;--shadow-lg:0 8px 20px #0000004d;--shadow-xl:0 12px 26px #00000047;--shadow-sidebar:0 16px 20px -12px #000000d6, 10px 4px 16px -12px #00000094, -10px 4px 16px -12px #00000094;--shadow-raised-hover:0 20px 24px -13px #000000e6, 12px 5px 18px -13px #000000ad, -12px 5px 18px -13px #000000ad;--shadow-dark:#000000c0;--muted-text:#bbb;--font-body:"Noto Sans SC", "Noto Sans CJK SC", system-ui, sans-serif;--font-size-subtitle:1.35rem;--font-size-base:1.1rem;--font-size-small:.95rem;--font-size-smaller:.9rem;--font-size-tiny:.85rem;--border-thin:1px;--border-medium:2px;--border-thick:3px}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:#2a2a2a;border-radius:4px}::-webkit-scrollbar-thumb{background:#4a4a4a;border-radius:4px;transition:background .3s ease-out}@media (hover:hover) and (pointer:fine){::-webkit-scrollbar-thumb:hover{background:#5a5a5a}}::-webkit-scrollbar-corner{background:#2a2a2a}.bg-layer{z-index:-10;background-position:50%;background-repeat:repeat;background-size:auto;background-color:var(--stalux-bg-color,transparent);filter:var(--stalux-bg-filter,none);pointer-events:none;opacity:0;forced-color-adjust:none;color-scheme:light only;transition:opacity .65s ease-in-out;position:fixed;inset:0}@media (prefers-reduced-motion:reduce){.bg-layer{transition-duration:0s}}footer{padding:var(--space-lg) var(--space-md);text-align:center;color:var(--muted-text);border-top:1px solid var(--white-10p);backdrop-filter:blur(16px);background:linear-gradient(#0c0e122e,#0c0e12b8)}}@media print{[data-stalux-offscreen-code],[data-stalux-offscreen-svg]{content-visibility:visible!important;contain-intrinsic-block-size:none!important}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.stagger-children>:first-child{animation-delay:.1s}.stagger-children>:nth-child(2){animation-delay:.15s}.stagger-children>:nth-child(3){animation-delay:.2s}.stagger-children>:nth-child(4){animation-delay:.25s}.stagger-children>:nth-child(5){animation-delay:.3s}.stagger-children>:nth-child(n+6){animation-delay:.35s}html,[data-astro-transition-persist],.stalux-main,.stalux-main *,.bg-layer,.bg-layer *,[data-stalux-scroll-sentinel],[data-stalux-back-to-top]{view-transition-name:none!important}html[data-stalux-vt-preset] .stalux-main [data-stalux-motion-focus][data-stalux-motion-visible=true]{view-transition-name:stalux-focus!important}html[data-stalux-vt-preset=none] .stalux-main [data-stalux-motion-focus][data-stalux-motion-visible=true]{view-transition-name:none!important}::view-transition-group(stalux-focus){animation:none}::view-transition-image-pair(stalux-focus){isolation:auto}::view-transition-old(stalux-focus){animation:none;display:none}::view-transition-new(stalux-focus){mix-blend-mode:normal;animation:.12s cubic-bezier(.2,.7,.2,1) both stalux-focus-fade}html[data-stalux-vt-preset=enter]::view-transition-new(stalux-focus){animation:.16s cubic-bezier(.2,.7,.2,1) both stalux-focus-enter}html[data-stalux-vt-preset=up]::view-transition-new(stalux-focus){animation:.14s cubic-bezier(.2,.7,.2,1) both stalux-focus-up}html[data-stalux-vt-preset=taxonomy]::view-transition-new(stalux-focus){animation:.14s cubic-bezier(.2,.7,.2,1) both stalux-focus-fade}html[data-stalux-vt-preset=previous]::view-transition-new(stalux-focus){animation:.16s cubic-bezier(.2,.7,.2,1) both stalux-focus-previous}html[data-stalux-vt-preset=next]::view-transition-new(stalux-focus){animation:.16s cubic-bezier(.2,.7,.2,1) both stalux-focus-next}html[data-stalux-vt-preset=home]::view-transition-new(stalux-focus){animation:.18s cubic-bezier(.2,.7,.2,1) both stalux-focus-home}html[data-stalux-vt-preset=restore]::view-transition-new(stalux-focus){animation:.1s cubic-bezier(.2,.7,.2,1) both stalux-focus-restore}html[data-stalux-vt-preset=error]::view-transition-new(stalux-focus){animation:.1s cubic-bezier(.2,.7,.2,1) both stalux-focus-fade}@keyframes stalux-focus-fade{0%{opacity:.86}to{opacity:1}}@keyframes stalux-focus-enter{0%{opacity:.86;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes stalux-focus-up{0%{opacity:.9;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes stalux-focus-previous{0%{opacity:.9;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-focus-next{0%{opacity:.9;transform:translate(8px)}to{opacity:1;transform:translate(0)}}@keyframes stalux-focus-home{0%{opacity:.9;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes stalux-focus-restore{0%{opacity:.96}to{opacity:1}}@keyframes stalux-page-exit{0%{opacity:1}to{opacity:1}}@keyframes stalux-page-enter{0%{opacity:.9}to{opacity:1}}@keyframes stalux-page-enter-back{0%{opacity:.96}to{opacity:1}}@keyframes stalux-taxonomy-enter{0%{opacity:.9}to{opacity:1}}@keyframes stalux-taxonomy-enter-back{0%{opacity:.96}to{opacity:1}}@keyframes stalux-article-enter{0%{opacity:.9}to{opacity:1}}@keyframes stalux-article-enter-back{0%{opacity:.96}to{opacity:1}}@keyframes stalux-sidebar-left-in{0%{opacity:.96}to{opacity:1}}@keyframes stalux-sidebar-left-out{0%{opacity:1}to{opacity:1}}@keyframes stalux-sidebar-left-back-in{0%{opacity:.96}to{opacity:1}}@keyframes stalux-sidebar-left-back-out{0%{opacity:1}to{opacity:1}}@keyframes stalux-sidebar-right-in{0%{opacity:.96}to{opacity:1}}@keyframes stalux-sidebar-right-out{0%{opacity:1}to{opacity:1}}@keyframes stalux-sidebar-right-back-in{0%{opacity:.96}to{opacity:1}}@keyframes stalux-sidebar-right-back-out{0%{opacity:1}to{opacity:1}}[data-stalux-scroll-sentinel]{visibility:hidden;pointer-events:none;width:1px;height:1px;position:absolute;top:240px;left:0}@media (width<=768px){html[data-stalux-vt-preset]::view-transition-new(stalux-focus){animation:.12s cubic-bezier(.2,.7,.2,1) both stalux-focus-fade}html[data-stalux-vt-preset=restore]::view-transition-new(stalux-focus){animation:.1s cubic-bezier(.2,.7,.2,1) both stalux-focus-restore}}@media (prefers-reduced-motion:reduce){html[data-stalux-vt-preset] .stalux-main [data-stalux-motion-focus][data-stalux-motion-visible=true]{view-transition-name:none!important}::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){filter:none!important;animation:none!important;transform:none!important}.stalux-main,.stalux-main *,.postLayout *{scroll-behavior:auto!important;transition-duration:1ms!important;animation-duration:1ms!important;animation-iteration-count:1!important}}
3
3
  /*$vite$:1*/
@@ -28,287 +28,311 @@
28
28
  animation-delay: 0.35s;
29
29
  }
30
30
 
31
- /* =========================================================
32
- View Transitions:主内容 slide + 淡入 + 新内容 scale+blur 到清晰,
33
- 与 Astro 默认的纯淡入淡出不同 — 旧内容沿方向快速滑出,新内容对向滑入
34
- 带轻微 scale 从 0.985 拉回 1,配合 1.2px blur 再还原。
35
- forwards (direction = "forward" | "push"): 旧内容向左滑出,新内容从右滑入
36
- backwards (direction = "back" | "traverse"): 镜像方向
37
- 持久壳层(header、footer、背景、sentinel、back-to-top 按钮)设
38
- view-transition-name: none 保留 DOM、不参与原生动画;标题/侧边栏/
39
- 卡片标题用局部 transition:animate 独立配置,与 root 伪元素分层。
40
- 方向值(forward | back)由 view-transitions.ts 写入 CSS 变量
41
- --stalux-vt-old / --stalux-vt-new,伪元素继承后用 animation-name 切换。
42
- ========================================================= */
43
-
44
- /* 标题 / 卡片标题交叉淡入 + 轻微缩放:让列表→详情的同名元素有“形态连续感” */
45
- @keyframes stalux-vt-title-swap-old {
46
- to {
47
- opacity: 0;
48
- transform: scale(0.94);
49
- filter: blur(2px);
50
- }
31
+ /* Route motion captures one visible heading, never a long main/article.
32
+ The router owns data-stalux-vt-preset and confirms visibility once per DOM.
33
+ Keep literal keyframe references: production CSS removes unreferenced frames. */
34
+ html,
35
+ [data-astro-transition-persist],
36
+ .stalux-main,
37
+ .stalux-main *,
38
+ .bg-layer,
39
+ .bg-layer *,
40
+ [data-stalux-scroll-sentinel],
41
+ [data-stalux-back-to-top] {
42
+ view-transition-name: none !important;
43
+ }
44
+
45
+ html[data-stalux-vt-preset]
46
+ .stalux-main
47
+ [data-stalux-motion-focus][data-stalux-motion-visible="true"] {
48
+ view-transition-name: stalux-focus !important;
49
+ }
50
+
51
+ html[data-stalux-vt-preset="none"]
52
+ .stalux-main
53
+ [data-stalux-motion-focus][data-stalux-motion-visible="true"] {
54
+ view-transition-name: none !important;
55
+ }
56
+
57
+ /* Different headings must not interpolate width, height, position or text size.
58
+ Old content stays readable until swap; only the small new heading animates. */
59
+ ::view-transition-group(stalux-focus) {
60
+ animation: none;
61
+ }
62
+
63
+ ::view-transition-image-pair(stalux-focus) {
64
+ isolation: auto;
65
+ }
66
+
67
+ ::view-transition-old(stalux-focus) {
68
+ display: none;
69
+ animation: none;
51
70
  }
52
71
 
53
- @keyframes stalux-vt-title-swap-new {
72
+ ::view-transition-new(stalux-focus) {
73
+ mix-blend-mode: normal;
74
+ animation: stalux-focus-fade 120ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
75
+ }
76
+
77
+ html[data-stalux-vt-preset="enter"]::view-transition-new(stalux-focus) {
78
+ animation: stalux-focus-enter 160ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
79
+ }
80
+
81
+ html[data-stalux-vt-preset="up"]::view-transition-new(stalux-focus) {
82
+ animation: stalux-focus-up 140ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
83
+ }
84
+
85
+ html[data-stalux-vt-preset="taxonomy"]::view-transition-new(stalux-focus) {
86
+ animation: stalux-focus-fade 140ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
87
+ }
88
+
89
+ html[data-stalux-vt-preset="previous"]::view-transition-new(stalux-focus) {
90
+ animation: stalux-focus-previous 160ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
91
+ }
92
+
93
+ html[data-stalux-vt-preset="next"]::view-transition-new(stalux-focus) {
94
+ animation: stalux-focus-next 160ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
95
+ }
96
+
97
+ html[data-stalux-vt-preset="home"]::view-transition-new(stalux-focus) {
98
+ animation: stalux-focus-home 180ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
99
+ }
100
+
101
+ html[data-stalux-vt-preset="restore"]::view-transition-new(stalux-focus) {
102
+ animation: stalux-focus-restore 100ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
103
+ }
104
+
105
+ html[data-stalux-vt-preset="error"]::view-transition-new(stalux-focus) {
106
+ animation: stalux-focus-fade 100ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
107
+ }
108
+
109
+ @keyframes stalux-focus-fade {
54
110
  from {
55
- opacity: 0;
56
- transform: scale(1.05);
57
- filter: blur(2px);
58
- }
59
- 70% {
60
- transform: scale(0.98);
61
- filter: blur(0px);
111
+ opacity: 0.86;
62
112
  }
63
113
  to {
64
114
  opacity: 1;
65
- transform: scale(1);
66
- filter: blur(0px);
67
115
  }
68
116
  }
69
117
 
70
- /* 主内容 View Transition 动画。
71
- ⚠ 约束 1:::view-transition-old() / ::view-transition-new() 属于独立 UA 伪元素树,
72
- 与 <html> 之间**没有祖先选择器关系**。
73
- ⚠ 约束 2:CSS 变量 fallback 字符串(`var(--x, keyframesName)`)不会被 Rolldown
74
- tree-shake 静态追踪 —— fallback 里的 keyframes 名会被判断为"没被引用"而裁掉。
75
- 所以伪元素规则必须写成**直接引用 keyframes 的完整 animation shorthand**。
76
- ⚠ 约束 3:方向切换暂时放弃(祖先选择器命不中伪元素),backward 暂不镜像。
77
- 后续可用 WAAPI 运行时覆盖伪元素 keyframes 实现方向切换。 */
78
-
79
- @keyframes stalux-vt-old-route {
80
- 0% {
81
- opacity: 1;
82
- transform: translate3d(0, 0, 0);
83
- }
84
- 45% {
85
- opacity: 0.5;
118
+ @keyframes stalux-focus-enter {
119
+ from {
120
+ opacity: 0.86;
121
+ transform: translateY(6px);
86
122
  }
87
- 100% {
88
- opacity: 0;
89
- transform: translate3d(-6%, 0, 0);
123
+ to {
124
+ opacity: 1;
125
+ transform: translateY(0);
90
126
  }
91
127
  }
92
128
 
93
- @keyframes stalux-vt-new-route {
94
- 0% {
95
- opacity: 0;
96
- transform: translate3d(6%, 0, 0) scale(0.985);
97
- filter: blur(1.2px);
98
- }
99
- 60% {
129
+ @keyframes stalux-focus-up {
130
+ from {
100
131
  opacity: 0.9;
101
- transform: translate3d(-0.8%, 0, 0) scale(1);
102
- filter: blur(0px);
132
+ transform: translateY(-4px);
103
133
  }
104
- 100% {
134
+ to {
105
135
  opacity: 1;
106
- transform: translate3d(0, 0, 0);
107
- filter: blur(0px);
136
+ transform: translateY(0);
108
137
  }
109
138
  }
110
139
 
111
- ::view-transition-old(stalux-page) {
112
- animation: stalux-vt-old-route 380ms cubic-bezier(0.22, 0.72, 0.22, 1) both;
113
- }
114
-
115
- ::view-transition-new(stalux-page) {
116
- animation: stalux-vt-new-route 460ms cubic-bezier(0.22, 0.72, 0.22, 1) both;
140
+ @keyframes stalux-focus-previous {
141
+ from {
142
+ opacity: 0.9;
143
+ transform: translateX(-8px);
144
+ }
145
+ to {
146
+ opacity: 1;
147
+ transform: translateX(0);
148
+ }
117
149
  }
118
150
 
119
- /* 标题交叉淡入:列表→详情 / 详情→详情 之间同名标题共享 transition:name 时
120
- 用一套独立动画(比 root 更快、更有“形态感”)。
121
- 注意:::view-transition-old/new 伪元素里不能放属性选择器(MDN 明确只接受
122
- 自定义 transition-name 字符串和 * 通配;属性选择器属于 legacy 浏览器实验
123
- 语法,lightningcss minify 不支持)。 */
124
- ::view-transition-old(stalux-post-title) {
125
- animation: stalux-vt-title-swap-old 260ms cubic-bezier(0.22, 0.72, 0.22, 1) both;
151
+ @keyframes stalux-focus-next {
152
+ from {
153
+ opacity: 0.9;
154
+ transform: translateX(8px);
155
+ }
156
+ to {
157
+ opacity: 1;
158
+ transform: translateX(0);
159
+ }
126
160
  }
127
161
 
128
- ::view-transition-new(stalux-post-title) {
129
- animation: stalux-vt-title-swap-new 320ms cubic-bezier(0.22, 0.72, 0.22, 1) both;
162
+ @keyframes stalux-focus-home {
163
+ from {
164
+ opacity: 0.9;
165
+ transform: translateY(4px);
166
+ }
167
+ to {
168
+ opacity: 1;
169
+ transform: translateY(0);
170
+ }
130
171
  }
131
172
 
132
- /* 侧边栏 — 独立于 root:沿内容方向做 12px 平移 + 淡入淡出,
133
- 让文章详情页左右栏与主内容分层出现。 */
134
- @keyframes stalux-vt-side-out {
173
+ @keyframes stalux-focus-restore {
174
+ from {
175
+ opacity: 0.96;
176
+ }
135
177
  to {
136
- opacity: 0;
137
- transform: translate3d(var(--stalux-side-out-x, -14px), 0, 0);
178
+ opacity: 1;
138
179
  }
139
180
  }
140
181
 
141
- @keyframes stalux-vt-side-in {
182
+ /* Public transition helpers retain their names as opacity-only compatibility
183
+ frames. Theme layouts no longer use them to move large content/sidebars. */
184
+ @keyframes stalux-page-exit {
142
185
  from {
143
- opacity: 0;
144
- transform: translate3d(var(--stalux-side-in-x, 14px), 0, 0);
186
+ opacity: 1;
145
187
  }
146
188
  to {
147
189
  opacity: 1;
148
- transform: translate3d(0, 0, 0);
149
190
  }
150
191
  }
151
-
152
- /* 持久壳层:header、背景、sentinel、back-to-top 按钮不参与 View Transition 伪元素;
153
- 直接设 view-transition-name: none 让浏览器为它们各自做即时更新。
154
- 这避免了原生快照把大体积 header 或整张背景图塞进 pseudo-element 树、
155
- 也与 view-transitions.ts 里的 .scrollY 优化保持一致 — 不强制 UI 同步。 */
156
- html,
157
- .stalux-main,
158
- .stalux-main *,
159
- [data-astro-transition-persist],
160
- [data-stalux-site-header],
161
- [data-stalux-site-header] *,
162
- .bg-layer,
163
- .bg-layer *,
164
- [data-stalux-scroll-sentinel],
165
- [data-stalux-scroll-sentinel] *,
166
- [data-stalux-back-to-top],
167
- [data-stalux-back-to-top] * {
168
- view-transition-name: none !important;
192
+ @keyframes stalux-page-enter {
193
+ from {
194
+ opacity: 0.9;
195
+ }
196
+ to {
197
+ opacity: 1;
198
+ }
169
199
  }
170
-
171
- /* BackToTop visibility sentinel */
172
- [data-stalux-scroll-sentinel] {
173
- position: absolute;
174
- top: 240px;
175
- left: 0;
176
- width: 1px;
177
- height: 1px;
178
- visibility: hidden;
179
- pointer-events: none;
200
+ @keyframes stalux-page-enter-back {
201
+ from {
202
+ opacity: 0.96;
203
+ }
204
+ to {
205
+ opacity: 1;
206
+ }
180
207
  }
181
-
182
- /* =========================================================
183
- 下面保留的是 Astro transition:animate 用的 web 动画 keyframes,
184
- 供 getSidebarAnimation("left"|"right") 和分类/文章页内局部
185
- transition:animate 消费;与 View Transition 伪元素层互不冲突。
186
- ========================================================= */
187
-
188
208
  @keyframes stalux-taxonomy-enter {
189
209
  from {
190
- opacity: 0;
191
- transform: translateX(12px);
210
+ opacity: 0.9;
192
211
  }
193
212
  to {
194
213
  opacity: 1;
195
- transform: translateX(0);
196
214
  }
197
215
  }
198
-
199
216
  @keyframes stalux-taxonomy-enter-back {
200
217
  from {
201
- opacity: 0;
202
- transform: translateX(-12px);
218
+ opacity: 0.96;
203
219
  }
204
220
  to {
205
221
  opacity: 1;
206
- transform: translateX(0);
207
222
  }
208
223
  }
209
-
210
224
  @keyframes stalux-article-enter {
211
225
  from {
212
- opacity: 0;
213
- transform: translateY(6px);
226
+ opacity: 0.9;
214
227
  }
215
228
  to {
216
229
  opacity: 1;
217
- transform: translateY(0);
218
230
  }
219
231
  }
220
-
221
232
  @keyframes stalux-article-enter-back {
222
233
  from {
223
- opacity: 0;
224
- transform: translateY(-6px);
234
+ opacity: 0.96;
225
235
  }
226
236
  to {
227
237
  opacity: 1;
228
- transform: translateY(0);
229
238
  }
230
239
  }
231
-
232
240
  @keyframes stalux-sidebar-left-in {
233
241
  from {
234
- opacity: 0;
235
- transform: translateX(-14px);
242
+ opacity: 0.96;
236
243
  }
237
244
  to {
238
245
  opacity: 1;
239
- transform: translateX(0);
240
246
  }
241
247
  }
242
-
243
248
  @keyframes stalux-sidebar-left-out {
249
+ from {
250
+ opacity: 1;
251
+ }
244
252
  to {
245
- opacity: 0;
246
- transform: translateX(-10px);
253
+ opacity: 1;
247
254
  }
248
255
  }
249
-
250
256
  @keyframes stalux-sidebar-left-back-in {
251
257
  from {
252
- opacity: 0;
253
- transform: translateX(14px);
258
+ opacity: 0.96;
254
259
  }
255
260
  to {
256
261
  opacity: 1;
257
- transform: translateX(0);
258
262
  }
259
263
  }
260
-
261
264
  @keyframes stalux-sidebar-left-back-out {
265
+ from {
266
+ opacity: 1;
267
+ }
262
268
  to {
263
- opacity: 0;
264
- transform: translateX(10px);
269
+ opacity: 1;
265
270
  }
266
271
  }
267
-
268
272
  @keyframes stalux-sidebar-right-in {
269
273
  from {
270
- opacity: 0;
271
- transform: translateX(14px);
274
+ opacity: 0.96;
272
275
  }
273
276
  to {
274
277
  opacity: 1;
275
- transform: translateX(0);
276
278
  }
277
279
  }
278
-
279
280
  @keyframes stalux-sidebar-right-out {
281
+ from {
282
+ opacity: 1;
283
+ }
280
284
  to {
281
- opacity: 0;
282
- transform: translateX(10px);
285
+ opacity: 1;
283
286
  }
284
287
  }
285
-
286
288
  @keyframes stalux-sidebar-right-back-in {
287
289
  from {
288
- opacity: 0;
289
- transform: translateX(-14px);
290
+ opacity: 0.96;
290
291
  }
291
292
  to {
292
293
  opacity: 1;
293
- transform: translateX(0);
294
294
  }
295
295
  }
296
-
297
296
  @keyframes stalux-sidebar-right-back-out {
297
+ from {
298
+ opacity: 1;
299
+ }
298
300
  to {
299
- opacity: 0;
300
- transform: translateX(-10px);
301
+ opacity: 1;
302
+ }
303
+ }
304
+
305
+ [data-stalux-scroll-sentinel] {
306
+ position: absolute;
307
+ top: 240px;
308
+ left: 0;
309
+ width: 1px;
310
+ height: 1px;
311
+ visibility: hidden;
312
+ pointer-events: none;
313
+ }
314
+
315
+ /* Small screens get the same deterministic timing with no spatial motion. */
316
+ @media (max-width: 768px) {
317
+ html[data-stalux-vt-preset]::view-transition-new(stalux-focus) {
318
+ animation: stalux-focus-fade 120ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
319
+ }
320
+ html[data-stalux-vt-preset="restore"]::view-transition-new(stalux-focus) {
321
+ animation: stalux-focus-restore 100ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
301
322
  }
302
323
  }
303
324
 
304
- /* prefers-reduced-motion:关闭 View Transition 伪元素上的所有动画,
305
- 但保留伪元素本身(浏览器会直接从 old 切到 new,视觉等价于无动画的软导航) */
306
325
  @media (prefers-reduced-motion: reduce) {
326
+ html[data-stalux-vt-preset]
327
+ .stalux-main
328
+ [data-stalux-motion-focus][data-stalux-motion-visible="true"] {
329
+ view-transition-name: none !important;
330
+ }
331
+
307
332
  ::view-transition-group(*),
308
333
  ::view-transition-old(*),
309
334
  ::view-transition-new(*) {
310
- animation-duration: 1ms !important;
311
- animation-delay: 0ms !important;
335
+ animation: none !important;
312
336
  filter: none !important;
313
337
  transform: none !important;
314
338
  }
@@ -0,0 +1,63 @@
1
+ import { getRouteKind, normalizePublicPath } from "./public-routes";
2
+
3
+ export type RouteMotionPreset =
4
+ | "none"
5
+ | "fade"
6
+ | "enter"
7
+ | "up"
8
+ | "taxonomy"
9
+ | "previous"
10
+ | "next"
11
+ | "home"
12
+ | "restore"
13
+ | "error";
14
+
15
+ interface MotionContext {
16
+ from: URL;
17
+ to: URL;
18
+ navigationType?: string;
19
+ intent?: string;
20
+ reducedMotion?: boolean;
21
+ browserMotion?: boolean;
22
+ hidden?: boolean;
23
+ }
24
+
25
+ /** Choose a visual hint, never a navigation or scroll operation. */
26
+ export function getRouteMotionPreset(context: MotionContext): RouteMotionPreset {
27
+ const { from, to } = context;
28
+ const source = getRouteKind(from.pathname);
29
+ const target = getRouteKind(to.pathname);
30
+ if (
31
+ context.hidden ||
32
+ context.reducedMotion ||
33
+ context.browserMotion ||
34
+ from.origin !== to.origin ||
35
+ source === "other" ||
36
+ target === "other" ||
37
+ (normalizePublicPath(from.pathname) === normalizePublicPath(to.pathname) &&
38
+ from.search === to.search)
39
+ ) {
40
+ return "none";
41
+ }
42
+ // Both directions restore an existing history entry. A push to a parent
43
+ // route is not a history traversal, and an article's previous/next is not back.
44
+ if (context.navigationType === "traverse") return "restore";
45
+ if (context.navigationType === "replace") return "fade";
46
+ if (target === "not-found") return "error";
47
+ if (source === "not-found") return "fade";
48
+ if (target === "home") return "home";
49
+ if (source === "article" && target === "article") {
50
+ return context.intent === "previous" || context.intent === "next" ? context.intent : "fade";
51
+ }
52
+ if (target === "article") return "enter";
53
+ if (target === "tags-detail" || target === "categories-detail") return "taxonomy";
54
+ if (
55
+ (source === "article" &&
56
+ (target === "archive" || target === "tags-index" || target === "categories-index")) ||
57
+ (source === "tags-detail" && target === "tags-index") ||
58
+ (source === "categories-detail" && target === "categories-index")
59
+ ) {
60
+ return "up";
61
+ }
62
+ return source === "home" ? "enter" : "fade";
63
+ }
@@ -35,10 +35,10 @@ export type RouteAnimation = {
35
35
  };
36
36
  };
37
37
 
38
- const easing = "cubic-bezier(0.22, 0.72, 0.22, 1)";
38
+ const easing = "cubic-bezier(0.2, 0.7, 0.2, 1)";
39
39
  const exitAnimation: TransitionAnimation = {
40
40
  name: "stalux-page-exit",
41
- duration: "0.14s",
41
+ duration: "0.1s",
42
42
  easing,
43
43
  fillMode: "both",
44
44
  };
@@ -49,7 +49,7 @@ function createRouteAnimation(name: string, backName = `${name}-back`): RouteAni
49
49
  old: exitAnimation,
50
50
  new: {
51
51
  name: productionStyleName(`stalux-${name}`),
52
- duration: "0.22s",
52
+ duration: "0.16s",
53
53
  easing,
54
54
  fillMode: "both",
55
55
  },
@@ -58,7 +58,7 @@ function createRouteAnimation(name: string, backName = `${name}-back`): RouteAni
58
58
  old: exitAnimation,
59
59
  new: {
60
60
  name: productionStyleName(`stalux-${backName}`),
61
- duration: "0.22s",
61
+ duration: "0.16s",
62
62
  easing,
63
63
  fillMode: "both",
64
64
  },
@@ -92,7 +92,7 @@ function createSidebarAnimation(
92
92
  ): TransitionAnimation {
93
93
  return {
94
94
  name: productionStyleName(`stalux-sidebar-${side}-${backwards ? "back-" : ""}${phase}`),
95
- duration: "0.22s",
95
+ duration: "0.16s",
96
96
  easing,
97
97
  fillMode: "both",
98
98
  };