/* ==========================================================================
   来处 · Pardine（dineloc）· styles.css（owner E）
   --------------------------------------------------------------------------
   这一份定义**全部令牌**与**共用类**（CONTRACT §6.3–6.4）；ui-map.css（G）与
   ui-settings.css（D）只在这些之上搭，不重定义。

   ⚠⚠⚠ 颜色纪律（UPDATE 3：「同一色相的深浅，不要花花绿绿」）
     · 全应用的颜色**只**出现在下面三个 :root 块里。块外一律 var(--…)，
       外加 #fff / transparent（test/csp.mjs 逐行查 hex 字面量）。
     · 界面只有两种墨：纸上的墨（--text 的三档）与印章红（--accent / --seal）。
       第二个色相花青（--sea-ink / --seal-sea）只属于含食材的视图（全部、食材）的海与湖，以及远近条的海段（ADDENDUM-5 E20）。
     · 没有中性灰：每一块面、每一条线、每一道阴影都是暖棕调的。
   ⚠⚠ 深色是基底，浅色写两遍（媒体查询一遍、[data-theme="light"] 一遍）——
     与 Parote 同形。只写一遍的话「跟随系统」和「强制浅色」总有一个是错的。
   ⚠ 没有 backdrop-filter，任何地方都没有：iOS 26 的 Safari 只要在采样带里
     看见它，就再也不给浏览器铬件取色（家族铁律，「别再加回来」）。
   ⚠ 字号一律 rem；发丝线、安全区、JS 量出来的像素（--kb）不用 rem。
   ⚠ 布局只用逻辑属性（inline / block），ar fa he ur 是真的从右往左。
   ========================================================================== */

/* ==========================================================================
   −2. 衬线的支柱字体（ADDENDUM-3 E7「中文字在框里偏高」的**根**；2026-09-24 用户：「Safari里还是有CJK字偏高的情况」）
   --------------------------------------------------------------------------
   衬线框里的字靠行盒的基线落在 0.875em，汉字的墨心（基线上 0.38em）才在框的正中。基线的位置只由
   「第一个可用字体」（font-family 里第一个 unicode-range 含 U+0020 的字面）的 ascent / descent 决定。
   原先那是 Newsreader，0.875 / 0.125 来自下面那几条 @font-face 的 ascent-override / descent-override ——
   **已发布的 Safari（macOS / iOS，到 27.2）一个都不认**：WebKit bug 219735 在 2026-08 才落进主干，
   Playwright 的 WebKit 与 Safari Technology Preview 跑的是主干，所以测量台的「WebKit」一直是绿的，
   而真 Safari 用 Newsreader 自带的 0.735 / 0.265：基线上移 0.14em，**每一个**衬线框里的汉字都高 14%
   （15px 的签高 2.1px；本机 Safari 27.2 的 WKWebView 实测，docs/optics README「safari」那一列）。
   修法：fonts/v2/whence-strut.woff 是一套**没有字形、只有度量**的小字体（tools/make-strut.mjs 从零造，
   ascent 0.875 / descent 0.125 写死在字体文件里），unicode-range 只有 U+0020，排在 --latin-serif 最前面：
     · 每一个引擎都拿它当第一个可用字体 → 基线都在 0.875em，不再依赖任何覆盖描述符；
     · 它的 cmap 一个字符都不映射 → 每一个字（连空格）照常逐字回退到 Newsreader / Noto，字形、字宽一点不变；
     · x 高、大写高、下划线、删除线、上下标照抄 Newsreader：Blink 里一个像素都不动。
   ⚠⚠ 不许拿掉，也不许把别的字体排到它前面（那个字体就成了第一个可用字体，Safari 的基线又回到它自带的度量）。
   ⚠ 覆盖描述符（下面与 fonts/v1/*.css 里的）留着：认它们的引擎里行高 normal 的行、行内背景用得上；
     但**基线从此不靠它们**。换 Newsreader 文件时重跑 make-strut（它从 Newsreader 读 x 高这些数）。
   ========================================================================== */
@font-face { font-family: "Whence Strut"; font-style: normal; font-weight: 1 1000; font-display: swap;
  src: url("fonts/v2/whence-strut.woff") format("woff"); unicode-range: U+0020; }
@font-face { font-family: "Whence Strut"; font-style: italic; font-weight: 1 1000; font-display: swap;
  src: url("fonts/v2/whence-strut.woff") format("woff"); unicode-range: U+0020; }

/* ==========================================================================
   −1. Newsreader 的字重补全
   --------------------------------------------------------------------------
   fonts/v1/dineloc-latin.css 只声明了 400 / 600 / 400 斜体三个**精确**字重。界面里有 31 处
   `font-weight: 500`（签、地名、选择器的行、月历的数字、时刻……）。WebKit 碰到没有正好对上的字面，
   会把 500 / 700 / 600 斜体造成一个加粗的派生字体（拉丁字宽 +6%；在认覆盖描述符的 WebKit 主干里，
   派生的那一份还丢掉 ascent-override）。这里给同一族补上**字重区间**，同样的文件、同样的覆盖值：
   任何字重都有一个正好对上的字面，不再造派生字体。与 dineloc-latin.css 那几条并存（同文件，打平时
   后声明的赢，结果相同），不多下载任何东西。行盒的基线不归这里管，归上面的支柱字体（−2）。
   ⚠ 换 Newsreader 文件（fonts/v2/）时这里的路径与 unicode-range 一起换。
   ========================================================================== */
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 1 500; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-latin-400.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 501 1000; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-latin-600.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Newsreader"; font-style: italic; font-weight: 1 1000; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-latin-italic.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 1 500; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-latin-ext-400.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 501 1000; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-latin-ext-600.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Newsreader"; font-style: italic; font-weight: 1 1000; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-latin-ext-italic.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 1 500; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-vietnamese-400.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 501 1000; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-vietnamese-600.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }
@font-face { font-family: "Newsreader"; font-style: italic; font-weight: 1 1000; font-display: swap; ascent-override: 87.5%; descent-override: 12.5%; line-gap-override: 0%;
  src: url("fonts/v1/newsreader-vietnamese-italic.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; }

/* ==========================================================================
   −0. 海与湖的印「≈」（ADDENDUM-5 用户定案 7 · E19）
   --------------------------------------------------------------------------
   Newsreader 没有「≈」（U+2248 不在它任何一个切片里），印面字原先逐字回退到系统字体：Blink 与 WebKit 各挑一个
   （Iowan / Georgia / Times……），墨的高低各不相同，WebKit 在 40 / 56px 上偏出 E7 的 ±4%。这里给印面字一个**真有这个字形**
   的字体：自托管的 Noto Serif SC 里带着 U+2248 的那一个切片（fonts/v1/noto-serif-sc-073.woff2，≈ 10 KB，可变字重 400–600），
   另起一个族名、unicode-range 只有 U+2248，所以它只画「≈」，别的字一概不碰；两家引擎画的是同一个字形，墨心同一个数
   （app.js SEAL_INK.approx，canvas 实测）。font-display: block：第一次出现时宁可空一瞬，也不先闪一个回退的「≈」再跳。
   ⚠ 只给印面字用（--seal-latin）。换这个文件就重量 SEAL_INK.approx（docs/optics 的 seal≈ 那几行）。
   ========================================================================== */
@font-face { font-family: "Seal Approx"; font-style: normal; font-weight: 400 600; font-display: block;
  src: url("fonts/v1/noto-serif-sc-073.woff2") format("woff2"); unicode-range: U+2248; }

/* ==========================================================================
   0. 令牌
   ========================================================================== */

:root {
  /* ---- 家族（Parote 原值，深色 = 基底）---- */
  --bg: #16120d;
  --bg-elev: #1f1a13;
  --bg-elev2: #2a2319;
  --bg-sunken: #120f0a;
  --panel-fill: #251f16;
  --border: #352c20;
  --border-soft: #2a2318;
  --text: #ece4d6;
  --text-dim: #a89c89;
  --text-faint: #948a76;
  --accent: #d8755c;
  --accent-strong: #e0866f;
  --accent-contrast: #2a1207;
  --accent-soft: rgba(216, 117, 92, .16);
  --accent-line: rgba(216, 117, 92, .42);
  --ok: #86b98a;
  --warn: #d9a441;
  --danger: #e0685e;
  --shadow-sm: 0 2px 10px rgba(0, 0, 0, .3);
  --shadow: 0 10px 30px rgba(0, 0, 0, .42);
  --shadow-lg: 0 24px 70px rgba(0, 0, 0, .55);
  --shadow-pill: 0 8px 20px -8px rgba(0, 0, 0, .72), 0 2px 6px -3px rgba(0, 0, 0, .56);
  --paper-noise: .13;
  /* 遮罩（ADDENDUM-3 §G / E3）：桌面上盖满整窗（rail、panel、地图一起），手机上盖住底下那一页。
     深色用黑 .46；浅色用暖墨（纸上压一层黑是灰的，压一层墨才是暖的）。小浮层叠在表单上时只用一半（CSS 里 opacity .5）。 */
  --scrim: rgba(0, 0, 0, .46);
  /* 开关的圆钮：深色里用纸墨色，浅色里用纸白（值都取自上面已有的令牌，不是新颜色） */
  --knob: var(--text);
  /* 回车会选的那一行（E5.5「纸上的墨」）的底色 = 根上的 --bg-elev2。⚠ 在 :root 上取值：浮板（.picker__panel）
     把 --bg-elev2 降成了 --panel-fill（手机选择器的底就是它），在那里直接写 var(--bg-elev2) 等于没有底色 */
  --fill-hi: var(--bg-elev2);

  /* ---- 表现（DESIGN §10.2）---- */
  --seal: #d8755c;
  --seal-glyph: #2a1207;
  --seal-sea: #79abcf;
  --seal-sea-glyph: #0f0c08;
  --band-1: #e5ddd0;
  --band-2: #b5ada0;
  --band-3: #877f73;
  --band-4: #5e574d;
  --ticket-bg: var(--bg-elev);
  --leader: var(--border);
  /* 品牌小印（DESIGN §10.8，扑勺：纸格子上一只朱豹扑向一把调羹）：格子、描边、豹与勺（coat）、三枚斑与勺里一点（spot）、眼（cut）。
     深色：斑、一点、眼都挖成格子色。两个浅色块各写前四个；--brand-cut 只写在这里（var(--brand-tile) 跟着浅色块的格子走）。 */
  --brand-tile: #2a2319;
  --brand-rim: #352c20;
  --brand-coat: #d8755c;
  --brand-spot: var(--brand-tile);   /* 深色：斑、一点都挖成格子色 */
  --brand-cut: var(--brand-tile);    /* 眼 */

  /* ---- 地图（globe.js 在 init / themeChanged 时读一次，从不逐帧读；DESIGN §7.1 S5 原值）---- */
  --map-ocean: #0f0c08;
  --map-land: #241e16;
  --map-border: #4a3f30;
  --map-sub: #322a1f;
  --map-seam: rgba(22, 18, 13, .45);
  --map-grat: #1f1a13;
  --map-limb: #2e261c;
  --ramp-1: #523126;
  --ramp-2: #7b4435;
  --ramp-3: #a85a46;
  --ramp-4: #d8755c;
  --ramp-5: #f0a782;
  --sea-ink: #79abcf;
  /* 深浅是无级的（ADDENDUM-5 E15）：上面五个 --ramp-k 是**锚点**，不是五个阶。globe.js 把它们解成 OKLab，
     锚点位置按相邻锚点的 OKLab 距离累加再归一，任何一个次数的深度 d ∈ [0,1] 落在两个锚点之间就在它们之间连续插值
     （每个次数都有自己的深浅）。斜线（ADDENDUM-3 §F「染 + 刻」V3）同理：淡晕 = rampInk(d) × --wash-a-k 在锚点之间线性，
     细线颜色（--hatch-line-k 的 OKLab 插值）与线宽（--hatch-w-k 线性）也一样；19°、间距 4.5px 说「这是一片」。
     线色锚点是 ramp（深色：3 3 4 4 4 —— 最深两个锚点都用 ramp 4：无级之后一片全境是最大值时它就是 d = 1，
     整片发光的 ramp 5 细线会盖过它上面的实色省，E15.2.5）。globe.js、图例的条、账本的条只读这三组（一套颜料，没有分叉）。 */
  --wash-a-1: .26;
  --wash-a-2: .34;
  --wash-a-3: .36;
  --wash-a-4: .38;
  --wash-a-5: .42;
  --hatch-line-1: #a85a46;
  --hatch-line-2: #a85a46;
  --hatch-line-3: #d8755c;
  --hatch-line-4: #d8755c;
  --hatch-line-5: #d8755c;
  --hatch-w-1: .5px;
  --hatch-w-2: .7px;
  --hatch-w-3: .8px;
  --hatch-w-4: .9px;
  --hatch-w-5: 1.05px;

  /* ---- 不随主题变的 ---- */
  --radius: .8125rem;
  --radius-sm: .5rem;
  --radius-card: 12px;
  --radius-sheet: 1.125rem;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-stamp: cubic-bezier(.1, .9, .2, 1);
  --ease-exit: cubic-bezier(.55, 0, .85, .35);
  /* ==== 进出的时间表（ADDENDUM-3 E8：每一次出现与消失都是过渡，非线性）——全应用只有这一张 ====
     进用 --ease（减速落定），出用 --ease-exit（加速离开）；没有弹簧、没有 linear。
     ⚠ 数只写在这里：CSS 一律 var(--t-…)；app.js 的收尾定时器（浮层落 hidden、提示条收掉、列表删行、换页的锁高）
       用 tms('--t-…') 从这里读（DLUI.tms 给 ui-map / ui-settings / globe 用），不另写毫秒数。
     ⚠ 不随主题变：只写在这个基底 :root 里，两个浅色块继承（颜色才三块都写）。
     减少动态效果：第 10 节的全局规则把时长压到 ≈ 0，JS 的 tms() 同时回 0 —— 每一处都直接落在终态。 */
  --t-in: 220ms;          /* 浮层进：居中的纸（表单 / 小浮层 / 对话框 / 调色板）、停靠页、说明条 */
  --t-sheet-in: 300ms;    /* 手机上从底边滑上来的表单（走的路长，多给一点） */
  --t-out: 170ms;         /* 浮层出 */
  --t-grow: 300ms;        /* 展开：高度长出来（Parote growBox / swapBox 的 SWAP_H）、列表里插进一行 */
  --t-shrink: 220ms;      /* 收起：列表删一行、「哪一处？」回答后、补记提示关掉 */
  --t-swap: 130ms;        /* 换内容：旧内容先淡出（swapBox 的 SWAP_FADE，「快出」） */
  --t-swap-in: 260ms;     /* 换内容：新内容淡入 + scale(.988) → 1（「慢进」） */
  --t-scrim-in: 260ms;    /* 遮罩 / 大块变暗变亮：进 */
  --t-scrim-out: 190ms;   /* 遮罩：出（浮层的 hidden 等它走完才落） */
  --t-toast-in: 180ms;    /* 提示条：进（淡入 + 从 .375rem 下方升起） */
  --t-toast-out: 140ms;   /* 提示条：出 */
  --t-xfade: 260ms;       /* 画布的淡入淡出（球↔平、报头换取景），globe.js 读它 */
  --t-view: 140ms;        /* 换页签：新的一页与顶栏标题一起淡入（DESIGN §10.6「页签 / 视图」）；月历换月、周印带换周同此 */
  --t-retint: 480ms;      /* 重新着色：那几处（或整张图的顶）从旧色缓缓换到新色（ADDENDUM-5 E15.4），globe.js 读它 */
  --tilt: 19deg;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  /* iOS 浏览器标签页里 = calc(100vh - 100dvh)，由下面 html[data-browser="ios"] 那一节给；
     这一截由底部页签栏自己吃掉，绝不加在 .app 上（家族铁律 E3） */
  --tb: 0px;
  --chrome-bottom: max(var(--safe-bottom), var(--tb));
  /* 软键盘高度：app.js 从 visualViewport 量出来写在 <html> 上。只拿来做 transform */
  --kb: 0px;
  --topbar-h: 2.75rem;
  --tabbar-h: 3.0625rem;
  --gutter: 16px;
  --panel-w: 400px;
  --rail-w: 72px;
  --map-h: min(56lvh, calc(100vw + 40px));
  /* 今天页报头小图的高（§G）：844 高的手机 ≈ 253px，932 高封顶 272；小屏（高 ≤ 700）在第 11 节再收一档 */
  --mast-h: clamp(11rem, 30svh, 17rem);
  --omni-h: 3.5rem;

  /* ---- 字体栈（Parote 原样 + ADDENDUM A1）----
     ⚠ 拉丁衬线排在任何 CJK 字体之前（CJK 字体自带的拉丁字母偏小偏高）；
     ⚠ 四个自托管 Noto 排在任何系统字体之前；绝不列宋体、ヒラギノ明朝这类地区性系统衬线
       （iOS 26 根本没有中文衬线，逐字回落会一行里蹦出黑体字）；以通用 serif 收尾。 */
  /* ⚠⚠ "Whence Strut" 必须排第一：它是第一个可用字体，行盒的基线由它定（见文件头 −2）；它不画任何字 */
  --latin-serif: "Whence Strut", "Newsreader", "Iowan Old Style", Georgia, "Times New Roman";
  /* 印面上的拉丁短码与「≈」（SVG <text>，不经过行盒，所以不用支柱打头）：「≈」由 Seal Approx 画（文件头 −0），字母照常是 Newsreader */
  --seal-latin: "Seal Approx", var(--latin-serif), serif;
  --web-sc: "Noto Serif SC";
  --web-tc: "Noto Serif TC";
  --web-jp: "Noto Serif JP";
  --web-kr: "Noto Serif KR";
  --pan-cjk: "Source Han Serif SC", "Source Han Serif TC", "Source Han Serif", "Source Han Serif K", "Noto Serif CJK SC", "Noto Serif CJK TC";
  --face-sc: var(--web-sc), var(--web-tc), var(--web-jp), var(--web-kr);
  --face-tc: var(--web-tc), var(--web-sc), var(--web-jp), var(--web-kr);
  --face-deva: "Noto Serif Devanagari";
  --face-arab: "Noto Naskh Arabic";
  --font-serif: var(--latin-serif), var(--face-sc), var(--face-deva), var(--face-arab), var(--pan-cjk), serif;
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans", "Helvetica Neue", "Microsoft YaHei", system-ui, sans-serif;

  /* ---- 光学居中（ADDENDUM-3 E7；scratchpad optics 探针实测，Apple 平台）----
     系统界面字体的行盒中线比字的墨心高 0.028em：SF 的 ascent / descent 0.967 / 0.211 → 盒心在基线上 0.378em，
     而苹方的汉字、冬青黑体的假名、Apple SD Gothic 的韩文、SF 的拉丁大写，墨心都在 0.35–0.37em。
     固定高度、行高 1 的小签（.pill .dish__flag .prow__badge）在底边多垫 2 × 这个量，字回到框的正中
     （WebKit +2.5% → 0；Blink +4.8% → +2%）。⚠ 行高 > 1 的按钮、分段不用它：Blink 把正的半行距向下取整，
     那一类在 Blink 里本来就偏高半像素，再抬就过头；它们在 WebKit 里是 +2.6%，在容差之内。
     衬线（支柱字体定的 87.5 / 12.5，见文件头 −2）的盒心 0.375em 与汉字墨心 0.380em 本来就重合，不需要这个量。 */
  --ink-ui: .028em;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) {
    --bg: #f7f2ea;
    --bg-elev: #fffdf9;
    --bg-elev2: #efe8da;
    --bg-sunken: #f1ebe0;
    --panel-fill: #f7f2ea;
    --border: #e7decb;
    --border-soft: #ede5d6;
    --text: #221d15;
    --text-dim: #645b4c;
    --text-faint: #786e5a;
    --accent: #8f3324;
    --accent-strong: #7c2c1f;
    --accent-contrast: #fff;
    --accent-soft: rgba(143, 51, 36, .085);
    --accent-line: rgba(143, 51, 36, .34);
    --ok: #3f7a59;
    --warn: #a4741a;
    --danger: #b03a2e;
    --shadow-sm: 0 1px 6px rgba(74, 56, 33, .06);
    --shadow: 0 8px 26px rgba(74, 56, 33, .09);
    --shadow-lg: 0 20px 60px rgba(74, 56, 33, .16);
    --shadow-pill: 0 8px 20px -8px rgba(74, 56, 33, .44), 0 2px 6px -3px rgba(74, 56, 33, .32);
    --paper-noise: .14;
    /* 浅色的遮罩用墨色而不是纯黑：纸上压一层黑是灰的，压一层墨才是暖的 */
    --scrim: rgba(34, 29, 21, .22);
    --knob: var(--bg-elev);

    --seal: #9e3a2b;
    --seal-glyph: #fffdf9;
    --seal-sea: #356890;
    --seal-sea-glyph: #fffdf9;
    --band-1: #322d24;
    --band-2: #5b5449;
    --band-3: #877f72;
    --band-4: #b5ad9f;
    --brand-tile: #f2ead9;
    --brand-rim: #e2d8c4;
    --brand-coat: #9e3a2b;
    --brand-spot: #26211a;

    --map-ocean: #ede5d6;
    --map-land: #faf7f1;
    --map-border: #c4b79f;
    --map-sub: #e0d5c1;
    --map-seam: rgba(250, 247, 241, .55);
    --map-grat: #e3d9c6;
    --map-limb: #d9cdb7;
    --ramp-1: #f3ccbb;
    --ramp-2: #e8aa93;
    --ramp-3: #d6826a;
    --ramp-4: #b95842;
    --ramp-5: #8f3324;
    --sea-ink: #356890;
    --wash-a-1: .48;
    --wash-a-2: .48;
    --wash-a-3: .52;
    --wash-a-4: .56;
    --wash-a-5: .60;
    --hatch-line-1: #b95842;
    --hatch-line-2: #b95842;
    --hatch-line-3: #8f3324;
    --hatch-line-4: #8f3324;
    --hatch-line-5: #8f3324;
    --hatch-w-1: .6px;
    --hatch-w-2: .7px;
    --hatch-w-3: .8px;
    --hatch-w-4: .85px;
    --hatch-w-5: 1px;
  }
}
:root[data-theme="light"] {
  --bg: #f7f2ea;
  --bg-elev: #fffdf9;
  --bg-elev2: #efe8da;
  --bg-sunken: #f1ebe0;
  --panel-fill: #f7f2ea;
  --border: #e7decb;
  --border-soft: #ede5d6;
  --text: #221d15;
  --text-dim: #645b4c;
  --text-faint: #786e5a;
  --accent: #8f3324;
  --accent-strong: #7c2c1f;
  --accent-contrast: #fff;
  --accent-soft: rgba(143, 51, 36, .085);
  --accent-line: rgba(143, 51, 36, .34);
  --ok: #3f7a59;
  --warn: #a4741a;
  --danger: #b03a2e;
  --shadow-sm: 0 1px 6px rgba(74, 56, 33, .06);
  --shadow: 0 8px 26px rgba(74, 56, 33, .09);
  --shadow-lg: 0 20px 60px rgba(74, 56, 33, .16);
  --shadow-pill: 0 8px 20px -8px rgba(74, 56, 33, .44), 0 2px 6px -3px rgba(74, 56, 33, .32);
  --paper-noise: .14;
  --scrim: rgba(34, 29, 21, .22);
  --knob: var(--bg-elev);

  --seal: #9e3a2b;
  --seal-glyph: #fffdf9;
  --seal-sea: #356890;
  --seal-sea-glyph: #fffdf9;
  --band-1: #322d24;
  --band-2: #5b5449;
  --band-3: #877f72;
  --band-4: #b5ad9f;
  --brand-tile: #f2ead9;
  --brand-rim: #e2d8c4;
  --brand-coat: #9e3a2b;
  --brand-spot: #26211a;

  --map-ocean: #ede5d6;
  --map-land: #faf7f1;
  --map-border: #c4b79f;
  --map-sub: #e0d5c1;
  --map-seam: rgba(250, 247, 241, .55);
  --map-grat: #e3d9c6;
  --map-limb: #d9cdb7;
  --ramp-1: #f3ccbb;
  --ramp-2: #e8aa93;
  --ramp-3: #d6826a;
  --ramp-4: #b95842;
  --ramp-5: #8f3324;
  --sea-ink: #356890;
  --wash-a-1: .48;
  --wash-a-2: .48;
  --wash-a-3: .52;
  --wash-a-4: .56;
  --wash-a-5: .60;
  --hatch-line-1: #b95842;
  --hatch-line-2: #b95842;
  --hatch-line-3: #8f3324;
  --hatch-line-4: #8f3324;
  --hatch-line-5: #8f3324;
  --hatch-w-1: .6px;
  --hatch-w-2: .7px;
  --hatch-w-3: .8px;
  --hatch-w-4: .85px;
  --hatch-w-5: 1px;
}

/* 语言决定 CJK 的先后：正體把 TC 放前面、日文 JP、韩文 KR（同一个汉字在几套字形里长得不一样） */
html[lang="zh-Hant"] {
  --font-serif: var(--latin-serif), var(--face-tc), var(--face-deva), var(--face-arab), var(--pan-cjk), serif;
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang TC", "PingFang SC", "Helvetica Neue", "Microsoft JhengHei", system-ui, sans-serif;
}
html[lang="ja"] {
  --font-serif: var(--latin-serif), var(--web-jp), var(--web-sc), var(--web-tc), var(--web-kr), var(--pan-cjk), serif;
  /* ⚠ 日文界面的系统字体不能先落到苹方：同一个汉字会变成中文字形 */
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", "Meiryo", system-ui, sans-serif;
}
html[lang="ko"] {
  --font-serif: var(--latin-serif), var(--web-kr), var(--web-sc), var(--web-tc), var(--web-jp), var(--pan-cjk), serif;
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "Apple SD Gothic Neo", "Malgun Gothic", system-ui, sans-serif;
}

/* ==========================================================================
   1. 基座与固定外壳
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: 100%;
}
/* 基准字号只写在 body 上：写在根上是自指的（rem 按初始值解析） */
body {
  font-size: .9375rem;
  /* ⚠⚠ 固定外壳（家族铁律 E2）：独立模式下 WebKit 无视 overflow:hidden 替你滚窗口，
     键盘收起后外壳整体上移、底下露一条空白。body 钉死，窗口就无处可滚；滚动只发生在 .pane 里 */
  position: fixed;
  inset: 0;
  overflow: hidden;
  touch-action: manipulation;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
/* 内容面与表单放行选择（界面控件默认不可选，长按不出放大镜） */
input, textarea, .selectable {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* iOS 浏览器标签页：外壳按 vh（≡ lvh）铺满，多出的那一条 --tb 由页签栏自己吃掉 */
@supports (height: 100dvh) {
  html[data-browser="ios"] { --tb: calc(100vh - 100dvh); }
  html[data-browser="ios"] body { bottom: auto; height: 100vh; }
}

/* 宣纸纸纹：固定的单色分形噪声，铺在暖底之上、内容之下。永远不画进画布。 */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--paper-noise);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.6' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='260' height='260' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 260px 260px;
}
/* iOS 触屏上去掉：固定层伸不到 Safari 的工具栏底下，会留下色带（Paral 的教训） */
@supports (-webkit-touch-callout: none) {
  @media (pointer: coarse) { body::before { display: none; } }
}

[hidden] { display: none !important; }

button { font: inherit; color: inherit; }
a { color: var(--accent); text-decoration: none; }
::selection { background: var(--accent-soft); color: inherit; }

/* 焦点环：全局 2px --accent。组件只准改 offset，不准改颜色（--accent-line 合成后只有 1.8:1）。
   ⚠ ADDENDUM-4 E14.5（用户：「所有住处点完之后有红框；地图按 ESC 以后有红黑框」）：环**只给键盘导航**。
     app.js 在捕获阶段记下最近一次是怎么动的 → <html data-focus="pointer" | "key">；只有 Tab / 方向键 / Home / End /
     PageUp / PageDown 算「在用键盘走」（Esc、回车、空格不算：Esc 关掉浮层、焦点回到开它的按钮，那一下不该出环）。
     浏览器自己的 :focus-visible 启发式在点击按钮后、程序聚焦后都可能为真，所以不能只靠它。
   ⚠ :where() 把前缀的特指度压成 0：组件那几条 `.x:focus-visible { outline-offset … }` 照样压得过这一条。
     文本框不在这里：它们的焦点画在外壳上（.field:focus-within），一直都有（打字的地方要看得见）。 */
:focus { outline: none; }
:focus-visible { outline: none; }
:where(html[data-focus="key"]) :focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: .25rem;
}
/* 程序聚焦的容器（面板、列表）不画环：那一圈没有信息，Tab 一下就落到真正的控件上 */
[tabindex="-1"]:focus { outline: none; }

* { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
*::-webkit-scrollbar { width: .625rem; height: .625rem; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--border); border: 3px solid transparent; background-clip: content-box; border-radius: 99px; }

/* 图标：app.js 的 icon() 造，尺寸由它用 CSSOM 写成 rem。flex 里一律不缩（行内 svg 能被压到 0）。 */
.ico { flex: none; display: block; }
.ico--down { transform: rotate(90deg); }
.ico--up { transform: rotate(-90deg); }
.ico--prev { transform: rotate(180deg); }
/* 有方向的图标在 RTL 下翻转（chevron / back）；上下方向的不翻 */
[dir="rtl"] .ico--dir { transform: scaleX(-1); }
[dir="rtl"] .ico--prev.ico--dir { transform: none; }
/* 转成上下方向的 chevron 不跟着书写方向翻（否则 RTL 下「▾」变成「‹」） */
[dir="rtl"] .ico--down { transform: rotate(90deg); }
[dir="rtl"] .ico--up { transform: rotate(-90deg); }

/* 用户写的东西（菜名、地名、在哪吃）和按语言格式化的钟点，方向由内容自己定：
   英文界面里的一个阿拉伯文菜名、#dev=rtl 下的「12 PM」，标点与省略号都落在该落的一头 */
.dish__name, .dish__place, .chip__label, .prow__label, .prow__sub, .repeat__name,
.ticket__meta-part > span, .venue, .ed__setlabel, .ticket__time, .kicker__text, .toast__msg, .now__attext, .mast__place {
  unicode-bidi: plaintext;
}

.vh {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   2. 共用控件（CONTRACT §6.4；G 与 D 直接用，不重定义）
   ========================================================================== */

.iconbtn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.875rem;
  height: 1.875rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: background 140ms var(--ease), color 140ms var(--ease), transform 90ms var(--ease);
}
.iconbtn:hover { background: var(--bg-elev2); color: var(--text); }
.iconbtn:active { transform: scale(.94); }
.iconbtn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); }
html[data-touch="on"] .iconbtn { width: 2.375rem; height: 2.375rem; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4375rem;
  min-height: 2.25rem;
  padding: 0 .9375rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-elev);
  color: var(--text);
  font: inherit;
  font-size: .875rem;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  transition: background 140ms var(--ease), border-color 140ms var(--ease), color 140ms var(--ease), transform 90ms var(--ease);
}
.btn:hover { background: var(--bg-elev2); }
.btn:active { transform: scale(.985); }
.btn--primary { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); font-weight: 600; }
.btn--primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn--ghost { background: transparent; border-color: transparent; color: var(--text-dim); }
.btn--ghost:hover { background: var(--bg-elev2); color: var(--text); }
.btn--danger { color: var(--danger); }
.btn--sm { min-height: 1.875rem; padding: 0 .6875rem; font-size: .8125rem; }
.btn:disabled { opacity: .42; cursor: default; }
.btn:disabled:hover { background: var(--bg-elev); border-color: var(--border); }
.btn--primary:disabled:hover { background: var(--accent); border-color: var(--accent); }
.btn--ghost:disabled:hover { background: transparent; border-color: transparent; }
html[data-touch="on"] .btn { min-height: 2.5rem; }
html[data-touch="on"] .btn--sm { min-height: 2.25rem; }
/* ⚠ 触屏上的「粘住的 hover」：只复位非填色的，填色的各自再写一遍（家族 F5） */
@media (hover: none) {
  .btn:hover { background: var(--bg-elev); }
  .btn--ghost:hover { background: transparent; color: var(--text-dim); }
  .btn--primary:hover { background: var(--accent); border-color: var(--accent); }
  .iconbtn:hover { background: transparent; color: var(--text-dim); }
  .iconbtn[aria-pressed="true"]:hover { background: var(--accent-soft); color: var(--accent); }
}

/* 分段控件 */
.seg {
  display: inline-flex;
  flex: none;
  padding: 2px;
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
}
.seg__btn {
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: .8125rem;
  line-height: 1.2;
  min-height: 1.75rem;
  padding: .25rem .75rem;
  border-radius: .375rem;
  white-space: nowrap;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  transition: background 150ms var(--ease), color 150ms var(--ease);
}
.seg__btn:hover { color: var(--text); }
.seg__btn[aria-pressed="true"] { background: var(--bg-elev); color: var(--text); box-shadow: var(--shadow-sm); }
html[data-touch="on"] .seg__btn { min-height: 2.125rem; padding-block: .4375rem; }

/* 签一行：横向滚动，两端淡出。淡出只在「那一头还有东西」时出现（app.js 写 data-fade）。 */
.chips {
  --fs: 0px;
  --fe: 0px;
  display: flex;
  align-items: center;
  gap: .5rem;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  padding-block: .25rem;
  -webkit-mask-image: linear-gradient(to right, transparent 0, black var(--fs), black calc(100% - var(--fe)), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, black var(--fs), black calc(100% - var(--fe)), transparent 100%);
}
[dir="rtl"] .chips {
  -webkit-mask-image: linear-gradient(to left, transparent 0, black var(--fs), black calc(100% - var(--fe)), transparent 100%);
  mask-image: linear-gradient(to left, transparent 0, black var(--fs), black calc(100% - var(--fe)), transparent 100%);
}
.chips::-webkit-scrollbar { display: none; }
.chips[data-fade~="start"] { --fs: 1.75rem; }
.chips[data-fade~="end"] { --fe: 1.75rem; }
/* 贴边出血：签行滚到屏幕边缘才自然 */
.chips--bleed { margin-inline: calc(-1 * var(--gutter)); padding-inline: var(--gutter); scroll-padding-inline: var(--gutter); }
/* 表单里出血到表单自己的内边距（1.125rem），不是页面的 --gutter：否则签行从面板边上探出去 */
.sheet__body .chips--bleed { margin-inline: -1.125rem; padding-inline: 1.125rem; scroll-padding-inline: 1.125rem; }

.chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  height: 2.25rem;
  max-width: 16rem;
  padding-inline: .4375rem .8125rem;
  /* ⚠ 上下也要写：签是 <button>，WebKit 的 UA 给按钮 padding 2px 6px 3px（上 2 下 3），
     只写 padding-inline 的话字在 Safari 里整体高 0.5px（Blink 的 UA 是对称的 1px，看不出来） */
  padding-block: 0;
  border: 1px solid var(--border);
  border-radius: .625rem;
  background: var(--bg-elev);
  color: var(--text);
  font-family: var(--font-serif);
  font-size: .9375rem;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background 140ms var(--ease), border-color 140ms var(--ease), transform 90ms var(--ease);
}
.chip:hover { border-color: var(--text-faint); }
.chip:active { transform: scale(.985); }
.chip__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; padding-block: .125rem; }
.chip--unclear { border-style: dashed; background: transparent; color: var(--text-dim); }
.chip--plain { padding-inline: .8125rem; }
.chip--ui { font-family: var(--font-ui); font-size: .8125rem; font-weight: 500; color: var(--text-dim); background: transparent; }
.chip--ui .ico { color: var(--text-faint); }
.chip[aria-pressed="true"] { background: var(--text); border-color: var(--text); color: var(--bg); }
@media (hover: none) { .chip:hover { border-color: var(--border); } }
html[data-touch="on"] .chips { padding-block: .25rem; }

/* 说明字：26×3 的印章红短条 + 小号字（Paral 的 kicker） */
.kicker {
  display: inline-flex;
  align-items: center;
  gap: .625rem;
  margin: 0;
  font-family: var(--font-ui);
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: .16em;
  color: var(--accent);
}
.kicker::before {
  content: "";
  flex: none;
  width: 26px;
  height: 3px;
  border-radius: 2px;
  background: currentColor;
}
/* 字距按文字来：汉字 .24em；拉丁/西里尔大写 .16em；日韩收一点；
   ⚠ 阿拉伯文、天城文、孟加拉文、泰文**一点字距都不能加**（连写会被拆开） */
/* ⚠ .24em 是给汉字的；数字挤在里面会被拆成「1 3时」。中文说明字里总有一个钟点，所以收到 .18em */
html:lang(zh) .kicker { letter-spacing: .18em; }
html:is(:lang(en), :lang(es), :lang(pt), :lang(fr), :lang(de), :lang(it), :lang(nl), :lang(pl), :lang(ru), :lang(uk), :lang(tr), :lang(vi), :lang(id), :lang(ms), :lang(fil)) .kicker { text-transform: uppercase; }
html:is(:lang(ja), :lang(ko)) .kicker { letter-spacing: .12em; }
html:is(:lang(ar), :lang(fa), :lang(ur), :lang(he), :lang(hi), :lang(bn), :lang(th)) .kicker { letter-spacing: 0; font-size: .75rem; }

.pill {
  display: inline-flex;
  align-items: center;
  flex: none;
  height: 1.375rem;
  padding: 0 .5rem;
  padding-block-end: calc(2 * var(--ink-ui));   /* 墨心居中，见 :root --ink-ui */
  border: 1px solid var(--text-faint);
  border-radius: 99px;
  font-family: var(--font-ui);
  font-size: .6875rem;
  font-weight: 500;
  line-height: 1;
  color: var(--text-dim);
  white-space: nowrap;
}

/* 空态基座：一种长相。每一句都此刻为真，后面跟那一个能用的动作 */
.zero {
  text-align: center;
  color: var(--text-faint);
  font-size: .78125rem;
  line-height: 1.7;
  padding: 1.5rem var(--gutter);
}
.zero__title { display: block; color: var(--text-dim); font-weight: 600; margin-bottom: .1875rem; }
.zero__act { margin-top: .875rem; }

/* 分组列表行（设置、地方页） */
.rows {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--bg);
  overflow: hidden;
}
.row {
  display: flex;
  align-items: center;
  gap: .75rem;
  width: 100%;
  min-height: 3rem;
  margin: 0;
  padding: .6875rem .875rem;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: .9375rem;
  text-align: start;
}
.row + .row { border-top: 1px solid var(--border-soft); }
button.row, a.row, .row--toggle { cursor: pointer; transition: background 140ms var(--ease); }
button.row:hover, a.row:hover, .row--toggle:hover { background: var(--bg-elev2); }
.row__label { flex: 1 1 auto; min-width: 0; }
.row__sub { display: block; margin-top: .125rem; font-size: .75rem; line-height: 1.45; color: var(--text-faint); }
.row__value { flex: 0 1 auto; min-width: 0; max-width: 55%; color: var(--text-dim); font-size: .875rem; text-align: end; overflow-wrap: anywhere; }
.row--danger { color: var(--danger); }
.row > .ico { color: var(--text-faint); }
@media (hover: none) { button.row:hover, a.row:hover, .row--toggle:hover { background: transparent; } }

/* 文本框：圈在外壳上（:focus-within），框内无框。
   ⚠ ADDENDUM-4 E14.1（「在哪吃」：行尾被裁、光标贴着起边、候选签贴着框底）：外壳占满它那一栏（inline-size 100%，
     border-box），自己不许比栏宽（min-inline-size 0）；字离两边各 .75rem（padding-inline，输入框自己不再带内边距）；
     输入框去掉引擎自带的外观（iOS 的圆角、内阴影、内边距），并且可以缩到 0（WebKit 给 <input> 的最小宽是 20 个字）。 */
.field {
  display: flex;
  align-items: center;
  gap: .5rem;
  inline-size: 100%;
  min-width: 0;
  min-height: 2.5rem;
  padding-block: 0;
  padding-inline: .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  color: var(--text-faint);
  transition: border-color 140ms var(--ease), background 140ms var(--ease);
}
.field:focus-within { border-color: var(--accent-line); background: var(--bg-elev); }
.field > input,
.field > textarea {
  flex: 1 1 auto;
  min-width: 0;
  inline-size: 100%;
  margin: 0;
  padding: .5rem 0;
  -webkit-appearance: none;
  appearance: none;
  border-radius: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 1rem;           /* ⚠ < 16px 时 iOS 聚焦会放大整页 */
  line-height: 1.45;
  outline: none;
}
.field > textarea { resize: none; min-height: 4.5rem; padding-block: .625rem; field-sizing: content; }
.field > input::placeholder,
.field > textarea::placeholder { color: var(--text-faint); opacity: 1; }
.field > .ico { color: var(--text-faint); }
.field--area { align-items: flex-start; }
.field--area > .ico { margin-top: .75rem; }

/* 开关：真的 <input type=checkbox role=switch> */
.toggle {
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  position: relative;
  width: 2.625rem;
  height: 1.5rem;
  margin: 0;
  border: 0;
  border-radius: 99px;
  background: var(--border);
  cursor: pointer;
  transition: background 160ms var(--ease);
}
.toggle::after {
  content: "";
  position: absolute;
  top: 3px;
  inset-inline-start: 3px;
  width: calc(1.5rem - 6px);
  height: calc(1.5rem - 6px);
  border-radius: 50%;
  background: var(--knob);
  box-shadow: var(--shadow-sm);
  transition: transform 180ms var(--ease);
}
.toggle:checked { background: var(--accent); }
.toggle:checked::after { transform: translateX(1.125rem); }
[dir="rtl"] .toggle:checked::after { transform: translateX(-1.125rem); }
.toggle:disabled { opacity: .42; cursor: default; }

/* 数字：大号 Newsreader，会变的数一律等宽 */
.facts {
  display: grid;
  grid-template-columns: 1fr 1fr;     /* 永远 2×2，不许 3+1 */
  gap: 1px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  background: var(--border-soft);
  overflow: hidden;
}
.stat { min-width: 0; padding: .875rem 1rem .8125rem; background: var(--bg); }
.stat__num {
  display: block;
  height: 1.15em;
  font-family: var(--font-serif);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -.02em;
  font-variant-numeric: lining-nums tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.stat__label { display: block; margin-top: .375rem; font-size: .75rem; font-weight: 500; line-height: 1.4; color: var(--text-dim); }

.sub-en {
  font-family: var(--latin-serif), serif;
  font-style: italic;
  font-size: .8125rem;
  line-height: 1.4;
  color: var(--text-faint);
}
/* 当地文字副名（ዶሮ ወጥ、مجبوس）：系统界面字体、不斜体、方向由 dir=auto 自己判 */
.sub-loc {
  font-family: var(--font-ui);
  font-style: normal;
  font-size: .8125rem;
  line-height: 1.4;
  color: var(--text-faint);
  unicode-bidi: plaintext;
}

/* 斜线小样：「这一片之中」（全境之中，或几处之一）。19° 偏离竖直，间距 4.5px（与地图同一套颜料，§F）。
   深浅是无级的（ADDENDUM-5 E15）：没有「第几阶」的类。用它的地方（ui-map 的账本条）按那一行的深度 d 用 CSSOM 写
   --hatch-wash / --hatch-c / --hatch-w（值来自 DLGlobe.inks(d)，与地图同一个函数）；不写时读第 3 个锚点的令牌。 */
.hatch-bg {
  --hatch-c: var(--hatch-line-3);
  --hatch-w: var(--hatch-w-3);
  --hatch-wash: color-mix(in srgb, var(--ramp-3) calc(var(--wash-a-3) * 100%), transparent);
  background-color: var(--hatch-wash);
  background-image: repeating-linear-gradient(calc(90deg + var(--tilt)), var(--hatch-c) 0 var(--hatch-w), transparent var(--hatch-w) 4.5px);
}

/* ==========================================================================
   3. 印、品牌小印、饭票
   ========================================================================== */

/* 印：4 条静态轮廓之一（按 id 哈希）+ 镂空或朱色的字。--s = 边长（px），--rot = 固定倾角 */
.seal {
  --s: 22px;
  --rot: 0deg;
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--s);
  height: var(--s);
  vertical-align: middle;
  line-height: 1;
  transform: rotate(var(--rot));
}
.seal__shape { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.seal--solid .seal__shape { fill: var(--seal); }
.seal--outline .seal__shape { fill: none; stroke: var(--seal); stroke-width: 2.6; }
.seal--round .seal__shape { fill: var(--seal-sea); }
.seal--dashed .seal__shape { fill: none; stroke: var(--text-faint); stroke-width: 1.4; stroke-dasharray: 3 2.2; }
.seal--untasted .seal__shape { fill: none; stroke: var(--border); stroke-width: 1.4; stroke-dasharray: 3 2.2; }
/* 印字是印自己那张 SVG 里的 <text>（app.js sealFromSpec）：字号与基线由 JS 按墨心写成视框坐标
   （SVG 表现属性，CSP 允许），这里只给字体与颜色。⚠ 这里**不许**写 font-size / line-height / margin 去「微调」：
   那会压过 font-size 属性、把按墨算好的位置整个带偏。⚠ 也不许写 text-rendering：JS 给每个印字写了
   text-rendering="geometricPrecision"，CSS 规则会压过它，落印（scale 2.2）之后字又会缩在左下（seal-flash，test/csp.mjs 11）。 */
.seal__glyph {
  font-family: var(--font-serif);
  font-weight: 600;
  fill: currentColor;
  stroke: none;          /* 朱文的描边写在 .seal__shape 上，会被字继承 —— 字不描边 */
  color: var(--seal-glyph);
  /* 印里的拉丁短码在 RTL 界面里也从左往右写 */
  direction: ltr;
  unicode-bidi: isolate;
  pointer-events: none;
}
.seal[data-latin] .seal__glyph {
  font-family: var(--seal-latin);
  letter-spacing: .02em;
  font-variant-numeric: lining-nums;
}
.seal[data-latin="3"] .seal__glyph { letter-spacing: 0; }
.seal--outline .seal__glyph { color: var(--seal); }
.seal--round .seal__glyph { color: var(--seal-sea-glyph); }
.seal--dashed .seal__glyph { color: var(--text-faint); font-family: var(--latin-serif), serif; font-weight: 400; }
.seal--untasted .seal__glyph { color: var(--text-faint); opacity: .5; }
/* 拿不准：印的右上角一个 8px 的「？」小圆 */
.seal__q {
  position: absolute;
  top: -3px;
  inset-inline-end: -4px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--bg-elev);
  box-shadow: 0 0 0 1px var(--text-faint);
  color: var(--text-dim);
  font: 700 7px/9px var(--font-ui);
  text-align: center;
  transform: rotate(calc(-1 * var(--rot)));
}

/* 加一样菜：只有新加的那一枚印动一下。基础样式 = 终态，减少动态效果时直接出现 */
@keyframes sealAdd {
  from { transform: rotate(var(--rot)) scale(1.3); opacity: .4; }
  to { transform: rotate(var(--rot)); opacity: 1; }
}
.seal.is-added { animation: sealAdd 220ms var(--ease-stamp); }
/* 初尝 · 落印：从 2.2 倍、转 −8°、透明处落下，70% 时略压 .96，回到自己的倾角；
   同时一圈同形墨晕放大淡出（DESIGN §10.6）。 */
@keyframes sealStamp {
  0% { transform: rotate(calc(var(--rot) - 8deg)) scale(2.2); opacity: 0; }
  70% { transform: rotate(var(--rot)) scale(.96); opacity: 1; }
  100% { transform: rotate(var(--rot)) scale(1); opacity: 1; }
}
@keyframes sealHalo {
  from { transform: scale(1); opacity: .28; }
  to { transform: scale(1.25); opacity: 0; }
}
.seal.is-new { animation: sealStamp 360ms var(--ease-stamp) both; }
.seal.is-new::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 16%;
  background: var(--seal);
  opacity: 0;
  pointer-events: none;
  animation: sealHalo 700ms var(--ease) 250ms backwards;
}
.seal--round.is-new::after { border-radius: 50%; background: var(--seal-sea); }

/* 品牌小印：同 icons/icon.svg 的几何（扑勺），颜色全由 --brand-* 给（JS 里不出现任何色值） */
.brand { display: block; flex: none; }
.brand__tile { fill: var(--brand-tile); }
.brand__rim { fill: none; stroke: var(--brand-rim); }
.brand__coat { fill: var(--brand-coat); }
.brand__tail { fill: none; stroke: var(--brand-coat); }
.brand__spot { fill: var(--brand-spot); }
.brand__eye { fill: var(--brand-cut); }

/* 饭票：左边存根（时间）+ 一条竖虚线 + 上下两个半圆缺口；平的，没有阴影 */
.ticket {
  --stub: 3.5rem;
  --notch: 6px;
  position: relative;
  display: grid;
  grid-template-columns: var(--stub) minmax(0, 1fr);
  width: 100%;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--ticket-bg);
  color: var(--text);
  font: inherit;
  text-align: start;
  /* 两个缺口：两层满尺寸的遮罩取交集（上一层挖上缺口、下一层挖下缺口）。
     ⚠ 曾经写成「各占一半高度的两层相加」省掉 mask-composite —— 票高是小数像素时，下半层的
     最后一行设备像素没被盖住，整条底边被切掉（放大四倍截图才看得出）。 */
  --notch-x: calc(var(--stub) + 1.5px);
  -webkit-mask-image:
    radial-gradient(circle at var(--notch-x) 0, transparent var(--notch), black calc(var(--notch) + .5px)),
    radial-gradient(circle at var(--notch-x) 100%, transparent var(--notch), black calc(var(--notch) + .5px));
  -webkit-mask-composite: source-in;
  mask-image:
    radial-gradient(circle at var(--notch-x) 0, transparent var(--notch), black calc(var(--notch) + .5px)),
    radial-gradient(circle at var(--notch-x) 100%, transparent var(--notch), black calc(var(--notch) + .5px));
  mask-composite: intersect;
}
[dir="rtl"] .ticket { --notch-x: calc(100% - var(--stub) - 1.5px); }
/* 缺口的描边：一圈半径 6–7px 的环，只露出票面里那半截 */
.ticket::before,
.ticket::after {
  content: "";
  position: absolute;
  inset-inline-start: calc(var(--stub) + .5px - var(--notch) - 1px);
  width: calc(2 * var(--notch) + 2px);
  height: calc(2 * var(--notch) + 2px);
  border: 1px solid var(--border);
  border-radius: 50%;
  pointer-events: none;
}
.ticket::before { top: calc(-1 * var(--notch) - 2px); }
.ticket::after { bottom: calc(-1 * var(--notch) - 2px); }
button.ticket, .ticket[role="button"] { cursor: pointer; transition: background 140ms var(--ease), transform 90ms var(--ease); }
button.ticket:active, .ticket[role="button"]:active { transform: scale(.992); }
button.ticket:hover, .ticket[role="button"]:hover { background: var(--bg-elev2); }
@media (hover: none) { button.ticket:hover, .ticket[role="button"]:hover { background: var(--ticket-bg); } }
.ticket:focus-visible { outline-offset: 3px; border-radius: var(--radius-card); }

.ticket__stub {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: .5rem;
  min-width: 0;
  padding: .875rem .25rem .75rem;
}
.ticket__time {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -.01em;
  font-variant-numeric: lining-nums tabular-nums;
  text-align: center;
  overflow-wrap: anywhere;
}
.ticket__time--part { font-size: 1.0625rem; line-height: 1.15; }
.ticket__hnum, .ticket__hunit { display: block; }
/* 拉丁等语言的钟点：数字照大号衬线，PM / Uhr / h 收成一行小字（存根只有 56pt 宽） */
.ticket__hunit {
  margin-top: .3125rem;
  font-family: var(--font-ui);
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .08em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--text-dim);
}
/* 拉丁等语言的时段名（Afternoon 61 px、Nachmittag 68 px @13px）比 56pt 的存根宽（验过：「Aftern / oon」）：
   非中日韩界面存根放宽到 4.5rem、时段名 13px；更长的词按语言断字，断字词典缺席时才退回逐字断 */
html:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)) .ticket { --stub: 4.5rem; }
html:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)) .ticket__time--part { font-size: .8125rem; -webkit-hyphens: auto; hyphens: auto; }
/* 初尝角标：存根里一枚小小的朱文章「初」 */
.ticket__first {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 .1875rem;
  border: 1px solid var(--seal);
  border-radius: 3px;
  color: var(--seal);
  font-family: var(--font-serif);
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1;
  transform: rotate(-4deg);
  position: relative;
  cursor: help;
}
/* 「初」可以点（E13）：记号只有 18px，触控区向四周放出 .5rem（不改它的样子） */
.ticket__first::after { content: ""; position: absolute; inset: -.5rem; }

/* 一行小字的说明条（E13「初」的那一句）：一张纸条，app.js 按记号的位置摆（--tx / --ty 是量出来的像素）。
   进：淡入 + 从 .25rem 下方升起（--t-in --ease）；出：淡出（--t-out --ease-exit）；纸条在记号下方时从上方落下。 */
.tip {
  position: fixed;
  /* ⚠ 这里用物理的 top / left 是有意的：--tx / --ty 是 getBoundingClientRect 量出来的物理坐标（RTL 下也从左量） */
  top: 0;
  left: 0;
  z-index: 115;
  translate: var(--tx, 0) var(--ty, 0);
  max-width: min(18rem, calc(100vw - 1rem));
  padding: .375rem .625rem;
  border: 1px solid var(--border);
  border-radius: .5rem;
  background: var(--bg-elev);
  box-shadow: var(--shadow-sm);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: .8125rem;
  line-height: 1.45;
  text-wrap: pretty;
  pointer-events: none;
  opacity: 0;
  transform: translateY(.25rem);
  transition: opacity var(--t-in) var(--ease), transform var(--t-in) var(--ease);
}
.tip__keep { white-space: nowrap; }   /* 日子不折开（E13 的小字） */
.tip[data-below] { transform: translateY(-.25rem); }
.tip.is-open { opacity: 1; transform: none; }
.tip.is-closing { opacity: 0; transition: opacity var(--t-out) var(--ease-exit), transform var(--t-out) var(--ease-exit); }
.ticket__body {
  min-width: 0;
  padding: .3125rem .75rem .5rem .875rem;
  border-inline-start: 1px dashed var(--border);
}
.ticket--edit .ticket__body { padding-inline-end: .25rem; }
.ticket__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .25rem .5rem;
  padding: .125rem 0 .25rem;
  font-size: .75rem;
  line-height: 1.4;
  color: var(--text-faint);
}
.ticket__meta .ico { color: var(--text-faint); }
.ticket__meta-part { display: inline-flex; align-items: center; gap: .3125rem; min-width: 0; }
/* 两段之间不画「·」：各自带着图标就已经分开了；折行时行首也不会挂一个孤零零的点 */
.ticket__meta { column-gap: .875rem; }

/* 菜的一行：菜名 → 点线 → 印 → 地名（× 只在可编辑时） */
.dishwrap {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows var(--t-shrink) var(--ease-exit), opacity var(--t-shrink) var(--ease-exit);
}
.dishwrap > .dish { min-height: 0; overflow: hidden; }
.dishwrap.is-gone { grid-template-rows: 0fr; opacity: 0; }
@keyframes dishBack { from { grid-template-rows: 0fr; opacity: 0; } }
.dishwrap.is-back { animation: dishBack 280ms var(--ease-stamp); }
/* 往已经在的一张票里加了一样：那一行长出来（E8；app.js markRowIn，只演一次） */
.dishwrap.is-in { animation: dishBack var(--t-grow) var(--ease); }
.dish {
  display: flex;
  align-items: center;
  gap: .25rem;
  min-height: 2.5rem;
  width: 100%;
  color: inherit;
  text-align: start;
}
/* 一行放得下：菜名 ······· 印 地名；放不下：where 整块折到第二行（点线仍从行首引到地名） */
.dish__main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: .4375rem;
  row-gap: .0625rem;
  padding-block: .3125rem;
  border-radius: .375rem;
}
.dish__main[role="button"] { cursor: pointer; }
.dish__main:focus-visible { outline-offset: 1px; }
.dish__what { flex: 0 1 auto; min-width: 0; max-width: 100%; display: flex; align-items: center; gap: .4375rem; }
.dish__name {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-serif);
  font-size: 1rem;
  font-weight: 400;
  /* E9.8：24px = 16px + 上下各 4px（整数半行距；1.45 的 3.6px 在 Blink 里取整成 3，菜名比印高 0.6px） */
  line-height: 1.5;
}
.dish__leader {
  flex: 1 1 .75rem;
  min-width: .5rem;
  height: 3px;
  align-self: center;
  margin-top: .45em;
  background-image: radial-gradient(circle, var(--leader) 0 .8px, transparent 1.2px);
  background-size: .3125rem 3px;
  background-repeat: repeat-x;
  background-position: 0 50%;
}
.dish__where {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .375rem;
}
.dish--noname .dish__where { justify-content: flex-start; }
.dish__seals { flex: none; display: inline-flex; align-items: center; gap: .1875rem; }
.dish__place {
  flex: 0 1 auto;
  min-width: 0;
  font-family: var(--font-serif);
  font-size: .9375rem;
  font-weight: 500;
  line-height: 1.3;
  color: var(--text-dim);
  /* 中文只在「、」这类标点处折（不把「吉林」拆成「吉 / 林」）；实在放不下才任意处折 */
  word-break: keep-all;
  overflow-wrap: anywhere;
  text-wrap: balance;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* ADDENDUM-5 E19.4：拉丁字母（与别的有词间空格的文字）的地名永远不在词中间断开 —— 英文此刻卡上「Chinese cuisine ·· [CN] China」
   曾被挤成「Chin / a」：一行放得下时 where 按它的 max-content 挤进这一行，点线的 flex-basis（.75rem）比它的最小宽（.5rem）多出的
   那一点由地名来缩，而 overflow-wrap: anywhere 让地名的最小宽只剩一个字母。这里给地名一个真的最小宽（最长的一个词），
   缩的只能是点线；真放不下时 where 整块换到菜名下面一行（.dish__main 的 flex-wrap）。中文、日文、韩文照旧逐字可断（keep-all + anywhere）。 */
html:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)) .dish__place { overflow-wrap: break-word; min-width: min-content; }
.dish--unclear .dish__place { font-weight: 400; color: var(--text-faint); }
.dish__flag {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: 1.125rem;
  padding: 0 .375rem;
  padding-block-end: calc(2 * var(--ink-ui));   /* 墨心居中，见 :root --ink-ui */
  border: 1px solid var(--border);
  border-radius: 99px;
  font-family: var(--font-ui);
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .04em;
  line-height: 1;
  color: var(--text-dim);
  white-space: nowrap;
}
.dish__x {
  flex: none;
  align-self: center;
  width: 2rem;
  height: 2rem;
  color: var(--text-faint);
}
html[data-touch="on"] .dish__x { width: 2.5rem; height: 2.5rem; margin-block: -.25rem; }

/* ==========================================================================
   4. 外壳布局（手机 < 900px；桌面见第 11 节）
   ========================================================================== */

.app { position: static; display: block; width: 100%; height: 100%; overflow: hidden; }
.rail, .deskmap { display: none; }

.main {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  /* ⚠ 铺满纸色（与 Parote 同）。试过不铺、让 body::before 的纸纹透出来：内容区被灰色噪点压暗一档，
     和不透明的顶栏 / 输入框 / 页签栏之间出现一条色差带，读起来像「脏」—— 而顶栏必须不透明（iOS 取色）。 */
  background: var(--bg);
}

/* 顶栏：sticky + 不透明 + translateZ(0)（iOS 26 从它取铬件颜色；静态的它会停止重采样） */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  flex: none;
  display: flex;
  align-items: center;
  gap: .375rem;
  height: calc(var(--topbar-h) + var(--safe-top));
  padding-top: var(--safe-top);
  padding-left: max(var(--gutter), var(--safe-left));
  padding-right: max(calc(var(--gutter) - .375rem), var(--safe-right));
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
  transform: translateZ(0);
}
.topbar__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -.012em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: lining-nums;
}
.topbar__acts { flex: none; display: flex; align-items: center; gap: .375rem; }
.topbar__nav { display: none; }
#app[data-view="days"] .topbar__nav { display: inline-flex; animation: viewIn var(--t-view) var(--ease); }
#app[data-view="days"] .topbar__title { flex: 0 1 auto; text-align: center; }
#app[data-view="days"] .topbar__acts { margin-inline-start: auto; }
#app[data-view="days"] .topbar__nav:first-child { margin-inline-start: -.5rem; }

.views { position: relative; flex: 1 1 auto; display: flex; min-height: 0; min-width: 0; }
.view { position: relative; flex: 1 1 auto; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* 换页签：新的一页 140ms 淡入（E8；不滑动）。基础样式 = 终态，减少动态效果时直接到位 */
@keyframes viewIn { from { opacity: 0; } }
.view:not([hidden]) { animation: viewIn var(--t-view) var(--ease); }
/* 同一页里换了一份内容（E8）：月历换月、日子页换一天的单子、周印带挪了一天 —— 新的那一份淡入，不滑。
   高度变了的由 app.js growBox / growFrom 过渡（.is-swapping：锁高的那几百毫秒里裁边） */
.calgrid.is-in, .daylist.is-in, .week__cols.is-in { animation: viewIn var(--t-view) var(--ease); }
.cal.is-swapping, .week.is-swapping { overflow: hidden; transition: height var(--t-grow) var(--ease); }
/* 通用的「会长个子的框」（ADDENDUM-4 E14.2）：任何一个框加上 data-grow，就能交给 DLUI.growBox / swapBox
   （锁高那几百毫秒里裁边、高度按时间表过渡）。ui-map / ui-settings 用它，不必各写一条。 */
[data-grow].is-swapping { overflow: hidden; transition: height var(--t-grow) var(--ease); }
/* swapBox 的里层（换一页时先淡出、再淡入）：给那一层加 .grow-in */
.grow-in { transition: opacity var(--t-swap-in) var(--ease), transform var(--t-swap-in) var(--ease); transform-origin: 50% 0; }
.grow-in.is-out { opacity: 0; transform: scale(.988); transition-duration: var(--t-swap); transition-timing-function: var(--ease-exit); }
/* ⚠ 唯一的滚动容器。scrollbar-gutter both-edges：经典滚动条出现时列不左右跳 */
.pane {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable both-edges;
  -webkit-overflow-scrolling: touch;
}

/* 底部页签栏：sticky + 不透明；iOS 标签页多出来的 --tb 由它自己吃掉 */
.tabbar {
  position: sticky;
  bottom: 0;
  z-index: 10;
  flex: none;
  display: flex;
  height: calc(var(--tabbar-h) + var(--chrome-bottom));
  padding-bottom: var(--chrome-bottom);
  padding-left: var(--safe-left);
  padding-right: var(--safe-right);
  background: var(--bg);
  border-top: 1px solid var(--border-soft);
  transform: translateZ(0);
}
.tab {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .1875rem;
  padding: .25rem 0 0;
  border: 0;
  background: transparent;
  color: var(--text-faint);
  font-family: var(--font-ui);
  font-size: .625rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: .02em;
  cursor: pointer;
  transition: color 140ms var(--ease);
}
.tab__label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-inline: .125rem; }
.tab[aria-current="page"] { color: var(--accent); }
.tab:active .ico { transform: scale(.94); }

/* 今天页底部的输入框：一个按钮样式的假输入（点它时同步打开选择器并聚焦真输入框） */
.omni {
  flex: none;
  position: relative;
  padding: .375rem max(var(--gutter), var(--safe-right)) .5rem max(var(--gutter), var(--safe-left));
  background: var(--bg);
}
/* 滚动内容在输入框上沿淡出，而不是一刀切 */
.omni::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 100%;
  height: 1rem;
  background: linear-gradient(to bottom, transparent, var(--bg));
  pointer-events: none;
}
.omni__field {
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  height: 2.5rem;
  padding: 0 1rem;
  border: 1px solid var(--border);
  border-radius: 99px;
  background: var(--bg-sunken);
  color: var(--text-faint);
  font: inherit;
  text-align: start;
  cursor: text;
  transition: border-color 140ms var(--ease), transform 90ms var(--ease);
}
.omni__field:hover { border-color: var(--accent-line); }
.omni__field:active { transform: scale(.992); }
.omni__ph { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .9375rem; }
.omni__kbd {
  flex: none;
  display: none;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 .3125rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--bg);
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.125rem;
  text-align: center;
  color: var(--text-faint);
}
html[data-touch="off"] .omni__kbd { display: inline-block; }

/* 地图槽（手机）与舞台（唯一的 #mapStage，app.js 在两个槽之间挪） */
.view--map .mapslot {
  position: relative;
  flex: none;
  height: var(--map-h);
  overflow: hidden;
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
}
html[data-mapfull] .view--map .mapslot { flex: 1 1 auto; height: auto; border-bottom: 0; }
html[data-mapfull] .view--map .mappane { display: none; }
.stage { position: absolute; inset: 0; isolation: isolate; overflow: hidden; }
.stage__canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
  outline-offset: -3px;
}
/* 舞台上的浮件只在这里定位；里面长什么样归 ui-map.css（G） */
.stage__callout { position: absolute; top: .625rem; inset-inline: .625rem; z-index: 20; }
.stage__tools { position: absolute; top: .625rem; inset-inline-end: .625rem; z-index: 20; display: flex; align-items: center; gap: .375rem; }
.stage__callout:not([hidden]) ~ .stage__tools { top: 4rem; }
.stage__legend { position: absolute; bottom: .625rem; inset-inline-start: .625rem; z-index: 20; max-width: calc(100% - 1.25rem); }
.stage__banner { position: absolute; top: 0; inset-inline: 0; z-index: 21; }
.stage__status { position: absolute; top: 50%; inset-inline: 0; margin-inline: auto; width: max-content; max-width: calc(100% - 2.5rem); transform: translateY(-50%); z-index: 20; text-align: center; }

/* 欢迎页的外框（里面归 ui-settings.css）：全屏、纸底、自己滚 */
.welcome {
  position: fixed;
  inset: 0;
  z-index: 60;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--bg);
  font-family: var(--font-serif);
}
.welcome__err { max-width: 30rem; margin: 0 auto; padding: calc(var(--safe-top) + 4rem) var(--gutter) 2rem; }
.welcome__err p { margin: 1rem 0 0; font-family: var(--font-ui); color: var(--text-dim); line-height: 1.6; }
.welcome__err .brand { margin-bottom: 1.25rem; }

/* ==========================================================================
   5. 浮层：sheet · pop · picker · dialog · toast
   z：rail/topbar/tabbar 10 · 舞台浮件 20 · welcome 60 · sheet 90 · pop 94 · picker 96 · dialog 100 · toast 110
   ========================================================================== */

.sheet { position: fixed; inset: 0; z-index: 90; }
.sheet--pop { z-index: 94; }
.sheet__backdrop {
  position: absolute;
  inset: 0;
  background: var(--scrim);
  opacity: 0;
  transition: opacity var(--t-scrim-in) var(--ease);
}
.sheet.is-open .sheet__backdrop { opacity: 1; }
/* 小浮层叠在表单上：遮罩只用一半（两层 --scrim 叠起来就把底下那张表单压没了） */
#sheet:not([hidden]) ~ #pop.is-open .sheet__backdrop { opacity: .5; }
.sheet__panel {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  max-height: calc(100% - var(--safe-top) - 2.5rem);
  display: flex;
  flex-direction: column;
  background: var(--bg-elev);
  border-top: 1px solid var(--border);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  box-shadow: var(--shadow-lg);
  padding-bottom: var(--safe-bottom);
  transform: translateY(100%);
  transition: transform var(--t-sheet-in) var(--ease);
}
/* 跟键盘只用 transform（家族铁律 E4：绝不改布局高度） */
.sheet.is-open .sheet__panel { transform: translateY(calc(-1 * var(--kb))); }
.sheet--pop .sheet__panel { max-height: calc(100% - var(--safe-top) - 4rem); }
.sheet.is-closing { pointer-events: none; }
.sheet.is-closing .sheet__backdrop { opacity: 0; transition: opacity var(--t-scrim-out) var(--ease-exit); }
.sheet.is-closing .sheet__panel { transform: translateY(100%); transition: transform var(--t-out) var(--ease-exit); }
/* 浮板上的填色降一档（Parote）：近白的板子上 hover 与输入框底色用纸色，不像补丁 */
.sheet__panel, .dialog__panel, .picker__panel {
  --bg-elev2: var(--panel-fill);
  --bg-sunken: var(--panel-fill);
}
.sheet__panel:focus { outline: none; }
.sheet__head {
  flex: none;
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: 3.25rem;
  padding: .5rem .625rem .375rem 1.125rem;
  padding-inline: 1.125rem .625rem;
}
.sheet__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -.01em;
  overflow-wrap: anywhere;
}
.sheet__back { margin-inline-start: -.625rem; }
.sheet__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: .125rem 1.125rem 1.25rem;
  transition: opacity var(--t-swap-in) var(--ease), transform var(--t-swap-in) var(--ease);
}
/* swapBox（Parote）：锁高 → 淡出 130ms → 换 → 高度 300ms → 淡入 260ms（scale .988） */
.sheet__body.is-out { opacity: 0; transform: scale(.988); transition-duration: var(--t-swap); transition-timing-function: var(--ease-exit); }
.sheet__panel.is-swapping { overflow: hidden; transition: transform var(--t-sheet-in) var(--ease), height var(--t-grow) var(--ease); }

