@windcoder/astro-theme-orchid 0.3.0 → 0.4.1

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.
@@ -191,6 +191,35 @@ html.dark a:hover {
191
191
  backdrop-filter: blur(14px);
192
192
  border-bottom: 1px solid var(--border);
193
193
  }
194
+ /* 壁纸导航栏透明形态(§4.98):html[data-wallpaper-nav] = semi/semifull/full/solid,
195
+ solid 走上方基础规则无需覆盖;wp-scrolled 由 app.ts 滚动监听切换 */
196
+ html[data-wallpaper-nav="semi"] .site-header {
197
+ background: color-mix(in srgb, var(--bg) 55%, transparent);
198
+ -webkit-backdrop-filter: blur(var(--wp-nav-blur, 5px));
199
+ backdrop-filter: blur(var(--wp-nav-blur, 5px));
200
+ border-bottom-color: transparent;
201
+ }
202
+ html[data-wallpaper-nav="semi"].wp-scrolled .site-header,
203
+ html[data-wallpaper-nav="semifull"].wp-scrolled .site-header {
204
+ background: color-mix(in srgb, var(--bg) 78%, transparent);
205
+ -webkit-backdrop-filter: blur(14px);
206
+ backdrop-filter: blur(14px);
207
+ border-bottom-color: var(--border);
208
+ }
209
+ html[data-wallpaper-nav="semifull"] .site-header,
210
+ html[data-wallpaper-nav="full"] .site-header {
211
+ background: transparent;
212
+ -webkit-backdrop-filter: none;
213
+ backdrop-filter: none;
214
+ border-bottom-color: transparent;
215
+ }
216
+ /* 移动端菜单展开时强制实底,保证导航可读性(特异性高于形态规则) */
217
+ html[data-wallpaper-nav] .site-header:has(.site-nav.open) {
218
+ background: color-mix(in srgb, var(--bg) 92%, transparent);
219
+ -webkit-backdrop-filter: blur(14px);
220
+ backdrop-filter: blur(14px);
221
+ border-bottom-color: var(--border);
222
+ }
194
223
  .header-inner {
195
224
  display: flex;
196
225
  align-items: center;
@@ -651,31 +680,360 @@ html.dark #modeToggle .i-sun {
651
680
  color: var(--muted);
652
681
  text-align: center;
653
682
  }
683
+ /* §4.104 浮层超出上限时的「查看全部 N 条结果」入口 */
684
+ .search-more {
685
+ display: block;
686
+ padding: 11px 14px;
687
+ border-top: 1px solid var(--border);
688
+ background: var(--bg-soft);
689
+ text-align: center;
690
+ font-size: 13px;
691
+ color: var(--accent-ink);
692
+ transition: background-color 0.15s;
693
+ }
694
+ .search-more:hover {
695
+ background: var(--accent-soft);
696
+ }
654
697
 
