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