dsh-theme-endfield 1.2.5 → 1.2.6

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/client.js CHANGED
@@ -5413,6 +5413,18 @@ function apply(ctx) { // Idempotency: the installed bundle can be applied mor
5413
5413
  { name: '国庆节', from: '10-01', to: '10-07', makeup: ['09-20', '10-10'] },
5414
5414
  ],
5415
5415
  },
5416
+ 2027: {
5417
+ notice: '国办发明电〔2026〕10号',
5418
+ spans: [
5419
+ { name: '元旦', from: '01-01', to: '01-03', makeup: [] },
5420
+ { name: '春节', from: '02-05', to: '02-13', makeup: ['01-31', '02-14'] },
5421
+ { name: '清明节', from: '04-03', to: '04-05', makeup: [] },
5422
+ { name: '劳动节', from: '05-01', to: '05-05', makeup: ['05-08'] },
5423
+ { name: '端午节', from: '06-09', to: '06-09', makeup: [] },
5424
+ { name: '中秋节', from: '09-15', to: '09-15', makeup: [] },
5425
+ { name: '国庆节', from: '10-01', to: '10-07', makeup: ['09-26', '10-09'] },
5426
+ ],
5427
+ },
5416
5428
  }
5417
5429
 
5418
5430
  /* 'YYYY-MM-DD' -> holiday name, expanded once from the spans above. */
@@ -6493,6 +6505,42 @@ function apply(ctx) { // Idempotency: the installed bundle can be applied mor
6493
6505
  scrollbar-width: thin;
6494
6506
  scrollbar-color: var(--edge-line) transparent;
6495
6507
  }
6508
+ /* Issue #43: the app draws the conversation-width drag indicator with a
6509
+ gradient whose two solid stops are var(--dsw-alias-scrollbar-bg-l1). The
6510
+ theme sets that token (and l2) to transparent so it can paint its own
6511
+ scrollbars — and the handle is the ONLY consumer of l1 that is not a
6512
+ scrollbar thumb, so the line is still painted on hover / while dragging,
6513
+ at opacity 1, in transparent. That is the whole bug.
6514
+
6515
+ WHY NOT JUST UN-TRANSPARENT THE TOKEN. The app spends --dsw-alias-
6516
+ scrollbar-bg-l2 in 45 rules and l1 in 3; every one but this gradient is a
6517
+ thumb (--dsh-scrollbar-thumb). Handing the token back a colour would
6518
+ repaint every themed scrollbar to the app's stock grey, i.e. trade one
6519
+ visible regression for another. So the token stays transparent and the
6520
+ handle is repainted on its own.
6521
+
6522
+ COLOUR: --dsw-alias-label-primary, the exact pair the app already uses for
6523
+ its own line (#0f1115 on cream, #f9fafb on near-black — 15.35:1 / 18.11:1
6524
+ against their papers). The theme never remaps that token globally, and
6525
+ reading it means both schemes and both palettes come out right without a
6526
+ second rule or a backing plate.
6527
+
6528
+ GEOMETRY: none. Width, radius, offsets and the pointer-y math stay the
6529
+ app's; only the two colour stops change, so the handle cannot grow into
6530
+ the transcript column.
6531
+
6532
+ ANCHORS: [data-width-handle] is the e2e hook the app declares on both
6533
+ handles; the class is matched as a SUBSTRING because a suffix match dies
6534
+ the day upstream appends a second class (the 0.1.2-rc.1 lesson). */
6535
+ :is([data-width-handle], [class*='_widthHandle']):after {
6536
+ background: linear-gradient(
6537
+ to bottom,
6538
+ transparent calc(var(--dsh-width-handle-pointer-y, 50%) - 36px),
6539
+ var(--dsw-alias-label-primary) calc(var(--dsh-width-handle-pointer-y, 50%) - 8px),
6540
+ var(--dsw-alias-label-primary) calc(var(--dsh-width-handle-pointer-y, 50%) + 8px),
6541
+ transparent calc(var(--dsh-width-handle-pointer-y, 50%) + 36px)
6542
+ );
6543
+ }
6496
6544
  /* ---------- Light mode: deepen tertiary/secondary labels for icon visibility ---------- */