655
- /* ---------- 3.5 背景壁纸(§4.35,banner 单模式) ---------- */
656
- /* Header 为 sticky 且背景半透明 + 毛玻璃:负 margin 让横幅上缘滑入 Header 底下 */
657
- .wallpaper-banner {
698
+ /* ---------- 独立搜索页(§4.104,/search/):静态外壳 + 客户端查询分页 ---------- */
699
+ .search-page {
700
+ max-width: 760px;
701
+ margin: 0 auto;
702
+ }
703
+ .search-page-bar {
704
+ display: flex;
705
+ align-items: center;
706
+ gap: 10px;
707
+ height: 46px;
708
+ padding: 0 16px;
709
+ border: 1px solid var(--border);
710
+ border-radius: 12px;
711
+ background: var(--surface);
712
+ color: var(--muted);
713
+ transition:
714
+ border-color 0.15s,
715
+ color 0.15s;
716
+ }
717
+ .search-page-bar:focus-within {
718
+ border-color: var(--accent-ink);
719
+ color: var(--ink-2);
720
+ }
721
+ .search-page-bar svg {
722
+ width: 18px;
723
+ height: 18px;
724
+ flex: none;
725
+ }
726
+ .search-page-bar input {
727
+ flex: 1;
728
+ min-width: 0;
729
+ border: none;
730
+ outline: none;
731
+ background: transparent;
732
+ font: inherit;
733
+ font-size: 16px;
734
+ color: var(--ink);
735
+ }
736
+ .search-page-bar input::placeholder {
737
+ color: var(--muted);
738
+ }
739
+ .search-page-bar input::-webkit-search-cancel-button {
740
+ -webkit-appearance: none;
741
+ }
742
+ .search-page-meta {
743
+ margin-top: 14px;
744
+ font-size: 13px;
745
+ color: var(--muted);
746
+ }
747
+ .search-page-results {
748
+ margin-top: 4px;
749
+ }
750
+ .search-page-results .search-item {
751
+ padding: 14px 4px;
752
+ }
753
+ .search-page-results .search-item:hover {
754
+ background: transparent;
755
+ }
756
+ .search-page-results .search-item:hover .search-item-title {
757
+ color: var(--accent-ink);
758
+ }
759
+ .search-page-results .search-item-title {
760
+ font-size: 15.5px;
761
+ font-weight: 600;
762
+ }
763
+ .search-page-results .search-item-excerpt {
764
+ margin-top: 4px;
765
+ font-size: 13px;
766
+ -webkit-line-clamp: 3;
767
+ }
768
+
769
+ /* ---------- 3.5 统一壁纸体系(§4.98):单一 .wp-stage + html[data-wallpaper-mode] 四形态 ---------- */
770
+ /* 形态语义:
771
+ banner 横幅——文档流内定高,负 margin 让上缘滑入 sticky Header 底下;
772
+ fullscreen 全屏首屏——文档流内 100vh,同样负 margin;
773
+ overlay 覆盖透明——fixed 垫底(z-index:-1),正文卡片按 --wp-card-opacity 半透明透出壁纸;
774
+ none 纯色——stage display:none,页面回退 body 画布底色 */
775
+ .wp-stage {
658
776
  position: relative;
659
- height: var(--banner-h, 32vh);
660
- margin-top: calc(-1 * var(--header-h));
661
777
  overflow: hidden;
662
778
  }
663
- .wallpaper-banner img {
664
- display: block;
779
+ html[data-wallpaper-mode="banner"] .wp-stage {
780
+ height: var(--banner-h, 60vh);
781
+ margin-top: calc(-1 * var(--header-h));
782
+ }
783
+ /* fullscreen 首页独占一屏;非首页降级(§4.98):classic→banner 高度,hero→overlay fixed 垫底 */
784
+ html[data-wallpaper-mode="fullscreen"][data-wp-is-home] .wp-stage {
785
+ height: 100vh;
786
+ margin-top: calc(-1 * var(--header-h));
787
+ }
788
+ html[data-wallpaper-mode="fullscreen"]:not([data-wp-is-home]):not(
789
+ [data-wp-fs-layout="hero"]
790
+ )
791
+ .wp-stage {
792
+ height: var(--banner-h, 60vh);
793
+ margin-top: calc(-1 * var(--header-h));
794
+ }
795
+ html[data-wallpaper-mode="fullscreen"]:not(
796
+ [data-wp-is-home]
797
+ )[data-wp-fs-layout="hero"]
798
+ .wp-stage {
799
+ position: fixed;
800
+ inset: 0;
801
+ height: auto;
802
+ margin-top: 0;
803
+ z-index: -1;
804
+ pointer-events: none;
805
+ opacity: var(--wp-overlay-opacity, 0.8);
806
+ }
807
+ /* overlay:fixed 垫底叠在 body 传播的画布底色之上、内容之下;整体 opacity 控制透出强度 */
808
+ html[data-wallpaper-mode="overlay"] .wp-stage {
809
+ position: fixed;
810
+ inset: 0;
811
+ z-index: -1;
812
+ pointer-events: none;
813
+ opacity: var(--wp-overlay-opacity, 0.8);
814
+ }
815
+ /* none 模式与 homeOnly 非首页:banner/fullscreen 形态下不渲染(overlay 天然全站忽略隐藏) */
816
+ html[data-wallpaper-mode="none"] .wp-stage,
817
+ html[data-wallpaper-mode="banner"] .wp-stage[data-wallpaper-hidden],
818
+ html[data-wallpaper-mode="fullscreen"] .wp-stage[data-wallpaper-hidden] {
819
+ display: none;
820
+ }
821
+
822
+ /* 底部衔接(§4.98 banner / fullscreen-classic,对齐 Firefly 首屏布局):
823
+ 内容区上拉 --wp-overlap 覆盖 stage 底缘,分类导航条半压壁纸;
824
+ stage 底部 ::after 渐隐(透明 → var(--bg)),壁纸自然过渡到正文纯色背景。
825
+ hero 布局(fixed 整屏 + 100vh 下推)与 overlay(fixed 全站垫底)不适用;
826
+ stage 隐藏(homeOnly 非首页 / JS 切走)时取消上拉,避免正文被 sticky Header 裁切 */
827
+ /* 仅 banner 与非首页 fullscreen-classic 上拉;fullscreen 首页独占一屏不上拉 */
828
+ html[data-wallpaper-mode="banner"]:not([data-wp-stage-hidden]) .site-main,
829
+ html[data-wallpaper-mode="fullscreen"]:not([data-wp-is-home]):not(
830
+ [data-wp-fs-layout="hero"]
831
+ ):not([data-wp-stage-hidden])
832
+ .site-main {
833
+ /* 上拉后与 stage 产生重叠:stage 是 positioned(z-auto),card 多为 static 会被其盖住;
834
+ 给 main 补 position 使其按 DOM 序(stage 前 main 后)压回壁纸之上 */
835
+ position: relative;
836
+ margin-top: calc(-1 * var(--wp-overlap, 64px));
837
+ }
838
+ html[data-wallpaper-mode="banner"] .wp-stage::after,
839
+ html[data-wallpaper-mode="fullscreen"]:not([data-wp-is-home]):not(
840
+ [data-wp-fs-layout="hero"]
841
+ )
842
+ .wp-stage::after {
843
+ content: "";
844
+ position: absolute;
845
+ inset: auto 0 0 0;
846
+ height: calc(var(--wp-overlap, 64px) + 56px);
847
+ background: linear-gradient(to bottom, transparent, var(--bg));
848
+ pointer-events: none;
849
+ }
850
+
851
+ /* 图片层:desktop/mobile 分端渲染;<768px 优先 mobile 源,未配置 mobile 时 desktop 层全宽兜底 */
852
+ .wp-images {
853
+ position: absolute;
854
+ inset: 0;
855
+ }
856
+ .wp-img {
665
857
  width: 100%;
666
858
  height: 100%;
667
859
  object-fit: cover;
860
+ opacity: 0;
861
+ transition:
862
+ opacity 0.8s ease,
863
+ transform 0.8s ease;
864
+ }
865
+ .wp-img.active {
866
+ opacity: 1;
867
+ }
868
+ html[data-wallpaper-mode="banner"] .wp-img,
869
+ html[data-wallpaper-mode="fullscreen"]:not([data-wp-is-home]):not(
870
+ [data-wp-fs-layout="hero"]
871
+ )
872
+ .wp-img {
668
873
  object-position: var(--banner-pos, center);
669
874
  }
670
- /* 黑蒙层:深浅模式同色(orchid-blog 口径),只保证压暗不改变色调 */
671
- .wallpaper-dim {
875
+ html[data-wallpaper-mode="fullscreen"][data-wp-is-home] .wp-img {
876
+ object-position: var(--fs-pos, center);
877
+ }
878
+ .wp-mobile {
879
+ display: none;
880
+ }
881
+ @media (max-width: 767px) {
882
+ .wp-mobile {
883
+ display: block;
884
+ }
885
+ /* :has 兜底"未配置 mobile 源"场景:desktop 层后方无 mobile 兄弟时保持显示 */
886
+ .wp-desktop:has(~ .wp-mobile) {
887
+ display: none;
888
+ }
889
+ }
890
+ /* overlay 形态的图片模糊/放大补偿(服务端算好 scale 防边缘露底),与 body 级旧口径一致;
891
+ 非首页 fullscreen-hero 降级为 overlay,复用同一套模糊参数 */
892
+ html[data-wallpaper-mode="overlay"] .wp-img,
893
+ html[data-wallpaper-mode="fullscreen"]:not(
894
+ [data-wp-is-home]
895
+ )[data-wp-fs-layout="hero"]
896
+ .wp-img {
897
+ filter: blur(var(--wp-overlay-blur, 0px));
898
+ transform: scale(var(--wp-overlay-scale, 1));
899
+ }
900
+
901
+ /* 轮播过渡(§4.98 carousel):opacity 交叉淡化为基础,其余效果经 data-effect 加成;
902
+ --wp-interval 由 JS 写入 stage,使 kenburns/zoom 动画时长与轮换间隔一致 */
903
+ .wp-stage[data-effect="slide"] .wp-img {
904
+ transform: translateX(48px);
905
+ }
906
+ .wp-stage[data-effect="slide"] .wp-img.active {
907
+ transform: translateX(0);
908
+ }
909
+ .wp-stage[data-effect="zoom"] .wp-img.active {
910
+ animation: wpZoom var(--wp-interval, 5s) ease-out forwards;
911
+ }
912
+ .wp-stage[data-effect="kenburns"] .wp-img.active {
913
+ animation: wpKenburns var(--wp-interval, 5s) linear forwards;
914
+ }
915
+ @keyframes wpZoom {
916
+ from {
917
+ transform: scale(1.1);
918
+ }
919
+ to {
920
+ transform: scale(1);
921
+ }
922
+ }
923
+ @keyframes wpKenburns {
924
+ from {
925
+ transform: scale(1) translate(0, 0);
926
+ }
927
+ to {
928
+ transform: scale(1.12) translate(-1.5%, 1%);
929
+ }
930
+ }
931
+
932
+ /* 视频壁纸层:默认不加载不显示(preload=none、无 src),播放态淡入盖过图片层 */
933
+ .wp-video {
672
934
  position: absolute;
673
935
  inset: 0;
674
- background: rgba(0, 0, 0, var(--banner-dim, 0.2));
936
+ width: 100%;
937
+ height: 100%;
938
+ object-fit: cover;
939
+ opacity: 0;
940
+ transition: opacity 0.6s ease;
941
+ pointer-events: none;
942
+ }
943
+ .wp-stage[data-video-playing] .wp-video {
944
+ opacity: 1;
945
+ }
946
+ .wp-stage[data-video-playing] .wp-images {
947
+ opacity: 0;
948
+ transition: opacity 0.6s ease;
949
+ }
950
+ /* 播放/暂停双图标显隐(is-playing 由 app.ts 依 video.play/pause 事件切换) */
951
+ #wpPlayerToggle .i-pause {
952
+ display: none;
953
+ }
954
+ #wpPlayerToggle.is-playing .i-play {
955
+ display: none;
956
+ }
957
+ #wpPlayerToggle.is-playing .i-pause {
958
+ display: block;
959
+ }
960
+
961
+ /* 蒙层:浅/暗双档不透明度(--wp-dim / --wp-dim-dark),压暗壁纸保证前景可读 */
962
+ .wp-dim {
963
+ position: absolute;
964
+ inset: 0;
965
+ background: rgb(0 0 0 / var(--wp-dim, 0.2));
966
+ }
967
+ html.dark .wp-dim {
968
+ background: rgb(0 0 0 / var(--wp-dim-dark, 0.65));
969
+ }
970
+
971
+ /* 底部渐变装饰:压暗底缘承托波浪与 hero,分端显隐与图片层同口径 */
972
+ .wp-gradient {
973
+ position: absolute;
974
+ inset: auto 0 0 0;
975
+ height: var(--wp-grad-h, 10%);
976
+ background: linear-gradient(to top, rgb(0 0 0 / 0.35), transparent);
977
+ pointer-events: none;
978
+ }
979
+ .wp-gradient.is-mobile {
980
+ display: none;
981
+ }
982
+ @media (max-width: 767px) {
983
+ .wp-gradient.is-mobile {
984
+ display: block;
985
+ }
986
+ .wp-gradient.is-desktop {
987
+ display: none;
988
+ }
989
+ }
990
+
991
+ /* 底部波浪装饰:双层错相反向平移(200% 宽无缝循环) */
992
+ .wp-waves {
993
+ position: absolute;
994
+ inset: auto 0 0 0;
995
+ height: 90px;
996
+ pointer-events: none;
675
997
  }