/* ---- 停靠页（ADDENDUM-3 §G / E3，DLUI.openPanelPage）：桌面上 panel 这一栏里不模态的一页 ----
   盖住那一栏的顶栏与页面（.main 是它的包含块），纸色 --bg，没有遮罩、没有阴影、没有圆角；右边的地图照样能用。
   进：从行尾一侧挪进 .75rem + 淡入（E8），出：淡出。只在 ≥ 900 打开（窄屏 openPanelPage 退回 #sheet）。 */
.ppage {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  opacity: 0;
  transform: translateX(.75rem);
  transition: opacity var(--t-in) var(--ease), transform var(--t-in) var(--ease);
}
[dir="rtl"] .ppage { transform: translateX(-.75rem); }
.ppage.is-open { opacity: 1; transform: none; }
.ppage.is-closing { opacity: 0; transition: opacity var(--t-out) var(--ease-exit), transform var(--t-out) var(--ease-exit); }
.ppage:focus { outline: none; }
.ppage__head {
  flex: none;
  display: flex;
  align-items: center;
  gap: .375rem;
  height: var(--topbar-h);
  padding-inline: 1.25rem .75rem;
  border-bottom: 1px solid var(--border-soft);
}
.ppage__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ppage__back { margin-inline-start: -.625rem; }
.ppage__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: .75rem 1.25rem 1.5rem;
  transition: opacity var(--t-swap-in) var(--ease), transform var(--t-swap-in) var(--ease);
}
.ppage__body.is-out { opacity: 0; transform: scale(.988); transition-duration: var(--t-swap); transition-timing-function: var(--ease-exit); }
/* 页里的签行出血到页自己的内边距 */
.ppage__body .chips--bleed { margin-inline: -1.25rem; padding-inline: 1.25rem; scroll-padding-inline: 1.25rem; }

/* ---- 选择器：专用全高浮层 ---- */
.picker { position: fixed; inset: 0; z-index: 96; }
/* 手机上选择器铺满整屏：底下那一整块纸色也是「大面积变亮」，淡入淡出（E8），不「啪」地盖上 */
.picker__backdrop { position: absolute; inset: 0; background: var(--bg); opacity: 0; transition: opacity var(--t-scrim-in) var(--ease); }
.picker.is-open .picker__backdrop { opacity: 1; }
.picker.is-closing .picker__backdrop { opacity: 0; transition: opacity var(--t-scrim-out) var(--ease-exit); }
.picker__panel {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding-top: var(--safe-top);
  background: var(--bg);
  opacity: 0;
  transform: translateY(.75rem);
  transition: opacity var(--t-in) var(--ease), transform var(--t-in) var(--ease);
}
.picker.is-open .picker__panel { opacity: 1; transform: none; }
.picker.is-closing .picker__panel { opacity: 0; transform: translateY(.5rem); transition: opacity var(--t-out) var(--ease-exit), transform var(--t-out) var(--ease-exit); }
.picker.is-closing { pointer-events: none; }
.picker__head {
  position: relative;
  z-index: 2;
  flex: none;
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: 3rem;
  padding: .25rem max(calc(var(--gutter) - .5rem), var(--safe-right)) .25rem max(var(--gutter), var(--safe-left));
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
}
.picker__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.35;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 迷你条出现时，标题只留给读屏（它仍是对话框的名字） */
.picker__head.has-strip .picker__title { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.picker__strip { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: .5rem; overflow: hidden; }
.picker__strip:empty { display: none; }
.picker__striplabel { flex: none; font-size: .75rem; font-weight: 600; color: var(--text-dim); }
.picker__stripseals { display: flex; align-items: center; gap: .3125rem; min-width: 0; overflow: hidden; padding: .25rem 0; }
.picker__done { flex: none; font-weight: 600; color: var(--accent); }
.picker__done:hover { color: var(--accent-strong); }
/* 结果从输入框往上长：最佳匹配在最下面、离拇指最近。翻转只需改这一行 flex-direction。 */
.picker__list {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column-reverse;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-block: calc(.5rem + var(--kb)) .25rem;
  transform: translateY(calc(-1 * var(--kb)));
}
.picker__chips,
.picker__inputrow { flex: none; transform: translateY(calc(-1 * var(--kb))); background: var(--bg); }
.picker__chips { padding: .25rem 0 .375rem; }
.picker__chips > .chips { padding-inline: max(var(--gutter), var(--safe-left)) max(var(--gutter), var(--safe-right)); }
.picker__chips:empty { display: none; }
.picker__inputrow {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .375rem max(var(--gutter), var(--safe-right)) max(.625rem, var(--safe-bottom)) max(var(--gutter), var(--safe-left));
}
html[data-kb] .picker__inputrow { padding-bottom: .5rem; }
/* 放大镜由 app.js 插在输入框前面（HTML 结构是契约定死的，只有输入框） */
.picker__inputrow { position: relative; }
.picker__glass { position: absolute; inset-inline-start: calc(max(var(--gutter), var(--safe-left)) + .9375rem); color: var(--text-faint); pointer-events: none; }
.picker__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 2.75rem;
  margin: 0;
  padding-block: 0;
  padding-inline: 2.625rem 1.125rem;
  border: 1px solid var(--accent-line);
  border-radius: 99px;
  background: var(--bg-elev);
  color: var(--text);
  font: inherit;
  font-size: 1.0625rem;      /* ≥ 16px：iOS 聚焦时不放大页面 */
  outline: none;
  box-shadow: var(--shadow-sm);
}
.picker__input::placeholder { color: var(--text-faint); opacity: 1; }
.picker__input:focus-visible { outline: none; }

/* ---- 对话框：只用于抹掉全部数据、导入预览、删掉一段住处（另有几处只有一个〔好〕的信息型对话框） ---- */
.dialog {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--safe-top) + 1rem) 1.25rem calc(var(--safe-bottom) + 1rem);
}
.dialog__backdrop { position: absolute; inset: 0; background: var(--scrim); opacity: 0; transition: opacity var(--t-scrim-in) var(--ease); }
/* 进场：translateY(.5rem) scale(.985) → 原位，220ms --ease（E3，与表单同一个动作）；退场是 170ms 的过渡，
   不是 animation … forwards（家族规则：退场一律用过渡）。is-open 由 app.js 的 openClass 在两帧之后加上。 */
.dialog__panel {
  position: relative;
  width: min(27.5rem, 100%);
  max-height: 100%;
  overflow-y: auto;
  padding: 1.375rem 1.375rem 1rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-sheet);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(.5rem) scale(.985);
  transition: opacity var(--t-in) var(--ease), transform var(--t-in) var(--ease);
}
.dialog.is-open .dialog__backdrop { opacity: 1; }
.dialog.is-open .dialog__panel { opacity: 1; transform: translateY(calc(-.5 * var(--kb))); }
.dialog__title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.1875rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -.01em;
}
.dialog__body { margin: .5rem 0 1.25rem; color: var(--text-dim); line-height: 1.6; white-space: pre-line; text-wrap: pretty; }
.dialog__body:empty { display: none; }
.dialog__acts { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; }
.dialog.is-closing { pointer-events: none; }
.dialog.is-closing .dialog__backdrop { opacity: 0; transition: opacity var(--t-scrim-out) var(--ease-exit); }
.dialog.is-closing .dialog__panel { opacity: 0; transform: translateY(.5rem) scale(.985); transition: opacity var(--t-out) var(--ease-exit), transform var(--t-out) var(--ease-exit); }

/* ---- 提示条：挂在 .app 上（包含块 = 固定的 body = 视口），absolute 不是 fixed（采样带） ---- */
.toast {
  --toast-lift: calc(var(--tabbar-h) + var(--chrome-bottom) + .75rem);
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 110;
  display: flex;
  justify-content: center;
  padding-inline: .75rem;
  pointer-events: none;
  transform: translateY(calc(-1 * (var(--toast-lift) + var(--kb))));
  transition: transform 180ms var(--ease);
}
#app[data-view="today"] .toast { --toast-lift: calc(var(--tabbar-h) + var(--chrome-bottom) + var(--omni-h) + .5rem); }
/* 选择器开着时提示条放到它的头部下面：底下是输入框、快捷签和离拇指最近的那几行，一行都不能盖 */
html[data-layer="picker"] .toast { top: calc(var(--safe-top) + 3.5rem); bottom: auto; transform: none; }
html[data-layer="picker"] .toast__box { animation-name: toastInTop; }
html[data-layer="picker"] .toast__box.is-out { transform: translateY(-.375rem); }
/* 表单开着时提示条挪到屏幕顶上：贴底的话正好盖住表单自己的〔好了〕〔删除这一次〕 */
html[data-layer="sheet"] .toast { top: calc(var(--safe-top) + .5rem); bottom: auto; transform: none; }
html[data-layer="sheet"] .toast__box { animation-name: toastInTop; }
html[data-layer="sheet"] .toast__box.is-out { transform: translateY(-.375rem); }
@keyframes toastInTop { from { opacity: 0; transform: translateY(-.375rem); } }
.toast__box {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: .75rem;
  max-width: min(30rem, 100%);
  min-height: 2.875rem;
  padding: .5rem .375rem .5rem .875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--bg-elev);
  box-shadow: var(--shadow-lg);
  font-size: .875rem;
  line-height: 1.4;
  animation: toastIn var(--t-toast-in) var(--ease);
  transition: opacity var(--t-toast-out) var(--ease-exit), transform var(--t-toast-out) var(--ease-exit);
}
.toast__box--seal { padding-inline-start: .625rem; }
.toast__box.is-out { animation: none; opacity: 0; transform: translateY(.375rem); pointer-events: none; }
.toast__text { flex: 1 1 auto; min-width: 0; }
.toast__msg { display: block; overflow-wrap: anywhere; }
.toast__sub { display: block; margin-top: .0625rem; font-size: .8125rem; color: var(--text-dim); }
.toast__box--seal .toast__msg { font-family: var(--font-serif); font-size: .9375rem; font-weight: 600; }
.toast__act {
  flex: none;
  min-height: 2rem;
  padding: .375rem .625rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--accent);
  font: 600 .8125rem/1 var(--font-ui);
  white-space: nowrap;
  cursor: pointer;
}
.toast__act:hover { background: var(--bg-elev2); }
@keyframes toastIn { from { opacity: 0; transform: translateY(.375rem); } }


/* ==========================================================================
   6. 今天：刊头（小图 + 日期头）、此刻卡、再来一次、最近签、「哪一处？」、补记提示、今天的饭票
   --------------------------------------------------------------------------
   ADDENDUM-3 §G「刊头」：手机上从上到下 = 按数据取景的小图（整块一个按钮 → 地图页）· 日期头
   （大号日子 · 月份 · 星期 · 一句此刻为真的话 · 「尝过 N 处 ›」）· 此刻卡（全页唯一一层发丝框，
   里面的卡与签不再描边，靠纸色 --bg 衬出来）· 一行小字的补记提示 · 今天的饭票 · 底部输入框。
   桌面：同一个日期头与那句话，没有小图（真地图就在右栏）。
   ⚠ 红色克制：今天页上「今天」的红记号只有一个 —— 此刻卡说明字那一道。日期头全用墨色；
     初尝的地名是「初尝」的红，不是「今天」的红。
   ========================================================================== */

/* ---- 刊头 ---- */
.mast { position: relative; }
/* 小图：整条是一个按钮（→ 地图页），没有手势、没有字；高 = --mast-h + 状态栏那一截（安全区里什么都不画） */
.mast__plate {
  position: relative;
  display: block;
  width: 100%;
  height: calc(var(--mast-h) + var(--safe-top));
  margin: 0;
  padding: var(--safe-top) 0 0;    /* app.js 读这个 padding 当作「状态栏那一截」传给 plate（clipTop） */
  border: 0;
  border-bottom: 1px solid var(--border-soft);
  background: transparent;
  cursor: pointer;
  overflow: hidden;
}
.mast__canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.mast__plate:focus-visible { outline-offset: -3px; }
/* 没有 DLGlobe.plate（渲染器还没交、或抛了）：小图整块不出现，今天页照样完整 */
.mast[data-noplate] .mast__plate { display: none; }

/* 日期头：大号 Newsreader 日子 + 右边两行（月份 · 星期 ··· 尝过 N 处 ›／一句话）；
   整行按最后一条基线对齐：那句话的最后一行落在大数字的基线上（不支持的引擎退回底对齐，看上去几乎一样） */
.mast__head {
  display: flex;
  align-items: flex-end;
  align-items: last baseline;
  gap: .875rem;
  padding: 1rem max(var(--gutter), var(--safe-right)) 0 max(var(--gutter), var(--safe-left));
}
.mast__day {
  flex: none;
  margin-inline-start: -.045em;              /* Newsreader 数字的左侧留白：光学对齐到页边 */
  font-family: var(--latin-serif), serif;
  font-size: 5.25rem;
  font-weight: 600;
  line-height: .86;
  letter-spacing: -.05em;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--text);
}
.mast__lines { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .3125rem; }
.mast__top { display: flex; align-items: baseline; gap: .75rem; min-width: 0; }
/* 「九月 · 星期三」：说明字的字形，墨色（不是印章红：今天的红记号留给此刻卡） */
.mast__date {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--font-ui);
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: .16em;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
html:lang(zh) .mast__date { letter-spacing: .2em; }
html:is(:lang(en), :lang(es), :lang(pt), :lang(fr), :lang(de), :lang(it), :lang(nl), :lang(pl), :lang(ru), :lang(uk), :lang(tr), :lang(vi), :lang(id), :lang(ms), :lang(fil)) .mast__date { text-transform: uppercase; }
html:is(:lang(ja), :lang(ko)) .mast__date { letter-spacing: .12em; }
html:is(:lang(ar), :lang(fa), :lang(ur), :lang(he), :lang(hi), :lang(bn), :lang(th)) .mast__date { letter-spacing: 0; font-size: .75rem; }
/* 「尝过 N 处 ›」：一辈子的数，Newsreader 等宽数字，安静的墨色；点它 = 地图页 */
.mast__life {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: .125rem;
  min-height: 1.75rem;
  margin-block: -.375rem;
  margin-inline-end: -.25rem;
  padding: 0 .25rem;
  border: 0;
  border-radius: .375rem;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-serif);
  font-size: .875rem;
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
  white-space: nowrap;
  cursor: pointer;
}
.mast__life .ico { color: var(--text-faint); }
.mast__life:hover { color: var(--text); }
@media (hover: none) { .mast__life:hover { color: var(--text-dim); } }
/* 那一句话：衬线，地名 600 墨色，初尝的那一处 600 印章红；第一天的邀请是两行（\n） */
.mast__sent {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.45;
  color: var(--text-dim);
  text-wrap: pretty;
  white-space: pre-line;
}
.mast__place { font-weight: 600; color: var(--text); }
.mast__place.is-first { color: var(--accent); }
/* 地名不在字中间折行（「马来 / 西亚」）：地名内部的汉字之间不给折行点，地名前后照常 */
.mast__place { word-break: keep-all; }
.mast__sent[data-empty] { color: var(--text-faint); }