6497
6545
  body:not([data-ds-dark-theme]) {
6498
6546
  --dsw-alias-label-tertiary: #6a6d68;
@@ -6500,6 +6548,48 @@ function apply(ctx) { // Idempotency: the installed bundle can be applied mor
6500
6548
  --dsw-alias-label-dimmed: #9a9d98;
6501
6549
  --edge-btn-muted: #dcddd6;
6502
6550
  }
6551
+ /* ---------- light mode: keep the accent as a SIGNAL, not as text ----------
6552
+ Issue #44. The composer's quoted selection takes its colour from
6553
+ --dsw-alias-state-business-primary, i.e. the app's brand blue. The light
6554
+ palette remaps that token to ink (#101110) so buttons, status dots and the
6555
+ rest of the blue chrome read as a darkroom instrument — and the quote goes
6556
+ with it, landing 0.7 L* away from body text at 16.84:1. Nothing is
6557
+ unreadable; the QUOTING ACTION stops being visible, which is the point of
6558
+ the colour.
6559
+
6560
+ WHY NOT FIX THE TOKEN. Button fills, status dots and the focus ring's
6561
+ ancestry all read it; a per-consumer repaint is the only change that does
6562
+ not drag one of them back to blue. So the token stays ink and the quote
6563
+ gets its own two-tone: ink on a 55% accent wash (16.4:1 on 谷地黄, 9.9:1
6564
+ on 武陵青). The signal is carried by HUE — yellow or cyan behind black
6565
+ type — which is exactly the axis the palette owns, and it needs no third
6566
+ colour that would have to be re-measured per palette.
6567
+
6568
+ NO PADDING, deliberately: the excerpt is a single-line ellipsis box inside
6569
+ the composer row, and inline padding here would widen its measured box.
6570
+ This sheet has never reflowed the app, and it does not start for a chip.
6571
+ (radius only rounds the wash's ends.)
6572
+
6573
+ Dark needs no rule: there the token already resolves to the accent
6574
+ (13.97:1), so the quote is signal-yellow text today and stays that way.
6575
+ The anchor is the app's declared attribute on the excerpt itself,
6576
+ data-quote-preview — matching the excerpt rather than a parent also keeps
6577
+ this rule from depending on how deeply the row nests it. */
6578
+ body:not([data-ds-dark-theme]) [data-quote-preview] {
6579
+ color: var(--dsw-alias-label-primary);
6580
+ background: rgba(var(--edge-accent-rgb), 0.55);
6581
+ border-radius: 3px;
6582
+ }
6583
+ /* The same token, the same defect, one row over: the ref chip that carries a
6584
+ file / skill / command name is also business-primary, so on cream it turns
6585
+ into body text and stops reading as a reference. --edge-status-light is the
6586
+ palette's own deep step for accent-as-text on paper (#6b5d00 谷地黄 5.35:1,
6587
+ #006a6a 武陵青 5.22:1) — already measured, already the value the turn-status
6588
+ gradient uses, and it switches with the palette for free. Dark is already
6589
+ the accent (the same 13.97:1 the quote gets), so it is out of scope. */
6590
+ body:not([data-ds-dark-theme]) [data-ref-chip] {
6591
+ color: var(--edge-status-light);
6592
+ }
6503
6593
  /* ---------- Neutralize remaining DeepSeek brand blues ---------- */
6504
6594
  body {
6505
6595
  --dsw-static-deepseek-50: #dcddd6;
@@ -6591,11 +6681,43 @@ function apply(ctx) { // Idempotency: the installed bundle can be applied mor
6591
6681
  --dsw-specific-sidebar-nav-item-active: rgba(var(--edge-accent-rgb), 0.20);
6592
6682
  --dsw-specific-sidebar-nav-item-hover: rgba(var(--edge-accent-rgb), 0.16);
6593
6683
  }
6684
+ /* ---------- the two places the accent may NOT be ink (#42, #43) ----------
6685
+ Both are painted by elements the theme does not own, and both used to read
6686
+ --edge-accent directly. That works on the near-black page and fails on
6687
+ cream: #fff500 is 13.97:1 on #202220 and 1.02:1 on the #f2f2ec input card.
6688
+ Pinning the two ANSWERS here, per scheme, keeps the accent token itself
6689
+ untouched (it is still the fill/icon colour everywhere else).
6690
+ --edge-caret ink in light, accent in dark
6691
+ --edge-focus-ring the APP's own deepseek-500/400 pair, as literal hex:
6692
+ a focus ring is a system-level accessibility signal
6693
+ and already clears its bar on both papers (5.0:1 on
6694
+ #e8e8e2, 9.2:1 on #101110). Literal, because the
6695
+ theme remaps --dsw-static-deepseek-500/600 to ink and
6696
+ accent, so reading that token would loop straight
6697
+ back to the accent this rule is escaping. */
6698
+ body {
6699
+ --edge-caret: var(--dsw-alias-label-primary);
6700
+ --edge-focus-ring: #4176e6;
6701
+ }
6702
+ body[data-ds-dark-theme] {
6703
+ --edge-caret: var(--edge-accent);
6704
+ --edge-focus-ring: #7aaaff;
6705
+ }
6706
+ /* Issue #42: the caret was the accent in both schemes. A 1px caret paints
6707
+ fine and is simply invisible at 1.02:1 (谷地黄) / 1.70:1 (武陵青) — the
6708
+ report's word was 「光标不可见」, not 「颜色不好看」. Ink on the card is
6709
+ 16.4:1; the dark scheme keeps the accent, which is the one scheme where
6710
+ accent-as-ink already measured 13.97:1. */
6594
6711
  input, textarea, [contenteditable='true'] {
6595
- caret-color: var(--edge-accent);
6712
+ caret-color: var(--edge-caret, var(--edge-accent));
6596
6713
  }
6714
+ /* Issue #43 annex: same defect on the keyboard focus ring — 2px of #fff500
6715
+ hugging a #f2f2ec button is 1.02:1, and the !important also suppressed the
6716
+ app's own blue ring, so Tab navigation had no visible focus at all. The
6717
+ geometry (2px, offset 1px) is the theme's and stays; only the colour goes
6718
+ back to the app's, which is what "no theme installed" looks like. */
6597
6719
  :focus-visible {
6598
- outline: 2px solid var(--edge-accent) !important;
6720
+ outline: 2px solid var(--edge-focus-ring, var(--edge-accent)) !important;
6599
6721
  outline-offset: 1px;
6600
6722
  }
6601
6723
  a {
@@ -752,7 +752,7 @@ const visual = delta - layoutDelta
752
752
 
753
753
  ### 日历是数据,不是逻辑
754
754
 
755
- `BALANCE_HOLIDAY_NOTICES` 按年抄录国务院的放假安排通知(2026 年 = **国办发明电〔2025〕7号**,https://www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm ),`from` / `to` 是**含端点的 MM-DD**,`makeup` 存调休日——它不只是给人看的,也是上面那条推理的证据。启动时逐日展开成 `BALANCE_HOLIDAY_DATES`(`'YYYY-MM-DD' → 节日名`),再由此得出 `balanceHolidayName` 与 `balanceDayIsOffPeak`。
755
+ `BALANCE_HOLIDAY_NOTICES` 按年抄录国务院的放假安排通知(2026 年 = **国办发明电〔2025〕7号**,https://www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm ;2027 年 = **国办发明电〔2026〕10号**,https://www.gov.cn/zhengce/content/202611/content_7085101.htm ),`from` / `to` 是**含端点的 MM-DD**,`makeup` 存调休日——它不只是给人看的,也是上面那条推理的证据。启动时逐日展开成 `BALANCE_HOLIDAY_DATES`(`'YYYY-MM-DD' → 节日名`),再由此得出 `balanceHolidayName` 与 `balanceDayIsOffPeak`。
756
756
 
757
757
  **没有收录的年份回退到普通工作日规则**,也就是一个未录入的节假日会被算成高峰。这是刻意的:宁可把假期显示成高峰(用户读到的只是「现在贵」),也不猜一个假的半价读数。代价是这份数据会随时间失效,而且失效是**静默**的——所以 `check.js` 在「当前北京年份不在表里」时响亮失败,作为每年 11 月(通知发布月)的提醒。
758
758
 
@@ -1045,6 +1045,39 @@ body:has([data-approval-key]) :is([data-composer-seat], [class$='_composerSeat']
1045
1045
 
1046
1046
  顺带钉死一条 Blink 怪癖(对照测试差点被它假失配搞挂):**`::-webkit-scrollbar` 的级联不按特异性、不按 `!important`、也不可被后插入的样式表翻转**——页面 `#list::-webkit-scrollbar{width:5px !important}` 输给后注入的主题全局 `::-webkit-scrollbar{width:10px}`,boot 之后再 append 一条 5px 全局规则同样翻不掉(实测 gap 恒 10px)。主题的全局滚动条规则一旦注入就统治文档的全部滚动容器占位,这也解释了真实 app 中列表占位是 10px(app 自己的 `--dsh-session-list-scrollbar-width` 计划值是 5px)——它是主题 v1.2.4 起的既成行为。对照测试因此不跨 boot 比行宽(占位差会假失配),只比滚动条碰不到的左半边,行宽改用列表盒内部一致性断言(行右缘 = 列表 client 右缘 − 右内边距)。
1047
1047
 
1048
+ ### 十二类:令牌的消费者不全在主题手里(#42 / #43 / #44)
1049
+
1050
+ 同一夜、同一台机器、同一个环境(v1.2.5 + 亮色 + 谷地黄)来的三份报告,读起来是三个 bug:输入框光标看不见、拖动会话宽度没有指示线、引用块和正文同色。实际是一条:**主题重映射了应用令牌,而令牌的消费者里有主题从未接管的元素**。这类缺陷有个共同伪装——**它不表现为「字看不清」,而表现为「东西画了但看不见」**,所以连报告者都要先量完才敢确认不是自己眼花了。
1051
+
1052
+ | 面 | 机制 | 修复前(亮色) | 修复后 |
1053
+ | --- | --- | --- | --- |
1054
+ | 输入光标 | `caret-color: var(--edge-accent)` | `#fff500` 压 `#f2f2ec` **1.02:1** | 墨 `16.84:1`(暗色仍用强调色 13.97:1) |
1055
+ | 宽度指示线 | 手柄渐变的两个实色停靠点取自 `--dsw-alias-scrollbar-bg-l1`,而主题把它设成 `transparent` 自绘滚动条 | 线照常画、`opacity:1`,**整条透明** | 墨 `15.35:1`(暗色纸白 18.11:1),2px 几何未动 |
1056
+ | 键盘焦点环 | `outline: 2px solid var(--edge-accent) !important` | 1.02:1,且把应用原版蓝环一起盖掉 | 应用自己的 `#4176e6` `4.96:1`(暗色 `#7aaaff` 9.02:1) |
1057
+ | 引用块 | 引用取 `--dsw-alias-state-business-primary`,亮色被重映射成墨 | 16.84:1 —— 读得清,**和正文同色**,引用这个动作失去信号 | 墨字压 55% 强调洗底:谷地黄 16.38:1 / 武陵青 12.07:1 |
1058
+ | ref chip | 同一枚令牌,同一次撞色 | 同正文墨 | `#6b5d00` 5.86:1 / `#006a6a` 5.72:1(暗色仍是强调色) |
1059
+
1060
+ **四处都不能在令牌层修**,这是这道题的关键:
1061
+
1062
+ - 滚动条令牌 `l1` 3 个消费者、`l2` 45 个,除这一条手柄渐变外全是滚动条滑块。把颜色还给令牌,等于用「自己刚修好的滚动条」换「一条指示线」。
1063
+ - `--dsw-alias-state-business-primary` 是主按钮填充、回合状态点、焦点环前身共用的入口,改它连带一片。
1064
+ - `--edge-accent` 更不能改:它就是主题本身。
1065
+
1066
+ 所以全部改成**逐个消费者重绘**,并且遵守这个仓库的老规矩——**只动颜色,不动几何**:手柄不加宽(应用 2px 就 2px)、引用块不加内边距(摘要是单行省略框,inline padding 会改它的测量宽度)。为此新增两枚只读令牌,把「答案」而不是「规则」放进 scheme 作用域:
1067
+
1068
+ ```css
1069
+ body { --edge-caret: var(--dsw-alias-label-primary); --edge-focus-ring: #4176e6 }
1070
+ body[data-ds-dark-theme] { --edge-caret: var(--edge-accent); --edge-focus-ring: #7aaaff }
1071
+ ```
1072
+
1073
+ 焦点环用**字面 hex** 而不是 `--dsw-static-deepseek-500`,因为主题把这枚令牌重映射成了墨/强调色——顺着令牌读会绕回正在逃离的那个颜色。焦点环也不做「更深的金」:它是系统级可访问性信号,最稳的答案是还给应用。
1074
+
1075
+ 锚点一律取应用自己声明的属性:`[data-width-handle]`(手柄的 e2e 钩子)、`[data-composer-quote]` / `[data-quote-preview]`、`[data-ref-chip]`;类名一侧用**子串**(`[class*='_widthHandle']`),因为后缀匹配在上游追加第二个类那天会静默失效——0.1.2-rc.1 的教训。
1076
+
1077
+ `test/light-token-consumers.test.js` 走四个状态(亮·谷地黄 / 亮·武陵青 / 暗·谷地黄 / 主题关闭),把应用侧规则原样搬进夹具,并把焦点环在夹具里设成**品红虚线**——应用的真是蓝色,而修复后的主题也是蓝色,蓝对蓝的断言在规则完全失效时照样通过。每个颜色断言都配一条页面内算出的 WCAG 比值。反向验证也做了:把 `client.js` 换回 HEAD 的构建,测试立刻在 `--edge-caret` 处报红(读回空串),不是自证。
1078
+
1079
+ **教训**:重映射一个令牌之前,先数一遍它的消费者。只要消费者里有一个不是「主题要重绘的那类元素」,这个令牌就已经不是主题的私有财产了——而这类失配不会打字面报错,只会让某个像素安静地消失。
1080
+
1048
1081
 
1049
1082
  ---
1050
1083
 
package/docs/features.md CHANGED
@@ -233,7 +233,7 @@
233
233
 
234
234
  开启后屏幕顶部悬浮一枚药丸:左边是 DeepSeek API 余额(¥ / $),右边是当前**峰谷时段**——`高峰` / `低谷`、时段剩余与已过百分比、一个圆环时钟,以及开场那帧「品牌 pose」(`/// DEEPSEEK API` + `DeepSeek 当前低谷`)。设置行提供「预览」按钮,按真实开场动画重播一次;没有配置 API Key 时按钮禁用并说明原因。
235
235
 
236
- **峰谷规则在本地推算**(Host 不提供排班表):北京时间**周一至周五 9:00-12:00、14:00-18:00 是高峰**,价格为空闲时段的 2 倍。按 DeepSeek 2026-09-19 的「API 峰谷时间补充说明」,**中国法定节假日全天**以及**调休上班的周末**都按空闲计费——后一条天然落在「周末即低谷」上,所以胶囊只要保管一份法定节假日日历(按年抄录国务院通知;未收录的年份退回普通工作日规则,宁可显示高峰也不猜一个假的半价)。
236
+ **峰谷规则在本地推算**(Host 不提供排班表):北京时间**周一至周五 9:00-12:00、14:00-18:00 是高峰**,价格为空闲时段的 2 倍。按 DeepSeek 2026-09-19 的「API 峰谷时间补充说明」,**中国法定节假日全天**以及**调休上班的周末**都按空闲计费——后一条天然落在「周末即低谷」上,所以胶囊只要保管一份法定节假日日历(按年抄录国务院通知,2026 / 2027 已收录;未收录的年份退回普通工作日规则,宁可显示高峰也不猜一个假的半价)。
237
237
 
238
238
  倒计时读的是**同价连续段**,而不是「今天还剩多少」:周五 18:00 到周一 09:00 是一整段 63 小时的低谷,七天国庆是一整段 183 小时,所以读数可能是 `剩余47:20:00`。节假日名只出现在开场 pose 的标题里(`DeepSeek 国庆节低谷`),正式行仍只写两三个字——胶囊宽 300px,多一个字就会撑破它。
239
239
 
package/docs/testing.md CHANGED
@@ -203,12 +203,12 @@ node test/balance-window.test.js # 峰谷窗口算术(纯函数,从 clie
203
203
  node test/balance-capsule.test.js # 胶囊标记 / CSS / 绘制 / 设置行(静态切片)
204
204
  ```
205
205
 
206
- **`balance-window.test.js`** 把 `const BALANCE_HOLIDAY_NOTICES` 到 `const balancePaintWindow` 之间的源码切出来,在 `vm` 里用 `{ Math, Date }` 求值——切片边界本身就是断言,结构性改动会把切片挪走并响亮失败(旧版起点是 `const BALANCE_PEAK_WINDOWS`,节假日数据加在它之前后必须跟着改)。所有时刻都用 `bj(y, mo, d, h, mi, s) = new Date(Date.UTC(y, mo-1, d, h-8, mi, s))` 造成固定瞬时,因此结果与跑测试的机器时区无关。69 项断言分四组:
206
+ **`balance-window.test.js`** 把 `const BALANCE_HOLIDAY_NOTICES` 到 `const balancePaintWindow` 之间的源码切出来,在 `vm` 里用 `{ Math, Date }` 求值——切片边界本身就是断言,结构性改动会把切片挪走并响亮失败(旧版起点是 `const BALANCE_PEAK_WINDOWS`,节假日数据加在它之前后必须跟着改)。所有时刻都用 `bj(y, mo, d, h, mi, s) = new Date(Date.UTC(y, mo-1, d, h-8, mi, s))` 造成固定瞬时,因此结果与跑测试的机器时区无关。105 项断言分四组:
207
207
 
208
208
  - **工作日**:周四 08:59 / 09:00 / 11:59 / 12:00 / 13:59 / 14:00 / 17:59 / 18:00 的峰谷;12-14 谷段 `totalMs = 2h`;20:00 的谷段一路读到次日 09:00(15h);23:30 倒计时 9h30m。
209
209
  - **周末**:周六 00:00 / 12:00 都是低谷,且窗口是 **Fri 18:00 → Mon 09:00 的 63h**(不是按天的 24h);周日 23:00 剩 10h;周一 07:00 剩 2h;周六 09:40 剩 47h20m 且 `elapsedPct = 25`。
210
- - **法定节假日**:元旦(周四)10:00 是低谷、`holiday = '元旦'`,窗口 12-31 18:00 → 01-05 09:00(111h);春节窗口 255h,02-14 / 02-28 调休仍是低谷、02-24 回到高峰;清明 / 劳动 / 端午 / 中秋各自成对断言「节日当天低谷 + 次日高峰」;国庆(周一)10:00 低谷、窗口 183h、10-07 23:59 剩 9h01m、10-08 00:00 仍是同一段谷、10-08 09:00 高峰;**2027-01-01 无表可查 → 回退按工作日高峰**,把「未收录年份的代价」钉住。
211
- - **表完整性**:展开恰为 33 天(3+9+3+5+3+3+7)、每条 span 每一天都映射到自己的名字;末尾三个断言直接调用切出来的**真** `balanceFormatCountdown`(旧版是在测试里重写一遍格式化,等于什么都没验)。
210
+ - **法定节假日**:元旦(周四)10:00 是低谷、`holiday = '元旦'`,窗口 12-31 18:00 → 01-05 09:00(111h);春节窗口 255h,02-14 / 02-28 调休仍是低谷、02-24 回到高峰;清明 / 劳动 / 端午 / 中秋各自成对断言「节日当天低谷 + 次日高峰」;国庆(周一)10:00 低谷、窗口 183h、10-07 23:59 剩 9h01m、10-08 00:00 仍是同一段谷、10-08 09:00 高峰;2027 年按国办发明电〔2026〕10号 另成一组:元旦 87h、春节 255h(01-31 / 02-14 两个调休周日仍是低谷)、清明 87h、劳动 135h、端午 / 中秋都是单个周三 → 39h 谷、国庆 183h;**2028-01-03 无表可查 → 回退按工作日高峰**,把「未收录年份的代价」钉住。
211
+ - **表完整性**:展开恰为 62 天(2026 的 33 = 3+9+3+5+3+3+7,2027 的 29 = 3+9+3+5+1+1+7)、每条 span 每一天都映射到自己的名字;末尾三个断言直接调用切出来的**真** `balanceFormatCountdown`(旧版是在测试里重写一遍格式化,等于什么都没验)。
212
212
 
213
213
  **`balance-capsule.test.js`** 从安装态标记里切片:胶囊 DOM 顺序、`slotsWritten` 只允许写标记内已存在的属性(例外集 `STATE_ATTRS`)、样式表选择器不得成孤儿、圆环 `conic-gradient` / `mask` / `elapsedPct * 3.6`、药丸 32px / 999px / `min-width: 300px`、**480px → 316px 两级窄屏断点**、开场 pose 448×72、品牌 lockup。本次新增的一条断言把节假日的落点钉死:**`win.holiday` 只被一行读取,且那一行在 brand-title 块内**——胶囊宽 300px、316px 断点由它推出,节假日名一旦爬进「时段剩余」行就会撑宽。窄屏两级也各自钉死:480px 只隐藏 `data-endfield-balance-remain-run`(「时段剩余hh:mm:ss」,手机宽度)、且**不得**触碰 `phase`(高峰/低谷 标签要留下)、必须排在 316px 之前(阶梯,而不是互相遮蔽);同格里还断言 `min-width: 0` 与隐藏规则**写在同一个媒体块里**——地板不让,读数减少后 `margin-left: auto` 会把富余像素全吞成空白,胶囊根本不会变短。
214
214
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-theme-endfield",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "DeepSeek Harness web theme: the industrial editorial look of the Arknights: Endfield official site — cream paper, ink text, signal-yellow accents, zero radius. Settings persist through the DSH volatile Config + configForms transport (0.2.0-rc.2 and 0.1.7+), with a ctx.settingsScope fallback for older hosts.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -47,8 +47,8 @@
47
47
  "test:coverage": "node test/contour-coverage.test.js",
48
48
  "test:perf": "node test/contour-perf.test.js",
49
49
  "test:loader": "node test/loader-performance.test.js && node test/loader-late-prefs.test.js",
50
- "test": "node check.js && node selftest.js && node test/import-probe.test.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/tools/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/tools/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-coverage.test.js && node test/contour-perf.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/contour-worker-budget.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/approval-band-transform.test.js && node test/sidebar-row-wash.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
51
- "test:ci": "node check.js && node selftest.js && node test/import-probe.test.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/tools/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/tools/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/contour-worker-budget.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/approval-band-transform.test.js && node test/sidebar-row-wash.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
50
+ "test": "node check.js && node selftest.js && node test/import-probe.test.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/tools/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/tools/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-coverage.test.js && node test/contour-perf.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/contour-worker-budget.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/approval-band-transform.test.js && node test/light-token-consumers.test.js && node test/sidebar-row-wash.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
51
+ "test:ci": "node check.js && node selftest.js && node test/import-probe.test.js && node test/font-scope.test.js && node test/palette-contrast.test.js && node test/palette-switch.test.js && node test/menu-surface.test.js dark && node test/menu-surface.test.js light && node test/settings-buttons.test.js && node test/tools/hover-check.js && node test/selector-guard.test.js && node test/preset-chip.test.js && node test/balance-window.test.js && node test/balance-capsule.test.js && node test/credit-capsule.test.js && node test/settings-rows.test.js && node test/settings-durable-hold.test.js && node test/settings-config-forms.test.js && node test/settings-config-fallback.test.js && node test/settings-namespace.test.js && node test/settings-off.test.js && node test/settings-locale.test.js && node test/audio-notify.test.js && node test/audio-attention-watch.test.js && node test/host-no-inject.test.js && node scripts/build-sounds.js --check && node test/thunder-edges.test.js && node test/tools/thunder-shot.js && node test/thunder-dismiss.test.js && node test/contour-render.test.js && node test/loader-performance.test.js && node test/loader-late-prefs.test.js && node test/contour-specks.test.js && node test/watermark-stacking.test.js && node test/contour-smoothness.test.js && node test/contour-cusps.test.js && node test/contour-a11y.test.js && node test/contour-density.test.js && node test/contour-bounds.test.js && node scripts/build-host.js --check && node scripts/build-client.js --check && node scripts/build-contour-worker.js --check && node test/worker-eol.test.js && node test/contour-worker.test.js && node test/contour-worker-budget.test.js && node test/theme-sheet-refresh.test.js && node test/titlebar-probe.test.js && node test/corner-shape.test.js && node test/approval-band-transform.test.js && node test/light-token-consumers.test.js && node test/sidebar-row-wash.test.js && node test/glass.test.js && node test/contour-trail.test.js && node test/contour-trail-browser.test.js && node test/scroll-anim.test.js && node test/contour-loop-reentry.test.js",
52
52
  "shots": "node test/tools/shoot.js",
53
53
  "shots:verify": "node test/tools/shoot.js && node test/tools/verify-shots.js",
54
54
  "test:bounds": "node test/contour-bounds.test.js",