676
- /* hero 叠加(§4.39):首页 hero 启用时主句/副句居中压到 banner 上;
677
- banner 上缘滑入 Header 底下(负 margin),文字区加 padding-top 补偿做视觉居中 */
678
- .wallpaper-hero {
998
+ .wp-waves .wave {
999
+ position: absolute;
1000
+ bottom: 0;
1001
+ left: 0;
1002
+ width: 200%;
1003
+ height: 100%;
1004
+ fill: rgb(255 255 255 / 0.16);
1005
+ }
1006
+ .wp-waves .wave.w1 {
1007
+ animation: wpWave 14s linear infinite;
1008
+ }
1009
+ .wp-waves .wave.w2 {
1010
+ fill: rgb(255 255 255 / 0.1);
1011
+ animation: wpWave 22s linear infinite reverse;
1012
+ }
1013
+ @keyframes wpWave {
1014
+ from {
1015
+ transform: translateX(0);
1016
+ }
1017
+ to {
1018
+ transform: translateX(-50%);
1019
+ }
1020
+ }
1021
+ .wp-waves.is-mobile {
1022
+ display: none;
1023
+ }
1024
+ @media (max-width: 767px) {
1025
+ .wp-waves.is-mobile {
1026
+ display: block;
1027
+ }
1028
+ .wp-waves.is-desktop {
1029
+ display: none;
1030
+ }
1031
+ }
1032
+
1033
+ /* hero 叠加(§4.98 homeText):主句/副句居中压在壁纸可视区上;字号走 stage 级变量;
1034
+ 上缘滑入 Header 底下(负 margin)且底缘被内容上拉覆盖(--wp-overlap),文字区
1035
+ padding-top/bottom 双向补偿,保证视觉居中不被导航遮挡、不压分类导航条 */
1036
+ .wp-hero {
679
1037
  position: absolute;
680
1038
  inset: 0;
681
1039
  z-index: 1;
@@ -686,45 +1044,503 @@ html.dark #modeToggle .i-sun {
686
1044
  padding: var(--header-h) 24px 0;
687
1045
  text-align: center;
688
1046
  }
689
- .wallpaper-hero .hero-quote {
1047
+ /* banner 底缘被内容上拉覆盖(--wp-overlap),文字区底部同步补偿保持视觉居中、
1048
+ 不压分类导航条;非首页 fullscreen-classic 降级为 banner 同样适用 */
1049
+ html[data-wallpaper-mode="banner"] .wp-hero,
1050
+ html[data-wallpaper-mode="fullscreen"]:not([data-wp-is-home]):not(
1051
+ [data-wp-fs-layout="hero"]
1052
+ )
1053
+ .wp-hero {
1054
+ padding-bottom: var(--wp-overlap, 64px);
1055
+ }
1056
+ /* 字号随窗口流体缩放:配置值为上限(宽屏保持大气),窄屏按 vw 平滑收缩,无需断点 */
1057
+ .wp-hero .hero-quote {
1058
+ font-size: clamp(1.8rem, 6vw + 1rem, var(--wp-hero-title-size, 3.8rem));
690
1059
  color: #fff;
691
1060
  text-shadow: 0 2px 16px rgba(0, 0, 0, 0.45);
692
1061
  }
693
- /* banner 上强调色需提亮:accent-ink 在黑蒙层上偏暗,混入白色保证可读 */
694
- .wallpaper-hero .hero-quote em {
1062
+ /* 壁纸上强调色需提亮:accent-ink 在黑蒙层上偏暗,混入白色保证可读 */
1063
+ .wp-hero .hero-quote em {
695
1064
  color: color-mix(in srgb, var(--accent) 45%, #fff);
696
1065
  }
697
- .wallpaper-hero .hero-sub {
1066
+ .wp-hero .hero-sub {
1067
+ min-height: 1.75em;
1068
+ margin-top: 14px;
1069
+ font-size: clamp(1rem, 2.5vw + 0.5rem, var(--wp-hero-sub-size, 1.5rem));
698
1070
  color: rgba(255, 255, 255, 0.88);
699
1071
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.4);
700
1072
  }
701
1073
 
702
- /* ---------- 3.5b 全站背景壁纸(§4.92):fixed 视口背景,与顶部 banner(§4.42)独立 ---------- */
703
- /* body 背景传播为画布底色:负 z-index 定位子元素画在其上、内容之下——壁纸加载中仍有底色兜底,
704
- body 自身的径向渐变装饰同样在画布层,被壁纸自然覆盖 */
705
- .site-wallpaper {
1074
+ /* 全屏首屏滚动提示(§4.98 fullscreen):底部靠上居中悬浮,上下浮动引导;
1075
+ 点击平滑滚过首屏(onclick scrollIntoView)。SSR 始终渲染、CSS 按模式门控显隐,
1076
+ 访客切到 fullscreen 即可用;hero 布局滚动后随 hero 一起淡出 */
1077
+ .wp-scroll-hint {
1078
+ display: none;
1079
+ position: absolute;
1080
+ left: 50%;
1081
+ bottom: 9vh;
1082
+ transform: translateX(-50%);
1083
+ z-index: 1;
1084
+ align-items: center;
1085
+ justify-content: center;
1086
+ width: 44px;
1087
+ height: 44px;
1088
+ padding: 0;
1089
+ border: none;
1090
+ border-radius: 50%;
1091
+ background: rgb(255 255 255 / 0.16);
1092
+ -webkit-backdrop-filter: blur(6px);
1093
+ backdrop-filter: blur(6px);
1094
+ color: #fff;
1095
+ cursor: pointer;
1096
+ animation: wpScrollHint 2.2s ease-in-out infinite;
1097
+ transition:
1098
+ background 0.2s,
1099
+ opacity 0.5s ease;
1100
+ }
1101
+ /* 仅 fullscreen 首页可见(banner/overlay/none 与非首页降级保持 display:none) */
1102
+ html[data-wallpaper-mode="fullscreen"][data-wp-is-home] .wp-scroll-hint {
1103
+ display: flex;
1104
+ }
1105
+ .wp-scroll-hint:hover {
1106
+ background: rgb(255 255 255 / 0.28);
1107
+ }
1108
+ .wp-scroll-hint svg {
1109
+ width: 22px;
1110
+ height: 22px;
1111
+ }
1112
+ @keyframes wpScrollHint {
1113
+ 0%,
1114
+ 100% {
1115
+ transform: translateX(-50%) translateY(0);
1116
+ }
1117
+ 50% {
1118
+ transform: translateX(-50%) translateY(10px);
1119
+ }
1120
+ }
1121
+ @media (prefers-reduced-motion: reduce) {
1122
+ .wp-scroll-hint {
1123
+ animation: none;
1124
+ }
1125
+ }
1126
+ /* hero 布局:stage fixed 且 pointer-events:none,箭头需单独恢复可点击;
1127
+ 滚动后随 .wp-hero 同步淡出 */
1128
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"]
1129
+ .wp-scroll-hint {
1130
+ pointer-events: auto;
1131
+ }
1132
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"].wp-scrolled
1133
+ .wp-scroll-hint {
1134
+ opacity: 0;
1135
+ pointer-events: none;
1136
+ }
1137
+
1138
+ /* 打字机光标(§4.98 typewriter):span.typewriter 文本后闪烁竖线 */
1139
+ .typewriter::after {
1140
+ content: "|";
1141
+ margin-left: 2px;
1142
+ color: rgba(255, 255, 255, 0.85);
1143
+ animation: wpCursor 1s step-end infinite;
1144
+ }
1145
+ @keyframes wpCursor {
1146
+ 0%,
1147
+ 100% {
1148
+ opacity: 1;
1149
+ }
1150
+ 50% {
1151
+ opacity: 0;
1152
+ }
1153
+ }
1154
+
1155
+ /* overlay 形态正文卡片半透明(§4.98 overlay.cardOpacity):壁纸从页缝与卡片间隙透出;
1156
+ --wp-card-opacity 由 SSR 输出为百分比字面量 */
1157
+ html[data-wallpaper-mode="overlay"] .card {
1158
+ background: color-mix(
1159
+ in srgb,
1160
+ var(--surface) var(--wp-card-opacity, 50%),
1161
+ transparent
1162
+ );
1163
+ }
1164
+
1165
+ /* 动画减免偏好:波浪/推近类装饰动画静止(交叉淡化保留,不影响可读性) */
1166
+ @media (prefers-reduced-motion: reduce) {
1167
+ .wp-waves .wave,
1168
+ .wp-stage[data-effect="kenburns"] .wp-img.active,
1169
+ .wp-stage[data-effect="zoom"] .wp-img.active {
1170
+ animation: none;
1171
+ }
1172
+ }
1173
+
1174
+ /* ---------- 3.5b 全屏 hero 布局(§4.103 fullscreen.layout=hero) ----------
1175
+ 与 classic 的差异:滚下后壁纸 fixed 铺满 + 模糊渐变过渡,卡片浮于模糊壁纸上;
1176
+ classic 滚下后正文区纯色背景(旧行为,无需额外规则)。
1177
+ 首屏两种布局一致:壁纸占满一屏 + 中央 hero 文案。 */
1178
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]
1179
+ .wp-stage {
706
1180
  position: fixed;
707
1181
  inset: 0;
1182
+ height: auto;
1183
+ margin-top: 0;
708
1184
  z-index: -1;
709
- overflow: hidden;
710
1185
  pointer-events: none;
711
1186
  }
712
- .site-wallpaper img {
713
- width: 100%;
714
- height: 100%;
715
- object-fit: cover;
716
- filter: blur(var(--wp-blur, 0px));
717
- /* 模糊边缘泛出透明底:按模糊量轻微放大补偿(服务端算好 --wp-scale) */
718
- transform: scale(var(--wp-scale, 1));
1187
+ /* 首屏让给 hero:正文流向下推一屏,滚上后覆盖 fixed 壁纸;
1188
+ stage 隐藏(homeOnly 非首页 / JS 切走)时取消下推,避免顶部整屏空白 */
1189
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]:not(
1190
+ [data-wp-stage-hidden]
1191
+ ) .site-main {
1192
+ margin-top: 100vh;
1193
+ }
1194
+ /* hero 交互:fixed 后 pointer-events 被关,hero 文案纯展示无需点击(打字机亦然) */
1195
+ /* hero 文字滚动淡出:滚离首屏后标题/副标题渐隐,不盖在正文区模糊壁纸上 */
1196
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]
1197
+ .wp-hero {
1198
+ transition: opacity 0.5s ease;
1199
+ }
1200
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home].wp-scrolled
1201
+ .wp-hero {
1202
+ opacity: 0;
1203
+ }
1204
+ /* 滚动模糊过渡:滚过 40px(html.wp-scrolled,app.ts updateWallpaperScroll)后
1205
+ 壁纸加模糊 + 放大补偿 + 底部渐隐蒙层加深,保证模糊渐变在 blur=0 时也可见 */
1206
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]
1207
+ .wp-img {
1208
+ transition:
1209
+ opacity 0.8s ease,
1210
+ transform 0.8s ease,
1211
+ filter 0.5s ease;
1212
+ }
1213
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home].wp-scrolled
1214
+ .wp-img {
1215
+ filter: blur(var(--wp-overlay-blur, 0px));
1216
+ transform: scale(var(--wp-overlay-scale, 1));
719
1217
  }