/* ---- 此刻卡：页面上唯一浮起的一块（写的地方）；一层发丝框，里面的东西靠纸色 --bg 衬出来 ---- */
.now {
  --ticket-bg: var(--bg);
  margin: 1.125rem max(var(--gutter), var(--safe-right)) 0 max(var(--gutter), var(--safe-left));
  padding: 1rem 1rem .75rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-sheet);
  box-shadow: var(--shadow-sm);
}
/* 卡里的签行出血到卡自己的内边距（1rem），不是页面的 --gutter */
.now .chips--bleed { margin-inline: -1rem; padding-inline: 1rem; scroll-padding-inline: 1rem; }
/* 只有一层发丝线：卡里的「再来一次」、签、饭票、在哪吃、按钮都不描边，纸色的底把它们衬出来 */
.now .repeat__card, .now .chip, .now .venue, .now .btn { border-color: transparent; background: var(--bg); }
.now .chip--unclear { color: var(--text-dim); }
.now .repeat__card:hover, .now .chip:hover, .now .venue:hover, .now .btn:hover { border-color: var(--border); }
@media (hover: none) { .now .repeat__card:hover, .now .chip:hover, .now .venue:hover, .now .btn:hover { border-color: transparent; } }
.now .field { border-color: transparent; background: var(--bg); }
.now .field:focus-within { border-color: var(--accent-line); background: var(--bg); }
.now .ticket, .now .ticket::before, .now .ticket::after { border-color: transparent; }
/* 说明字那一行：此刻 · 15时 ▾ ·（在京都 ▾）〔回家了〕 */
.now__top { display: flex; align-items: center; flex-wrap: wrap; gap: .25rem .5rem; min-height: 1.5rem; }
.kicker--btn {
  gap: .625rem;
  padding: .375rem .5rem .375rem 0;
  margin-block: -.375rem;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: .375rem;
  font-variant-numeric: lining-nums;
}
.kicker--btn .ico { margin-inline-start: -.3125rem; opacity: .8; }
.kicker--btn:hover { color: var(--accent-strong); }
/* 「· 在成都 ▾」（ADDENDUM-2 C3）：墨色，不是印章红；点它 = 换此刻在哪 */
.now__at {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
  max-width: 100%;
  padding: .375rem .25rem;
  margin-block: -.375rem;
  margin-inline-start: -.25rem;
  border: 0;
  border-radius: .375rem;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: .75rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: .04em;
  cursor: pointer;
}
.now__atsep { color: var(--text-faint); }
.now__attext { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.now__at .ico { color: var(--text-faint); }
.now__at:hover { color: var(--text); }
@media (hover: none) { .now__at:hover { color: var(--text-dim); } }
.now__back { height: 1.75rem; padding-inline: .625rem; }
.now__frame { position: relative; }
.now__frame.is-swapping { overflow: hidden; transition: height var(--t-grow) var(--ease); }
.now__inner { transition: opacity var(--t-swap-in) var(--ease), transform var(--t-swap-in) var(--ease); transform-origin: 50% 0; }
.now__inner.is-out { opacity: 0; transform: scale(.988); transition-duration: var(--t-swap); transition-timing-function: var(--ease-exit); }
.now__q {
  margin: .5rem 0 1rem;
  font-family: var(--font-serif);
  font-size: 1.5rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -.01em;
  text-wrap: balance;
  color: var(--text);
}

/* 两张「再来一次」卡：一张一行（上：小字「和上次一样」；下：一枚 22px 的印 + 菜名），≈ 64pt 高 */
.repeat { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; margin-bottom: .75rem; }
.repeat__card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: .3125rem;
  min-width: 0;
  min-height: 4rem;
  padding: .5rem .75rem .5625rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--bg-elev);
  color: var(--text);
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition: background 140ms var(--ease), border-color 140ms var(--ease), transform 90ms var(--ease);
}
.repeat__card:only-child { grid-column: 1 / -1; }
.repeat__card:hover { border-color: var(--text-faint); }
.repeat__card:active { transform: scale(.985); }
@media (hover: none) { .repeat__card:hover { border-color: var(--border); } }
.repeat__label { display: flex; align-items: center; gap: .3125rem; min-width: 0; font-size: .75rem; font-weight: 500; line-height: 1.3; color: var(--text-dim); }
.repeat__label .ico { color: var(--text-faint); }
/* 英文的「Like Thursday around now」一行放不下就省略号（读屏读 aria-label 里的整句） */
.repeat__labtext { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.repeat__line { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.repeat__name {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-serif);
  font-size: 1rem;
  /* 1.25：半行距正好 2px，Blink 不取整，菜名的墨心与旁边那枚印对齐（1.35 在 Blink 里高 0.9px，E7 探针） */
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.now__recents { margin-top: .125rem; }
/* 第一天（一个最近都没有）：常见的签折成两行，不横滑 */
.now__recents[data-wrap] { flex-wrap: wrap; overflow: visible; -webkit-mask-image: none; mask-image: none; }
/* 第一天：签下面一句怎么打字 */
.now__first { margin: .375rem 0 0; font-size: .8125rem; line-height: 1.5; color: var(--text-faint); }

/* 状态 B：这一次 */
.now__label {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: .875rem 0 .5rem;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text-dim);
}
.now__row {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: .5rem 0 .75rem;
}
.now__hint { flex: 1 1 auto; min-width: 0; font-size: .8125rem; line-height: 1.45; color: var(--text-faint); }
.now__another { flex: none; }
.now__where { margin-bottom: .625rem; min-width: 0; }
/* 用过的店名（聚焦时出现）：离框底一个固定的 .5rem，一行；多了横着滑，从不折回去压到框上（E14.1）。
   出现 / 收起由 app.js growIn / growOut 演（高度 + 淡入淡出）。 */
.venues {
  display: flex;
  flex-wrap: nowrap;
  gap: .375rem;
  margin: .5rem 0 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.venues::-webkit-scrollbar { display: none; }
.entry__sec .venues { margin-bottom: 0; }
.venue {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: 1.875rem;
  max-width: 100%;
  padding: 0 .6875rem;
  border: 1px solid var(--border);
  border-radius: 99px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: .8125rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.venue:hover { color: var(--text); border-color: var(--text-faint); }

/* ---- 「哪一处？」（ADDENDUM-3 E1 · ADDENDUM-5 E16.7）：新记下的那一样下面一行安静的选择 ----
   问句行：问句 + 行尾一个字按钮「都有可能」（它不改地图，只是不再问）；
   签行：「两处都算 / N 处都算」（这一片的白文印）最前 + 一道发丝竖线 + 每个候选一枚签（印 + 短名）。
   签行只放会改地图的回答，横向滚动（竹筒饭 11 处也一样），「都算」在最前、不用滚就看得见。不理它 = 整组照存（那本来就是真话）。
   全境的菜（中餐、越南菜……）只有一枚「{place}全境都算」（.choose--whole：没有问句、不标 pending），不理它照旧是斜线。 */
.now__choose:empty { display: none; }
/* 出现：从 0 高长出来（grid-template-rows 0fr → 1fr，--t-grow --ease）；回答后先收起（--ease-exit）再写（E8）。
   长 / 收的那一下才裁边（平时签行要出血到卡边，不能裁） */
.choose {
  display: grid;
  grid-template-rows: 1fr;
  margin: .375rem 0 .5rem;
  transition: grid-template-rows var(--t-shrink) var(--ease-exit), opacity var(--t-shrink) var(--ease-exit), margin var(--t-shrink) var(--ease-exit);
}
/* ⚠ min-inline-size: 0：网格项的自动最小宽度 = 签行的 min-content，会把问句行撑出卡外（英文「Could be any」被裁掉一半） */
.choose__in { min-height: 0; min-inline-size: 0; }
.choose.is-new, .choose.is-gone { overflow: hidden; }
@keyframes chooseIn { from { grid-template-rows: 0fr; opacity: 0; } }
.choose.is-new { animation: chooseIn var(--t-grow) var(--ease); }
.choose.is-gone { grid-template-rows: 0fr; opacity: 0; margin-block: 0; }
.choose + .choose { margin-top: .625rem; }
.choose__q {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .125rem .5rem;
  margin: 0 0 .125rem;
  font-family: var(--font-serif);
  font-size: .9375rem;
  font-weight: 500;
  line-height: 1.4;
  color: var(--text);
}
.choose__name { font-size: .8125rem; font-weight: 400; color: var(--text-faint); }
/* 「都有可能」：问句行尾的字按钮（UI 字、墨色淡一档、一道发丝下划线），不画框。
   触区 2.25rem 高（触屏档 2.75rem），用负的上下外边距吃回去：问句行照旧一行字高，此刻卡不因为它变高 */
.choose__keep {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-block-size: 2.25rem;
  margin-block: -.4375rem;
  margin-inline-start: auto;
  padding: 0 .125rem;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: .8125rem;
  font-weight: 500;
  line-height: 1;
  text-decoration: underline;
  text-decoration-color: var(--border);
  text-decoration-thickness: 1px;
  text-underline-offset: .25em;
  white-space: nowrap;
  cursor: pointer;
  transition: color 140ms var(--ease), text-decoration-color 140ms var(--ease);
}
.choose__keep:hover { color: var(--text); text-decoration-color: var(--text-faint); }
html[data-touch="on"] .choose__keep { min-block-size: 2.75rem; margin-block: -.6875rem; }
/* 「都算」与候选之间一道发丝竖线：前面是「整片」，后面是「其中一处」 */
.choose__sep { flex: none; inline-size: 1px; block-size: 1.375rem; background: var(--border); margin-inline: .125rem; }
/* 全境的菜只有一枚签：紧贴在饭票下面，没有问句行 */
.choose--whole { margin-block-start: .25rem; }
/* 饭票上的「哪一处？ ›」：这一样还没回答时，一行安静的小字（点整张票进记录页去选） */
.dish__ask {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .125rem;
  margin: -.375rem 0 .25rem;
  font-size: .75rem;
  line-height: 1.4;
  color: var(--text-faint);
}
.dish__ask .ico { color: var(--text-faint); }

/* 补记提示（§G）：一行小字「昨天还没有记录 · 补上 ✕」，不是框。只提昨天，只在为真时 */
.nudge {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0 .375rem;
  margin: .625rem max(var(--gutter), var(--safe-right)) 0 max(var(--gutter), var(--safe-left));
  padding-inline-start: .125rem;
  font-size: .8125rem;
  line-height: 1.4;
  color: var(--text-faint);
}
/* 出现 / 关掉：app.js growIn / growOut（高度 + 上边距 + 淡入淡出，--t-grow / --t-shrink），这里不另写过渡 */
.nudge__text { flex: 0 1 auto; min-width: 0; }
.nudge__sep { color: var(--text-faint); }
.nudge__fill {
  flex: none;
  padding: .375rem .5rem;
  margin-inline: -.125rem;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--accent);
  /* ⚠ 13.5px / 1.2 是 E7 探针量过、两家引擎都居中的那一组（13px 在 Blink 里因半行距取整偏高 4–5%） */
  font: 600 .84375rem/1.2 var(--font-ui);
  cursor: pointer;
}
.nudge__fill:hover { background: var(--accent-soft); }
.nudge__x { width: 1.75rem; height: 1.75rem; color: var(--text-faint); }
html[data-touch="on"] .nudge__x { width: 2.25rem; height: 2.25rem; }

/* 一天的饭票列表 */
.daylist {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  padding: .5rem max(var(--gutter), var(--safe-right)) 1.75rem max(var(--gutter), var(--safe-left));
}
.daylist:empty { display: none; }
.dayhead {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: .875rem 0 .125rem;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text-dim);
  font-variant-numeric: lining-nums tabular-nums;
}
.dayhead::after { content: ""; flex: 1 1 auto; height: 1px; background: var(--border-soft); }
.daylist__act { align-self: flex-start; margin-top: .25rem; }
.daylist .zero { padding-block: 1.25rem .5rem; }

/* ==========================================================================
   7. 日子：月历（WAI-ARIA grid）与复制模式
   ========================================================================== */

/* ---- 这七天（ADDENDUM-3 §G：日记的周印带做日子页的页眉）----
   七栏，每栏：星期小字 · 那天的印往下叠（下一枚只压住上一枚的边框带，不压字）· 日数。
   印下面垫一圈纸色（.seal__halo），叠着的印之间留一道纸缝；--js 边长、--jmax 层数、--i / --dx 由 app.js 写（CSSOM）。
   ⚠ 这一页的「今天」红记号是月历里那道下划线：这里的今天只用墨色（600 的字 + 墨色虚线空位）。 */
.week { padding: .75rem max(var(--gutter), var(--safe-right)) .25rem max(var(--gutter), var(--safe-left)); }
.week:empty { display: none; }
.week__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  margin-bottom: .375rem;
  font-size: .75rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: .04em;
  color: var(--text-dim);
}
.week__sum { font-weight: 500; letter-spacing: .02em; color: var(--text-faint); font-variant-numeric: lining-nums tabular-nums; white-space: nowrap; }
.week__cols {
  --js: 28px;
  --jmax: 3;
  --jstep: calc(var(--js) * .8);
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  margin-inline: -.25rem;
}
.week__day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .4375rem;
  min-width: 0;
  padding: .375rem 0;
  border: 0;
  border-radius: .625rem;
  background: transparent;
  color: var(--text-faint);
  font: inherit;
  cursor: pointer;
  transition: background 140ms var(--ease), transform 90ms var(--ease);
}
.week__day:hover { background: var(--bg-elev2); }
.week__day:active { transform: scale(.97); }
@media (hover: none) { .week__day:hover { background: transparent; } }
.week__dow { max-width: 100%; overflow: hidden; text-overflow: ellipsis; font-size: .6875rem; font-weight: 500; line-height: 1.2; letter-spacing: .02em; white-space: nowrap; }
.week__day.is-today .week__dow { color: var(--text); font-weight: 600; }
.week__stack {
  position: relative;
  width: 100%;
  height: calc(var(--js) + (var(--jmax) - 1) * var(--jstep));
}
.week__stack > .seal,
.week__stack > .week__more {
  position: absolute;
  top: calc(var(--i, 0) * var(--jstep));
  inset-inline-start: calc(50% - var(--js) / 2 + var(--dx, 0px));
}
.week__more {
  direction: ltr;              /* 「+2」在从右往左的界面里也是加号在前 */
  unicode-bidi: isolate;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--js);
  height: var(--js);
  font-family: var(--latin-serif), serif;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-dim);
  font-variant-numeric: lining-nums;
}
.week__blank {
  position: absolute;
  top: calc(var(--js) / 2);
  inset-inline-start: calc(50% - 6px);
  width: 12px;
  height: 1px;
  background: var(--border);
}
.week__date {
  position: relative;
  font-family: var(--latin-serif), serif;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.15;
  color: var(--text-dim);
  font-variant-numeric: lining-nums tabular-nums;
}
.week__day:hover .week__date { color: var(--text); }
.week__day.is-today .week__date { color: var(--text); font-weight: 600; }
/* 那天有初尝：日期右上一个印章红小点（与月历同一个记号） */
.week__date.has-first::before {
  content: "";
  position: absolute;
  top: 0;
  inset-inline-end: -.4375rem;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--seal);
}
.week__hint { margin: .375rem 0 0; font-size: .8125rem; line-height: 1.5; color: var(--text-faint); }
/* 叠印的纸缝：每一枚印下面垫一圈纸色，叠在上一枚上时中间留一道缝，不糊成一团 */
.seal__halo { fill: var(--bg); stroke: var(--bg); stroke-width: 5; stroke-linejoin: round; }
.week__stack .seal--dashed .seal__shape { fill: var(--bg); }
/* 今天还空着：一个墨色虚线的空位（这一枚落下来的地方） */
.seal--slot .seal__shape { fill: none; stroke: var(--text-faint); stroke-width: 1.6; stroke-dasharray: 3.4 2.6; }

.cal { padding: .625rem max(calc(var(--gutter) - .25rem), var(--safe-right)) .25rem max(calc(var(--gutter) - .25rem), var(--safe-left)); }
.calgrid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); row-gap: .125rem; }
.calgrid__row { display: contents; }
.calgrid__wd {
  padding: .25rem 0 .5rem;
  font-size: .6875rem;
  font-weight: 500;
  text-align: center;
  color: var(--text-faint);
  letter-spacing: .02em;
}
.calgrid__cell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: .1875rem;
  min-height: 2.875rem;
  padding-top: .25rem;
  border-radius: .625rem;
  cursor: pointer;
  font-family: var(--font-serif);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--text);
}
.calgrid__cell:focus-visible { outline-offset: -2px; }
.calgrid__num {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  transition: background 140ms var(--ease), box-shadow 140ms var(--ease);
}
.calgrid__cell:hover .calgrid__num { background: var(--bg-elev2); }
/* 今天：2px 印章红下划线 */
.calgrid__cell[data-today] .calgrid__num::after {
  content: "";
  position: absolute;
  bottom: .25rem;
  inset-inline: .625rem;
  height: 2px;
  border-radius: 1px;
  background: var(--accent);
}
/* 选中：墨色细圈 */
.calgrid__cell[aria-selected="true"] .calgrid__num { box-shadow: inset 0 0 0 1.25px var(--text); }
/* 有记录：日期下一个小墨点 */
.calgrid__dot { width: 4px; height: 4px; border-radius: 50%; background: var(--text-dim); }
.calgrid__dot--none { visibility: hidden; }
/* 那天有初尝：那个点换成印章红，略大一点 */
.calgrid__dot--first { width: 5px; height: 5px; background: var(--seal); }
.calgrid__cell[aria-disabled="true"] { cursor: default; color: var(--text-faint); opacity: .45; }
.calgrid__cell[aria-disabled="true"]:hover .calgrid__num { background: transparent; }
.calgrid__cell--pad { cursor: default; }
/* 复制模式：被点选的日子墨色填满 */
.calgrid__cell[data-copy] .calgrid__num { background: var(--text); color: var(--bg); box-shadow: none; }
.calnav { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin: 0 0 .375rem; }
.calnav__title { font-family: var(--font-serif); font-size: 1rem; font-weight: 600; font-variant-numeric: lining-nums; }

/* 日子页：复制模式时横幅钉在最上面 */
#daysPane { display: flex; flex-direction: column; }
#daysPane > * { flex: none; }
.copybar {
  order: -1;
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  padding: .625rem max(var(--gutter), var(--safe-right)) .625rem max(var(--gutter), var(--safe-left));
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
}
.copybar__text { flex: 1 1 12rem; min-width: 0; font-size: .875rem; color: var(--text-dim); }
.copybar__acts { display: flex; gap: .375rem; margin-inline-start: auto; }

/* ==========================================================================
   8. 选择器的结果行
   ========================================================================== */

.pgroup { display: flex; flex-direction: column; }
.prow {
  position: relative;
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 3.25rem;
  padding: .4375rem max(var(--gutter), var(--safe-right)) .4375rem max(var(--gutter), var(--safe-left));
  cursor: pointer;
  color: var(--text);
  transition: background 120ms var(--ease);
}
.prow:hover { background: var(--bg-elev2); }
@media (hover: none) { .prow:hover { background: transparent; } }
/* 回车会选的那一行（唯一的「自动选择」，永远看得见）：纸上的墨，不是一整条黑（E5.5）——
   略深一档的纸色底 + 行首一道 2px 墨线 + 墨色的字，行尾一个安静的 ↵ */