720
- /* 遮罩层:浅/暗双档不透明度(--wp-dim / --wp-dim-dark),保证任意壁纸下正文可读 */
721
- .site-wallpaper-dim {
1218
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]
1219
+ .wp-stage::after {
1220
+ content: "";
722
1221
  position: absolute;
723
- inset: 0;
724
- background: rgb(0 0 0 / var(--wp-dim, 0.45));
1222
+ inset: auto 0 0 0;
1223
+ height: 40vh;
1224
+ background: linear-gradient(to bottom, transparent, var(--bg));
1225
+ opacity: 0;
1226
+ transition: opacity 0.5s ease;
1227
+ pointer-events: none;
725
1228
  }
726
- html.dark .site-wallpaper-dim {
727
- background: rgb(0 0 0 / var(--wp-dim-dark, 0.65));
1229
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home].wp-scrolled
1230
+ .wp-stage::after {
1231
+ opacity: 1;
1232
+ }
1233
+ /* hero 布局正文卡片半透明:复用 overlay 的 --wp-card-opacity(壁纸从卡片间隙透出)。
1234
+ 文章列表 .post-card 与分页 .page-item 不走 .card 类,需一并覆盖;
1235
+ 非首页 fullscreen-hero 降级为 overlay,同样需要半透明卡片 */
1236
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]
1237
+ .card,
1238
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]
1239
+ .post-card,
1240
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"][data-wp-is-home]
1241
+ .page-item,
1242
+ html[data-wallpaper-mode="fullscreen"]:not(
1243
+ [data-wp-is-home]
1244
+ )[data-wp-fs-layout="hero"]
1245
+ .card,
1246
+ html[data-wallpaper-mode="fullscreen"]:not(
1247
+ [data-wp-is-home]
1248
+ )[data-wp-fs-layout="hero"]
1249
+ .post-card,
1250
+ html[data-wallpaper-mode="fullscreen"]:not(
1251
+ [data-wp-is-home]
1252
+ )[data-wp-fs-layout="hero"]
1253
+ .page-item {
1254
+ background: color-mix(
1255
+ in srgb,
1256
+ var(--surface) var(--wp-card-opacity, 50%),
1257
+ transparent
1258
+ );
1259
+ }
1260
+
1261
+ /* ---------- 3.5c 壁纸访客开关显隐(§4.103):html data 属性驱动 ----------
1262
+ boot 脚本(BaseLayout)与 app.ts applySavedWallpaper 双入口写入,
1263
+ 面板开关切换时同步更新 */
1264
+ /* hero 文案显隐总规则(§4.98 硬规则,用户多次确认、后续改动不得回退):
1265
+ 壁纸文字只允许出现在两类位置——① banner 形态的横幅区(Header 菜单导航与
1266
+ 分类导航条之间,含非首页 fullscreen-classic 降级);② fullscreen 首页首屏
1267
+ (hero 布局居中文案)。其余形态一律不展示文字:overlay 形态 stage 为 fixed
1268
+ 垫底,.wp-hero 会浮在半透明内容区背后;fullscreen-hero 非首页降级为 overlay
1269
+ 同样适用(data-wallpaper-mode 仍是 "fullscreen",需按 layout+非首页匹配)。
1270
+ 文字职责交还内容区标题(.page-title/.post-title-lg 等,见下方规则) */
1271
+ html[data-wallpaper-mode="overlay"] .wp-hero,
1272
+ html[data-wallpaper-mode="none"] .wp-hero,
1273
+ html[data-wallpaper-mode="fullscreen"][data-wp-fs-layout="hero"]:not(
1274
+ [data-wp-is-home]
1275
+ )
1276
+ .wp-hero {
1277
+ display: none;
1278
+ }
1279
+ html[data-wp-home-text="off"] .wp-hero {
1280
+ display: none;
1281
+ }
1282
+ /* hero 横幅显示页面标题时,隐藏内容区重复标题(避免归档/文章等页面出现两个同名标题)。
1283
+ 仅 banner 与 fullscreen-classic 生效:fullscreen-hero 非首页降级为 overlay,
1284
+ .wp-hero 被上方规则隐藏,此时内容区标题应保留可见 */
1285
+ html[data-wp-hero="visible"][data-wallpaper-mode="banner"] .page-title,
1286
+ html[data-wp-hero="visible"][data-wallpaper-mode="banner"] .page-sub,
1287
+ html[data-wp-hero="visible"][data-wallpaper-mode="banner"] .post-title-lg,
1288
+ html[data-wp-hero="visible"][data-wallpaper-mode="banner"] .archive-head,
1289
+ html[data-wp-hero="visible"][data-wallpaper-mode="fullscreen"]:not(
1290
+ [data-wp-fs-layout="hero"]
1291
+ )
1292
+ .page-title,
1293
+ html[data-wp-hero="visible"][data-wallpaper-mode="fullscreen"]:not(
1294
+ [data-wp-fs-layout="hero"]
1295
+ )
1296
+ .page-sub,
1297
+ html[data-wp-hero="visible"][data-wallpaper-mode="fullscreen"]:not(
1298
+ [data-wp-fs-layout="hero"]
1299
+ )
1300
+ .post-title-lg,
1301
+ html[data-wp-hero="visible"][data-wallpaper-mode="fullscreen"]:not(
1302
+ [data-wp-fs-layout="hero"]
1303
+ )
1304
+ .archive-head {
1305
+ display: none;
1306
+ }
1307
+ html[data-wp-waves="off"] .wp-waves {
1308
+ display: none;
1309
+ }
1310
+ html[data-wp-gradient="off"] .wp-gradient {
1311
+ display: none;
1312
+ }
1313
+ html[data-wp-sakura="off"] #sakura-canvas {
1314
+ display: none;
1315
+ }
1316
+
1317
+ /* ---------- 3.5d 显示设置面板(§4.103,对齐 Firefly) ----------
1318
+ 齿轮入口的右上角浮层:三 Tab(外观/壁纸/特效)+ 组卡片 + 开关/滑块/模式宫格;
1319
+ 样式变量复用 palette-pop/card 体系(surface/border/radius/shadow) */
1320
+ .ds-panel {
1321
+ position: fixed;
1322
+ top: calc(var(--header-h) + 12px);
1323
+ right: max(16px, calc((100vw - var(--page-width, 1600px)) / 2));
1324
+ z-index: 120;
1325
+ width: 330px;
1326
+ max-width: calc(100vw - 32px);
1327
+ max-height: 78vh;
1328
+ display: flex;
1329
+ flex-direction: column;
1330
+ background: var(--surface);
1331
+ border: 1px solid var(--border);
1332
+ border-radius: var(--radius);
1333
+ box-shadow: var(--shadow-md);
1334
+ overflow: hidden;
1335
+ }
1336
+ .ds-panel[hidden] {
1337
+ display: none;
1338
+ }
1339
+ /* Tab 栏:图标+文字横排,激活态 accent 底色 */
1340
+ .ds-tabs {
1341
+ display: flex;
1342
+ gap: 4px;
1343
+ padding: 10px 12px 0;
1344
+ border-bottom: 1px solid var(--border);
1345
+ }
1346
+ .ds-tab {
1347
+ flex: 1;
1348
+ display: flex;
1349
+ align-items: center;
1350
+ justify-content: center;
1351
+ gap: 6px;
1352
+ padding: 8px 4px 10px;
1353
+ font-size: 13px;
1354
+ color: var(--muted);
1355
+ border-bottom: 2px solid transparent;
1356
+ transition:
1357
+ color 0.15s,
1358
+ border-color 0.15s;
1359
+ }
1360
+ .ds-tab svg {
1361
+ width: 16px;
1362
+ height: 16px;
1363
+ }
1364
+ .ds-tab:hover {
1365
+ color: var(--ink-2);
1366
+ }
1367
+ .ds-tab.is-active {
1368
+ color: var(--accent-ink);
1369
+ border-bottom-color: var(--accent);
1370
+ }
1371
+ /* 内容区可滚动(面板 max-height 78vh) */
1372
+ .ds-body {
1373
+ overflow-y: auto;
1374
+ padding: 14px;
1375
+ }
1376
+ .ds-page {
1377
+ display: none;
1378
+ }
1379
+ .ds-page.is-active {
1380
+ display: block;
1381
+ }
1382
+ /* 组卡片:标题 + 右上组重置按钮(壁纸设置/透明设置) */
1383
+ .ds-group {
1384
+ padding: 12px;
1385
+ border: 1px solid var(--border);
1386
+ border-radius: var(--radius);
1387
+ background: var(--bg-soft, transparent);
1388
+ }
1389
+ .ds-group + .ds-group {
1390
+ margin-top: 12px;
1391
+ }
1392
+ .ds-group-title {
1393
+ display: flex;
1394
+ align-items: center;
1395
+ justify-content: space-between;
1396
+ font-size: 12px;
1397
+ color: var(--muted);
1398
+ letter-spacing: 0.08em;
1399
+ margin-bottom: 10px;
1400
+ }
1401
+ .ds-group-reset {
1402
+ font-size: 14px;
1403
+ line-height: 1;
1404
+ color: var(--muted);
1405
+ padding: 2px 6px;
1406
+ border-radius: 6px;
1407
+ transition:
1408
+ color 0.15s,
1409
+ background-color 0.15s;
1410
+ }
1411
+ .ds-group-reset:hover {
1412
+ color: var(--accent-ink);
1413
+ background: var(--accent-soft);
1414
+ }
1415
+ /* 模式宫格:两列按钮(图标+文字),当前选中态 accent 描边 */
1416
+ .ds-mode-grid {
1417
+ display: grid;
1418
+ grid-template-columns: 1fr 1fr;
1419
+ gap: 8px;
1420
+ }
1421
+ .ds-mode-btn {
1422
+ display: flex;
1423
+ align-items: center;
1424
+ justify-content: center;
1425
+ gap: 6px;
1426
+ padding: 9px 6px;
1427
+ font-size: 13px;
1428
+ color: var(--ink-2);
1429
+ border: 1px solid var(--border);
1430
+ border-radius: 10px;
1431
+ background: var(--surface);
1432
+ transition:
1433
+ color 0.15s,
1434
+ border-color 0.15s,
1435
+ background-color 0.15s;
1436
+ }
1437
+ .ds-mode-btn svg {
1438
+ width: 16px;
1439
+ height: 16px;
1440
+ }
1441
+ .ds-mode-btn:hover {
1442
+ border-color: var(--accent);
1443
+ }
1444
+ .ds-mode-btn.is-active {
1445
+ color: var(--accent-ink);
1446
+ border-color: var(--accent);
1447
+ background: var(--accent-soft);
1448
+ }
1449
+ /* 开关行:图标 + 文案 + switch(44x24 轨道,accent 开态) */
1450
+ .ds-switch-row,
1451
+ .ds-slider-row {
1452
+ display: flex;
1453
+ align-items: center;
1454
+ gap: 10px;
1455
+ padding: 7px 0;
1456
+ }
1457
+ .ds-switch-row svg,
1458
+ .ds-slider-row svg {
1459
+ width: 16px;
1460
+ height: 16px;
1461
+ flex-shrink: 0;
1462
+ color: var(--muted);
1463
+ }
1464
+ .ds-row-label {
1465
+ flex: 1;
1466
+ font-size: 13px;
1467
+ color: var(--ink-2);
1468
+ }
1469
+ .ds-switch {
1470
+ position: relative;
1471
+ width: 40px;
1472
+ height: 22px;
1473
+ flex-shrink: 0;
1474
+ border-radius: 999px;
1475
+ background: var(--border);
1476
+ transition: background-color 0.2s;
1477
+ }
1478
+ .ds-switch-knob {
1479
+ position: absolute;
1480
+ top: 3px;
1481
+ left: 3px;
1482
+ width: 16px;
1483
+ height: 16px;
1484
+ border-radius: 50%;
1485
+ background: var(--surface);
1486
+ box-shadow: var(--shadow-sm);
1487
+ transition: transform 0.2s;
1488
+ }
1489
+ .ds-switch[aria-checked="true"] {
1490
+ background: var(--accent);
1491
+ }
1492
+ .ds-switch[aria-checked="true"] .ds-switch-knob {
1493
+ transform: translateX(18px);
1494
+ }
1495
+ /* 滑块行:图标 + 文案 + range + 数值徽章(80% / 10.0px / 60%) */
1496
+ .ds-slider {
1497
+ flex: 1;
1498
+ min-width: 0;
1499
+ height: 6px;
1500
+ appearance: none;
1501
+ -webkit-appearance: none;
1502
+ background: var(--border);
1503
+ border-radius: 999px;
1504
+ cursor: pointer;
1505
+ outline-offset: 3px;
1506
+ }
1507
+ .ds-slider::-webkit-slider-thumb {
1508
+ appearance: none;
1509
+ -webkit-appearance: none;
1510
+ width: 16px;
1511
+ height: 16px;
1512
+ border-radius: 50%;
1513
+ background: var(--surface);
1514
+ border: 2px solid var(--accent);
1515
+ box-shadow: var(--shadow-sm);
1516
+ }
1517
+ .ds-slider::-moz-range-thumb {
1518
+ width: 16px;
1519
+ height: 16px;
1520
+ border-radius: 50%;
1521
+ background: var(--surface);
1522
+ border: 2px solid var(--accent);
1523
+ box-shadow: var(--shadow-sm);
1524
+ }
1525
+ .ds-badge {
1526
+ min-width: 44px;
1527
+ text-align: right;
1528
+ font-size: 12px;
1529
+ color: var(--muted);
1530
+ font-variant-numeric: tabular-nums;
1531
+ }
1532
+ /* 面板内模式相关组/行的运行时显隐(app.ts 按当前模式+布局刷新) */
1533
+ .ds-group[data-modes].is-hidden,
1534
+ .ds-slider-row[data-modes].ds-row-hidden {
1535
+ display: none;
1536
+ }
1537
+ /* 移动端:面板贴边全宽 */
1538
+ @media (max-width: 767px) {
1539
+ .ds-panel {
1540
+ right: 12px;
1541
+ left: 12px;
1542
+ width: auto;
1543
+ }
728
1544
  }
729
1545
 
730
1546
  /* ---------- 3.5c 番组追番页(§4.93) ---------- */
@@ -2671,15 +3487,28 @@ html.dark .form-grid .input-error {
2671
3487
  }
2672
3488
 
2673
3489
  /* ---------- 7. 归档 ---------- */
3490
+ /* §4.105:页面头居中排版——居中标题 + 标题下渐变短线 + 副标题,
3491
+ PC 宽屏下标题与内容列同轴居中,不再贴容器左缘 */
2674
3492
  .archive-head {
2675
3493
  max-width: 760px;
2676
- margin-bottom: 32px;
3494
+ margin: 0 auto 32px;
3495
+ text-align: center;
2677
3496
  }
2678
3497
  .archive-head .page-title {
2679
3498
  font-family: var(--font-display);
2680
3499
  font-size: 30px;
2681
3500
  font-weight: 700;
2682
3501
  }
3502
+ /* 标题下渐变短线(accent → 透明),随暗色模式 accent 变量自动适配 */
3503
+ .archive-head .page-title::after {
3504
+ content: "";
3505
+ display: block;
3506
+ width: 56px;
3507
+ height: 3px;
3508
+ margin: 14px auto 0;
3509
+ border-radius: 2px;
3510
+ background: linear-gradient(90deg, var(--accent), transparent);
3511
+ }
2683
3512
  .archive-head .page-sub {
2684
3513
  margin-top: 6px;
2685
3514
  color: var(--muted);