.prow[aria-selected="true"],
.prow[aria-selected="true"]:hover { background: var(--fill-hi); color: var(--text); }
.prow[aria-selected="true"]::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 2px;
  background: var(--text);
}
.prow__enter { display: none; flex: none; margin-inline-start: auto; font-family: var(--font-ui); font-size: .875rem; line-height: 1; color: var(--text-faint); }
.prow[aria-selected="true"] .prow__enter { display: inline; }
.prow__badge + .prow__enter { margin-inline-start: 0; }
.prow__seals { flex: none; display: flex; align-items: center; gap: .1875rem; min-width: 1.5rem; }
.prow__text { flex: 1 1 auto; min-width: 0; }
.prow__main { display: flex; align-items: baseline; gap: .5rem; min-width: 0; }
.prow__label {
  flex: 0 1 auto;
  min-width: 0;
  font-family: var(--font-serif);
  font-size: 1.0625rem;
  font-weight: 500;
  /* E9.8：行高 23px = 字 17px + 上下各 3px 的半行距（整数）。1.35（22.95px）的半行距 2.975 被 Blink 向下取整成 2，
     字比行首那枚印高 0.9px（optics：prow__label↔seal −5.2%）；整数的半行距两家引擎都不取整 */
  line-height: 1.4375rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.prow__sub {
  flex: 0 1000 auto;
  min-width: 0;
  font-family: var(--font-serif);
  font-size: .875rem;
  line-height: 1.35;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.prow__sub::before { content: "·"; margin-inline-end: .5rem; color: var(--text-faint); }
/* 当地文字副名自成一行：盒子收成内容宽、贴在行的起始边（مجبوس 在英文行里靠左，在阿拉伯文界面里靠右），
   盒子里面由 dir=auto 自己从右往左（不然整行 238px 的块里它会被推到另一头） */
.prow__loc { display: block; width: fit-content; max-width: 100%; margin-top: .0625rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prow__badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: 1.25rem;
  padding: 0 .4375rem;
  padding-block-end: calc(2 * var(--ink-ui));   /* 墨心居中，见 :root --ink-ui */
  border: 1px solid var(--border);
  border-radius: 99px;
  font-size: .6875rem;
  font-weight: 500;
  line-height: 1;
  color: var(--text-dim);
  white-space: nowrap;
}
/* 多选（E1「可能是这几处」）：每一行行尾一个圈，放进这一组的打勾（墨色） */
.prow__check {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border: 1px solid var(--border);
  border-radius: 50%;
  color: transparent;
}
.prow.is-chosen .prow__check { border-color: var(--text); background: var(--text); color: var(--bg); }
.prow[aria-checked] .prow__enter { display: none; }
.prow__more { flex: none; margin-inline-end: -.5rem; color: inherit; opacity: .7; }
.prow__more[aria-expanded="true"] .ico { transform: rotate(-90deg); }
.prow[aria-selected="true"] .prow__more:hover { background: transparent; color: inherit; opacity: 1; }
/* 多选时头部的「可能是这几处：」 */
.picker__multi .ico { color: var(--text-faint); }
.pnarrow {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  padding: .25rem max(var(--gutter), var(--safe-right)) .75rem calc(max(var(--gutter), var(--safe-left)) + 2.25rem);
}
.pnarrow__label { font-size: .75rem; color: var(--text-faint); }
.pnarrow__chips { display: flex; flex-wrap: wrap; gap: .375rem; }
.pnarrow .chip { height: 2rem; font-size: .875rem; }
/* 有细分的国家那一行 › 展开后的第一行（ADDENDUM-5 E16.8.2）：一枚「{place}全境都算」（白文印），下面照旧「或者具体一点：」 */
.pnarrow__each { display: flex; margin-block-end: .5rem; }
.pnote {
  padding: .5rem max(var(--gutter), var(--safe-right)) .25rem max(var(--gutter), var(--safe-left));
  font-family: var(--font-serif);
  /* ⚠ 不斜体：这一行里是用户打的字，可能是任何文字；汉字的「斜体」是引擎硬拧出来的 */
  font-style: normal;
  font-size: .9375rem;
  color: var(--text-faint);
  overflow-wrap: anywhere;
}
.pcap {
  padding: .25rem max(var(--gutter), var(--safe-right)) .375rem max(var(--gutter), var(--safe-left));
  font-size: .75rem;
  line-height: 1.5;
  color: var(--text-faint);
}
.pcap b { font-weight: 600; color: var(--text-dim); margin-inline-end: .375rem; }
.pempty { padding: 1.25rem max(var(--gutter), var(--safe-right)) .5rem max(var(--gutter), var(--safe-left)); }

/* ==========================================================================
   9. 记录页（补记 / 编辑）、菜的编辑、时间面板
   ========================================================================== */

.entry { display: flex; flex-direction: column; gap: 1.125rem; padding-top: .25rem; }
.entry__top { display: flex; flex-direction: column; gap: .75rem; }
.entry__q {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.3125rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -.01em;
  text-wrap: balance;
}
.entry__add {
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  height: 2.625rem;
  padding: 0 1rem;
  border: 1px solid var(--border);
  border-radius: 99px;
  background: var(--bg-sunken);
  color: var(--text-dim);
  font: inherit;
  font-size: .9375rem;
  text-align: start;
  cursor: text;
}
.entry__add .ico { color: var(--text-faint); }
.entry__add:hover { border-color: var(--accent-line); }
.entry__sec { display: flex; flex-direction: column; gap: .5rem; }
.entry__label {
  display: flex;
  align-items: center;
  gap: .4375rem;
  margin: 0;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--text-dim);
}
.entry__label .ico { color: var(--text-faint); }
.entry__hint { margin: 0; font-size: .8125rem; line-height: 1.5; color: var(--text-faint); }
.entry__foot { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: .25rem; padding-top: .25rem; }
.entry__sec > .btn { align-self: flex-start; }
.entry__slot:empty { display: none; }
/* 记录页里「哪一处？」那一行紧贴在饭票下面（与此刻卡同一个组件） */
.entry__choose .choose:first-child { margin-top: -.125rem; }
/* 当时在（ADDENDUM-2 C2）：一行，点开选择器的「家」模式；值是这一次自己的住处快照 */
.entry__at {
  min-height: 2.75rem;
  padding: .5rem .75rem;
  gap: .5rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  background: var(--bg);
}
.entry__at > .ico:first-child { color: var(--text-faint); }
.entry__at .row__label { flex: 0 0 auto; font-size: .75rem; font-weight: 600; letter-spacing: .04em; color: var(--text-dim); }
.entry__at .row__value { flex: 1 1 auto; max-width: none; font-family: var(--font-serif); font-size: .9375rem; font-weight: 500; color: var(--text); }
.itemlist {
  display: flex;
  flex-direction: column;
  padding: .125rem .25rem .125rem .75rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-card);
  background: var(--bg);
}
.itemlist:empty { display: none; }
.itemlist .dishwrap + .dishwrap { border-top: 1px solid var(--border-soft); }

/* ---- 自己做的一次（ADDENDUM-4 E10）：食材一段展开，一行快签 ----
   此刻卡上：小标题「食材」· 已经加了的几样（与记录页同一个 .itemlist）· 快签；记录页里快签取代〔加一样食材〕按钮。 */
.now__ingr { display: flex; flex-direction: column; gap: .5rem; margin: .5rem 0 .75rem; }
.now__ingr .itemlist { background: var(--bg); border-color: transparent; }
.now__ingrlabel { margin-top: .125rem; }
.homeingr .chips { margin-top: 0; }
.now .homeingr .chips--bleed { margin-inline: -1rem; padding-inline: 1rem; scroll-padding-inline: 1rem; }
.sheet__body .homeingr .chips--bleed { margin-inline: -1.125rem; padding-inline: 1.125rem; scroll-padding-inline: 1.125rem; }
/* 〔本地买的 · 悉尼 ▾〕：一颗签里两个按钮 —— 前一截加这一样，地名那一截改这一次的「当时在」。
   两截共用签的外框（按钮里不许套按钮，所以外框是 span，两个按钮并排）；地名墨色 --text-dim，带一个 ▾ 说「可以换」。 */
.chip--split { gap: 0; padding: 0; cursor: default; }
.chip--split:active { transform: none; }
.chip__main, .chip__place {
  display: inline-flex;
  align-items: center;
  height: 100%;
  margin: 0;
  padding-block: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
}
.chip__main { gap: .5rem; padding-inline: .4375rem .3125rem; border-start-start-radius: inherit; border-end-start-radius: inherit; }
.chip__place { gap: .25rem; padding-inline: .125rem .625rem; color: var(--text-dim); border-start-end-radius: inherit; border-end-end-radius: inherit; }
.chip__place .ico { color: var(--text-faint); }
.chip__main:hover, .chip__place:hover { background: var(--bg-elev2); }
.chip__place:hover { color: var(--text); }
@media (hover: none) { .chip__main:hover, .chip__place:hover { background: transparent; } }
.chip__main:active, .chip__place:active { transform: scale(.985); }

/* 菜的编辑（#pop） */
.ed { display: flex; flex-direction: column; gap: 1rem; padding-top: .125rem; }
.ed__sec { display: flex; flex-direction: column; gap: .5rem; }
.ed__cat { margin: 0; font-size: .8125rem; line-height: 1.5; color: var(--text-faint); }
.ed__sets { display: flex; flex-direction: column; border: 1px solid var(--border-soft); border-radius: var(--radius-card); background: var(--bg); }
.ed__set { display: flex; align-items: center; gap: .625rem; min-height: 3rem; padding: .375rem .375rem .375rem .75rem; }
.ed__set + .ed__set { border-top: 1px solid var(--border-soft); }
.ed__setlabel { flex: 1 1 auto; min-width: 0; font-family: var(--font-serif); font-size: 1rem; font-weight: 500; line-height: 1.35; word-break: keep-all; overflow-wrap: anywhere; }
.ed__setlabel--unclear { color: var(--text-faint); font-weight: 400; }
.ed__checks { display: flex; flex-direction: column; }
.ed__check { display: flex; align-items: center; gap: .75rem; min-height: 2.75rem; cursor: pointer; font-size: .9375rem; }
.ed__check > span { flex: 1 1 auto; }
/* 真的 disabled 的开关（「说不清来处」开着时的「都算」，E16.8.4）：字淡一档、不像能点 */
.ed__check:has(> .toggle:disabled) { cursor: default; color: var(--text-dim); }
.ed__foot { display: flex; justify-content: flex-end; }
.btn--danger-fill { background: var(--danger); border-color: var(--danger); color: var(--accent-contrast); }
.btn--danger-fill:hover { background: var(--danger); border-color: var(--danger); filter: none; }
.ed__fusion { align-self: flex-start; }

/* ==========================================================================
   时间面板（#pop）：日子条 + 一日尺（ADDENDUM-3 E6 / §H，timeline-lab 的 dayline.css 原样搬来）
   --------------------------------------------------------------------------
   ⚠⚠⚠ 只用本文件的令牌（外加 transparent）。一日尺的三档光是**现成令牌的别名**，不是新颜色：
        昼 / 晨昏 / 夜 = 纸的三层（面板、底、柔线）。深浅方向随主题反过来（浅色里夜更深，深色里昼更亮），
        所以别名按家族的样子写三遍：深色是基底，浅色在媒体查询里一遍、[data-theme="light"] 一遍。
        ⚠ 面板里 --bg-elev2 / --bg-sunken 被降成了 --panel-fill，别名不用这两个。
   ⚠⚠ 位置一律 inset-inline-start + 百分比（一格 = 100% / 24），RTL 自己镜像；唯一的 translate 是读数那一下「跳」。
   ⚠ 字号 rem；发丝线、针宽、点径是 px。
   ========================================================================== */
.when { display: flex; flex-direction: column; gap: .875rem; padding-top: .125rem; }
.when__foot { display: flex; justify-content: flex-end; }

/* ---- 光的三档（别名）---- */
.dl {
  --dl-night: var(--bg);
  --dl-twilight: var(--bg-elev);
  --dl-day: var(--border-soft);
  --dl-wash: color-mix(in srgb, var(--text) 8%, transparent);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) .dl {
    --dl-night: var(--border-soft);
    --dl-twilight: var(--bg);
    --dl-day: var(--bg-elev);
    --dl-wash: color-mix(in srgb, var(--text) 5%, transparent);
  }
}
:root[data-theme="light"] .dl {
  --dl-night: var(--border-soft);
  --dl-twilight: var(--bg);
  --dl-day: var(--bg-elev);
  --dl-wash: color-mix(in srgb, var(--text) 5%, transparent);
}

.dl {
  position: relative;
  --h: 0;
  --drawn: 24;
}

/* ---- 滑杆：读数（2.75rem）+ 光带（1.5rem）+ 刻度（1.375rem）---- */
.dl__slider {
  position: relative;
  padding-top: 3rem;
  touch-action: pan-y;          /* 横着拖归尺子，竖着划归面板 */
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
.dl__slider:focus-visible { border-radius: .5rem; }   /* 环本身是家族的 2 px --accent、偏移 2 px，这里只把角放圆 */

/* 读数：跟着针走，夹在两头之内（--x 由 JS 量了写进来） */
.dl__readout {
  position: absolute;
  top: .125rem;
  inset-inline-start: var(--x, 0px);
  display: flex;
  align-items: baseline;
  gap: .1875rem;
  height: 2.5rem;
  white-space: nowrap;
  pointer-events: none;
  transition: inset-inline-start 120ms var(--ease);
}
.dl[data-drag] .dl__readout { transition-duration: 90ms; }
/* 量尺寸时的挪位不走过渡（JS 在 layout() 里短暂挂上 data-still） */
.dl[data-still] .dl__readout, .dl[data-still] .dl__band, .dl[data-still] .dl__needle { transition: none; }
.dl__num {
  display: inline-block;
  font-family: var(--font-serif);
  font-size: 2.125rem;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -.02em;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--text);
  transform-origin: 50% 90%;
}
.dl__readout[data-kind="part"] .dl__num { font-size: 1.5rem; letter-spacing: 0; }
/* 不记时间：读数这一行不空着，轻轻说一句尺子怎么用 */
.dl__hint {
  align-self: center;
  font-family: var(--font-ui);
  font-size: .8125rem;
  color: var(--text-faint);
}
.dl__unit {
  font-family: var(--font-serif);
  font-size: .9375rem;
  font-weight: 500;
  line-height: 1;
  color: var(--text-dim);
}
.dl__unit--pre { margin-inline-end: .0625rem; }
/* 「此刻」：只在今天、并且针就停在此刻那一格时出现（与此刻卡的说明字同一个口吻） */
.dl__nowcap {
  margin-inline-start: .4375rem;
  font-family: var(--font-ui);
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--text-faint);
}

/* 小时一变，数字轻轻一跳：只有这一下；基础样式 = 终态 */
.dl__num.is-bump { animation: dl-bump 220ms var(--ease-stamp); }
@keyframes dl-bump {
  from { transform: translateY(-.1875rem) scale(1.045); }
  to { transform: none; }
}

/* ---- 光带 ---- */
.dl__track { position: relative; height: 1.5rem; }
.dl__band {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: calc(var(--drawn) * 100% / 24);
  display: flex;
  overflow: hidden;
  border-radius: .375rem;
  transition: width 300ms var(--ease);
}
/* 发丝框画在格子上面（框线不占宽度，格子才与刻度逐格对齐） */
.dl__band::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--border);
  border-radius: inherit;
  pointer-events: none;
}
.dl__cell { flex: 1 1 0; min-width: 0; background: var(--dl-day); }
.dl__cell[data-tone="t"] { background: var(--dl-twilight); }
.dl__cell[data-tone="n"] { background: var(--dl-night); }

/* 今天：此刻之后还没画，只留一根虚线 */
.dl__thread {
  position: absolute;
  top: calc(50% - .5px);
  inset-inline-start: calc(var(--drawn) * 100% / 24 + 5px);
  inset-inline-end: 0;
  border-top: 1px dashed var(--border);
}
.dl:not([data-today]) .dl__thread { display: none; }

/* 选中的时段：一片淡墨，只染它那三个钟点（在光带之内，不画框：是一抹墨，不是一个选框） */
.dl__wash {
  position: absolute;
  inset-block: 1px;
  inset-inline-start: calc(var(--a, 0) * 100% / 24 + 1px);
  width: calc(var(--n, 3) * 100% / 24 - 2px);
  border-radius: 4px;
  background: var(--dl-wash);
  opacity: 0;
  transition: opacity 160ms var(--ease), inset-inline-start 160ms var(--ease);
  pointer-events: none;
}
.dl[data-mode="part"] .dl__wash { opacity: 1; }
/* 大概：读数与光带之间是一道印章红的括号（开口朝下，罩住那三个钟点）——
   与准点的竖针同一个位置、同一个角色：红 = 选中的时间，形状 = 准到哪（一点 / 一段） */
.dl__span {
  position: absolute;
  bottom: calc(100% + 3px);
  height: 7px;
  inset-inline-start: calc(var(--a, 0) * 100% / 24 + 3px);
  width: calc(var(--n, 3) * 100% / 24 - 6px);
  border: 1.5px solid var(--accent);
  border-bottom: 0;
  border-radius: 3px 3px 0 0;
  opacity: 0;
  transition: opacity 160ms var(--ease), inset-inline-start 160ms var(--ease);
  pointer-events: none;
}
.dl[data-mode="part"] .dl__span { opacity: 1; }

/* 这一天已经记下的：墨点（小时）、空心圈（时段，落在名义钟点上）；同一格最多叠 3 个 */
.dl__dot {
  position: absolute;
  top: calc(50% - 2.5px + var(--k, 0) * 7px);
  inset-inline-start: calc((var(--h) + .5) * 100% / 24 - 2.5px);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-dim);
}
.dl__dot--part { background: transparent; box-shadow: inset 0 0 0 1.25px var(--text-dim); }

/* 针：印章红 2 px，从读数下沿穿过光带，落到长刻度的底 */
.dl__needle {
  position: absolute;
  top: -.5rem;
  bottom: -.4375rem;
  inset-inline-start: calc((var(--h) + .5) * 100% / 24 - 1px);
  width: 2px;
  border-radius: 1px;
  background: var(--accent);
  transition: inset-inline-start 120ms var(--ease);
  pointer-events: none;
}
.dl[data-drag] .dl__needle { transition-duration: 90ms; }
.dl:not([data-mode="hour"]) .dl__needle { display: none; }

/* 桌面悬停：一根淡墨线预告「点这里会落在哪一格」 */
.dl__hover {
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc((var(--h) + .5) * 100% / 24 - .5px);
  width: 1px;
  background: var(--text-faint);
  opacity: .55;
  pointer-events: none;
}
@media (hover: none) { .dl__hover { display: none; } }

/* ---- 刻度：每小时一根短的，每 3 小时一根长的，从光带下沿垂下来 ---- */
.dl__scale { position: relative; height: 1.375rem; }
.dl__tick {
  position: absolute;
  top: 0;
  inset-inline-start: calc((var(--h) + .5) * 100% / 24 - .5px);
  width: 1px;
  height: 3px;
  background: var(--border);
}
.dl__tick[data-major] { height: 6px; background: var(--text-faint); }
.dl__tick[data-future] { opacity: .45; }
.dl__numeral {
  position: absolute;
  top: .5rem;
  inset-inline-start: var(--x, 0px);
  font-family: var(--font-serif);
  font-size: .6875rem;
  font-weight: 400;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--text-faint);
  white-space: nowrap;
}
.dl__numeral[data-future] { opacity: .45; }

/* ---- 时段：尺子下的五个括号（开口朝上，指着它覆盖的钟点）---- */
.dl__parts { position: relative; height: 2.75rem; margin-top: .3125rem; }
.dl[data-stagger] .dl__parts { height: 3.875rem; }
.dl__part {
  position: absolute;
  top: 0;
  bottom: 0;
  inset-inline-start: calc(var(--a) * 100% / 24);
  width: calc(var(--n) * 100% / 24);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  font: inherit;
}
.dl__part::before {
  content: "";
  position: absolute;
  top: .1875rem;
  inset-inline: 3px;
  height: 5px;
  border: 1px solid var(--border);
  border-top: 0;
  border-radius: 0 0 3px 3px;
  transition: border-color 140ms var(--ease);
}
.dl__plabel {
  position: absolute;
  top: .875rem;
  inset-inline-start: var(--x, 0px);
  font-family: var(--font-serif);
  font-size: .875rem;
  font-weight: 500;
  /* 行高 1（不是实验室的 1.3）：Blink 把正的半行距向下取整，拉丁的时段名（Pho / Lunch）在 1.3 里偏高 8%（E7 探针） */
  line-height: 1;
  white-space: nowrap;
  transition: color 140ms var(--ease);
}
/* 拼音文字的时段名更长：小半号，一行里多挤出一点缝 */
html:not(:lang(zh)):not(:lang(ja)):not(:lang(ko)) .dl__plabel { font-size: .8125rem; }
/* 错成两行时（长名字的语言），第 2、4 个（午饭、晚饭）落到下一行，
   从括号正中垂一根发丝线下去接住它：线正好穿过上一行两个名字之间的缝 */
.dl[data-stagger] .dl__part:nth-child(2n) .dl__plabel { top: 2.0625rem; }
.dl[data-stagger] .dl__part:nth-child(2n)::after {
  content: "";
  position: absolute;
  top: calc(.1875rem + 5px);
  inset-inline-start: calc(50% - .5px);
  width: 1px;
  height: calc(2.0625rem - .1875rem - 5px - 4px);
  /* 饭票上的点线竖过来：1 px 圆点，间距 4 px */
  background: radial-gradient(circle, var(--text-faint) .6px, transparent .9px) center top / 1px 4px repeat-y;
  opacity: .8;
}
.dl[data-stagger] .dl__part[aria-pressed="true"]:nth-child(2n)::after { background-image: radial-gradient(circle, var(--text) .6px, transparent .9px); opacity: 1; }
.dl__part:hover .dl__plabel { color: var(--text); }
.dl__part:hover::before { border-color: var(--text-faint); }
.dl__part[aria-pressed="true"] { color: var(--text); }
.dl__part[aria-pressed="true"] .dl__plabel { font-weight: 600; }
.dl__part[aria-pressed="true"]::before { border-color: var(--text); }
.dl__part:disabled { cursor: default; opacity: .4; }
.dl__part:disabled:hover .dl__plabel { color: var(--text-dim); }
.dl__part:disabled:hover::before { border-color: var(--border); }
.dl__part:focus-visible { outline-offset: 0; }
@media (hover: none) {
  .dl__part:hover .dl__plabel { color: inherit; }
  .dl__part:hover::before { border-color: var(--border); }
  .dl__part[aria-pressed="true"]:hover::before { border-color: var(--text); }
}

/* ---- 底行：「不记时间」安静的文字钮 + 应用放进来的〔好了〕---- */
.dl__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin-top: .5rem;
}
.dl__none {
  position: relative;
  min-height: 2.25rem;
  padding: 0 .125rem;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: .875rem;
  cursor: pointer;
}
.dl__none::after {
  content: "";
  position: absolute;
  inset-inline: .125rem;
  bottom: .25rem;
  height: 2px;
  border-radius: 1px;
  background: var(--text);
  opacity: 0;
  transition: opacity 140ms var(--ease);
}
.dl__none:hover { color: var(--text); }
.dl__none[aria-pressed="true"] { color: var(--text); font-weight: 600; }
.dl__none[aria-pressed="true"]::after { opacity: 1; }
@media (hover: none) { .dl__none:hover { color: var(--text-dim); } .dl__none[aria-pressed="true"]:hover { color: var(--text); } }
html[data-touch="on"] .dl__none { min-height: 2.75rem; }

/* ==========================================================================
   日子条：星期小字在上、日数在下，选中 = 日数下一道 2 px 墨线；今天的小字写「今天」
   ========================================================================== */
.dl-days { gap: 0; padding-block: 0; }
.dl-day {
  flex: none;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .3125rem;
  width: 2.75rem;
  height: 3.625rem;
  padding: 0 0 .375rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  font: inherit;
}
.dl-day__wd {
  font-family: var(--font-ui);
  font-size: .625rem;
  font-weight: 500;
  line-height: 1;
  color: var(--text-faint);
  white-space: nowrap;
}
.dl-day__dn {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: lining-nums tabular-nums;
}
.dl-day::after {
  content: "";
  position: absolute;
  bottom: .3125rem;
  inset-inline-start: calc(50% - .5625rem);
  width: 1.125rem;
  height: 2px;
  border-radius: 1px;
  background: var(--text);
  opacity: 0;
  transition: opacity 140ms var(--ease);
}
.dl-day[data-today] .dl-day__wd { color: var(--text); font-weight: 600; }
.dl-day[aria-pressed="true"] { color: var(--text); }
.dl-day[aria-pressed="true"] .dl-day__dn { font-weight: 600; }
.dl-day[aria-pressed="true"]::after { opacity: 1; }
.dl-day:hover { color: var(--text); }
.dl-day--extra { margin-inline-end: .75rem; }
.dl-days__more {
  flex: none;
  align-self: center;
  min-height: 2.25rem;
  margin-inline-end: .25rem;
  padding-block: 0;
  padding-inline: 0 .625rem;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: .8125rem;
  white-space: nowrap;
  cursor: pointer;
}
.dl-days__more:hover { color: var(--text); }
@media (hover: none) { .dl-day:hover { color: var(--text-dim); } .dl-day[aria-pressed="true"]:hover { color: var(--text); } .dl-days__more:hover { color: var(--text-dim); } }

/* 换深浅色（app.js setTheme 用 View Transitions）：整页的旧样子淡出、新样子淡入，--t-xfade --ease（E8：大面积变暗变亮
   不「啪」地换）。引擎不支持时没有这一段，直接换；减少动态效果时下面的全局规则把它压到 0。 */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: var(--t-xfade); animation-timing-function: var(--ease); }

/* ==========================================================================
   10. 减少动态效果（Parote 原样）：动画缩到瞬间，所以基础样式必须 = 终态，退场一律用过渡
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: .001ms !important;
  }
}

/* ==========================================================================
   11. 断点：≥ 720 表单 / 小浮层 / 对话框是整窗居中的对话框；≥ 900 桌面三栏（rail | panel | 地图）
   另：今天页的刊头与浮在小图上的顶栏（手机）、小屏与横屏
   ========================================================================== */

/* ---- 今天页：日期头还在屏上时，顶栏不写日期、不画发丝线（大号日期就是标题，不写两遍）；滚过去才出现 ---- */
.topbar { transition: border-color 160ms var(--ease), background-color 160ms var(--ease); }
.topbar__title { transition: opacity 160ms var(--ease); }
#app[data-view="today"]:not([data-mast-off]) .topbar { border-bottom-color: transparent; }
#app[data-view="today"]:not([data-mast-off]) .topbar__title { opacity: 0; }
/* ⚠ E14.6：上面这两条过渡只给「在今天页里滚过日期头」用。换页签的那一刻（app.js go() 同步加上、算定终态后拿掉
   data-vswap）顶栏一步到终态：不然从地图回到今天，刚写上的「9月23日 周三」带着 160ms 从 1 淡到 0，在左上角一闪而过
   （量过：Chrome 与 WebKit 都有 8–10 帧看得见）。标题的字换了就与新的一页同一个 140ms 淡入（.is-in；看不见的标题淡入也看不见）。 */
#app[data-vswap] .topbar,
#app[data-vswap] .topbar * { transition: none; }
.topbar__title.is-in { animation: viewIn var(--t-view) var(--ease); }

/* ---- 手机、有小图时：顶栏透明地浮在小图上（只剩 ⚙，垫一枚纸色的圆）；
   今天页一滚动就铺回不透明的纸色（小图滚到状态栏底下时，iOS 26 取色取到的仍是纸）。 ---- */
@media (max-width: 899px) and (min-height: 501px) {
  #app[data-plate][data-view="today"] .topbar {
    position: absolute;
    top: 0;
    inset-inline: 0;
    background: transparent;
  }
  #app[data-plate][data-view="today"][data-mast-scrolled] .topbar { background: var(--bg); }
  #app[data-plate][data-view="today"]:not([data-mast-scrolled]) #btnSettings { background: var(--bg-elev); box-shadow: var(--shadow-sm); }
  #app[data-plate][data-view="today"]:not([data-mast-scrolled]) #btnSettings { border: 1px solid var(--border); border-radius: 99px; }
}

/* ---- 小屏（高 ≤ 700，SE 一类）：小图收一档、间距收紧，此刻卡的问句留在折线以上 ---- */
@media (max-height: 700px) and (max-width: 899px) {
  :root { --mast-h: clamp(8.5rem, 22svh, 10rem); }
  .mast__head { padding-top: .75rem; }
  .mast__day { font-size: 3.75rem; }
  .mast__sent { font-size: 1rem; line-height: 1.4; }
  .now { margin-top: .875rem; padding-top: .8125rem; }
  .now__q { font-size: 1.3125rem; margin: .375rem 0 .75rem; }
  .week__cols { --jstep: calc(var(--js) * .76); }
}
/* 横屏手机（矮于 500）：小图让位（顶栏照常不透明，见上一条的 min-height） */
@media (max-height: 500px) and (max-width: 899px) {
  .mast__plate { display: none; }
}

@media (min-width: 720px) {
  :root { --gutter: 24px; }

  /* ---- ADDENDUM-3 E3：表单、小浮层、对话框 = 整窗居中的一张纸 ----
     遮罩盖满整窗（rail、panel、地图一起，暖色 --scrim）；纸宽 560 / 420 / 440，高不超过 min(80vh, 760px)，
     四角 --radius-sheet、--shadow-lg，里面自己滚。进：translateY(.5rem) scale(.985) → 原位 220ms --ease；
     出：170ms 过渡（减少动态效果时直接到位）。从 #welcome 打开的表单也一样（不再挤在左边一栏）。 */
  .sheet { display: flex; align-items: center; justify-content: center; padding: 1.5rem; }
  .sheet__panel {
    position: relative;
    inset: auto;
    width: min(35rem, 100%);
    max-height: min(80vh, 47.5rem);
    border: 1px solid var(--border);
    border-radius: var(--radius-sheet);
    padding-bottom: 0;
    opacity: 0;
    transform: translateY(.5rem) scale(.985);
    transition: transform var(--t-in) var(--ease), opacity var(--t-in) var(--ease);
  }
  .sheet.is-open .sheet__panel { opacity: 1; transform: translateY(calc(-.5 * var(--kb))); }
  .sheet.is-closing .sheet__panel { opacity: 0; transform: translateY(.5rem) scale(.985); transition: transform var(--t-out) var(--ease-exit), opacity var(--t-out) var(--ease-exit); }
  .sheet--pop .sheet__panel { width: min(26.25rem, 100%); max-height: min(80vh, 47.5rem); }
  .dialog__panel { max-height: min(80vh, 47.5rem); }
}

@media (min-width: 900px) {
  .app {
    display: grid;
    grid-template-columns: var(--rail-w) var(--panel-w) minmax(0, 1fr);
    height: 100%;
  }
  .tabbar { display: none; }
  #btnSettings { display: none; }
  .main { height: 100%; border-inline-end: 1px solid var(--border-soft); }
  .topbar { padding-top: 0; height: var(--topbar-h); padding-left: 0; padding-right: 0; padding-inline-start: 1.25rem; padding-inline-end: .75rem; }

  .rail {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
    min-height: 0;
    padding: .875rem 0 1rem;
    background: var(--bg);
    border-inline-end: 1px solid var(--border-soft);
  }
  .rail__brand { margin-bottom: 1.125rem; line-height: 0; }
  .rail__btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .3125rem;
    width: 3.75rem;
    padding: .5625rem 0 .5rem;
    border: 0;
    border-radius: .625rem;
    background: transparent;
    color: var(--text-faint);
    font-family: var(--font-ui);
    font-size: .6875rem;
    font-weight: 500;
    line-height: 1.2;
    cursor: pointer;
    transition: background 140ms var(--ease), color 140ms var(--ease);
  }
  .rail__btn:hover { background: var(--bg-elev2); color: var(--text-dim); }
  .rail__btn[aria-current="page"] { color: var(--accent); }
  .rail__btn--gear { margin-top: auto; }
  .rail__label { max-width: 100%; padding-inline: .125rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .deskmap { display: block; position: relative; min-width: 0; min-height: 0; background: var(--bg); }
  .view--map .mapslot { display: none; }

  /* 今天页：没有小图（真地图就在右栏，E9.1），日期头直接开页 */
  .mast__plate { display: none; }
  .mast__head { padding-top: .25rem; }

  /* 提示条住在 panel 这一栏的底上（它说的是这一栏里的列表）；浮层开着时挪到整窗底部正中 */
  .toast { inset-inline-start: var(--rail-w); inset-inline-end: auto; width: var(--panel-w); --toast-lift: 1.25rem; }
  #app[data-view="today"] .toast { --toast-lift: calc(var(--omni-h) + .75rem); }
  html[data-layer] .toast { inset-inline: 0; width: auto; top: auto; bottom: 0; transform: translateY(-1.25rem); }
  html[data-layer] .toast__box { animation-name: toastIn; }
  html[data-layer] .toast__box.is-out { transform: translateY(.375rem); }

  /* ---- 选择器 = 居中的调色板（Parote 的命令面板）：宽 640、离顶 12vh，输入框在上、签在它下面、结果往下长；
     遮罩与表单同一层暖色 --scrim。「在地图上选」收起调色板、地图上方出横幅（app.js pickOnMap）。 ---- */
  .picker__backdrop { background: var(--scrim); opacity: 0; transition: opacity var(--t-scrim-in) var(--ease); }
  .picker.is-open .picker__backdrop { opacity: 1; }
  .picker.is-closing .picker__backdrop { opacity: 0; transition: opacity var(--t-scrim-out) var(--ease-exit); }
  .picker__panel {
    inset: auto;
    top: 12vh;
    inset-inline: 0;
    margin-inline: auto;
    width: min(40rem, calc(100% - 4rem));
    max-height: min(76vh, 44rem);
    padding-top: 0;
    background: var(--bg-elev);
    border: 1px solid var(--border);
    border-radius: var(--radius-sheet);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    transform: translateY(.5rem) scale(.985);
  }
  .picker.is-open .picker__panel { transform: none; }
  .picker.is-closing .picker__panel { transform: translateY(.5rem) scale(.985); transition: opacity var(--t-out) var(--ease-exit), transform var(--t-out) var(--ease-exit); }
  /* 打字时结果变多变少：面板的高度过渡过去（app.js growBox；E14.2）。只动 height，边框、圆角、投影不动 */
  .picker__panel.is-swapping { transition: opacity var(--t-in) var(--ease), transform var(--t-in) var(--ease), height var(--t-grow) var(--ease); }
  .picker__head { order: 0; min-height: 2.75rem; padding: .25rem .5rem 0 1.25rem; padding-inline: 1.25rem .5rem; background: transparent; border-bottom: 0; }
  .picker__inputrow { order: 1; padding: .25rem 1rem .5rem; background: transparent; transform: none; }
  html[data-kb] .picker__inputrow { padding-bottom: .5rem; }
  .picker__glass { inset-inline-start: 1.9375rem; }
  .picker__chips { order: 2; padding: 0 0 .5rem; background: transparent; transform: none; }
  .picker__chips > .chips { padding-inline: 1rem; }
  .picker__list { order: 3; flex: 0 1 auto; flex-direction: column; transform: none; padding-block: .375rem .75rem; border-top: 1px solid var(--border-soft); }
  .picker__list:empty { display: none; }
  .picker .prow, .picker .pnote, .picker .pcap, .picker .pempty { padding-inline: 1.25rem; }
  .picker .pnarrow { padding-inline: 3.5rem 1.25rem; }
  .omni { padding-bottom: .75rem; }
}

@media (min-width: 1280px) {
  :root { --panel-w: 440px; }
}
