/* =========================================================
   学习笔记 · 主站样式
   ---------------------------------------------------------
   设计变量与「工具箱」（/tools/）保持完全一致，
   两个站放在同一域名下时看起来是同一个站。
   配色：纯黑白，只用黑 / 白 / 灰阶。
   ========================================================= */

:root {
  /* ---- 亮色（默认）：白底黑字 ---- */
  --paper:       #fbfbfa;
  --surface:     #ffffff;
  --ink:         #151515;
  --ink-2:       #5c5c60;
  --ink-3:       #8e8e94;
  --line:        #e4e4e2;
  --line-strong: #c9c9c5;
  --fill:        #151515;
  --on-fill:     #ffffff;

  /* 告诉浏览器现在是亮色：输入框、下拉框、滚动条这些由浏览器
     自己画的部件会跟着用亮色，不会在深色页面里突兀地亮一块。 */
  color-scheme: light;

  /* ---- 字号 ---- */
  --fs-body: 1.0625rem;
  --fs-sm:   .9375rem;
  --fs-xs:   .8125rem;
  --fs-h1:   clamp(1.7rem, 1.25rem + 1.8vw, 2.25rem);
  --fs-h2:   1.25rem;
  --fs-item: clamp(1.125rem, 1rem + .6vw, 1.375rem);
  --lh:      1.8;   /* 中文正文行高要松 */

  /* ---- 间距 ---- */
  --sp-1: .25rem;
  --sp-2: .5rem;
  --sp-3: .75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;

  /* ---- 布局 ---- */
  --measure: 38rem;   /* 正文栏宽，约 36 个汉字一行 */
  --wrap:    64rem;   /* 页面宽度。和工具箱那份（tools/style.css）保持一致，
                         改一个务必改另一个，否则跨站跳转时容器会宽窄不一 */
  --radius:  6px;

  /* ---- 字体（全部系统字体，零外部依赖）---- */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
               "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", monospace;
}

/* ---- 深色：按了页头开关手动选的这套 ----
   ⚠️ 下面这 9 个颜色和再下面 @media 里那份必须一模一样，
   改一个务必改另一个，不然「手动深色」和「跟随系统深色」
   会长得不一样。 */
:root[data-theme="dark"] {
  --paper:       #0f0f0f;
  --surface:     #171717;
  --ink:         #ededed;
  --ink-2:       #a2a2a6;
  --ink-3:       #6f6f74;
  --line:        #262626;
  --line-strong: #3d3d3d;
  --fill:        #ededed;
  --on-fill:     #0f0f0f;
  color-scheme: dark;
}

/* ---- 深色：没按过开关时跟着系统走 ----
   也是禁用 JS 时的兜底（那样就切不了了，至少系统是深色时它还深）。
   :not([data-theme]) 是关键 —— 手动选过亮色的人，
   哪怕系统是深色，也不该被这份规则拉回去。 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --paper:       #0f0f0f;
    --surface:     #171717;
    --ink:         #ededed;
    --ink-2:       #a2a2a6;
    --ink-3:       #6f6f74;
    --line:        #262626;
    --line-strong: #3d3d3d;
    --fill:        #ededed;
    --on-fill:     #0f0f0f;
    color-scheme: dark;
  }
}

/* =========================================================
   基础
   ========================================================= */

*, *::before, *::after { box-sizing: border-box; }

/* 根元素必须自己铺一层底色。
   不写这条的话，页面之外的「画布」底色由 color-scheme 推导 ——
   切换深浅色时它会比页面内容先一步跳变（白变纯黑），而它不属于
   DOM、不在视图快照里，动画收尾撤掉快照的那一帧就会闪出这块纯黑。
   写在 html 上，底色就成了页面的一部分，跟着快照一起参与动画。 */
html {
  -webkit-text-size-adjust: 100%;
  background: var(--paper);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

/* 元素上任何显式的 display 都会盖掉 hidden 属性，
   所以这条用 !important 提权，保证 hidden 任何时候都管用 */
[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

::selection {
  background: var(--ink);
  color: var(--paper);
}

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--sp-5);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
}
.skip:focus {
  left: var(--sp-4);
  top: var(--sp-4);
  z-index: 10;
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
}

/* =========================================================
   页头
   ========================================================= */

.site-header { border-bottom: 1px solid var(--line); }

.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  min-height: 4rem;
}

.brand {
  font-size: 1rem;
  font-weight: 650;
  letter-spacing: .01em;
}

.nav {
  display: flex;
  gap: var(--sp-5);
  font-size: var(--fs-sm);
}
.nav a { color: var(--ink-2); }
.nav a:hover { color: var(--ink); }
.nav a[aria-current="page"] { color: var(--ink); font-weight: 600; }

/* =========================================================
   首页
   ========================================================= */

.intro {
  padding: var(--sp-7) 0 var(--sp-6);
}
.intro h1 {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-h1);
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -.01em;
}
.intro p {
  max-width: var(--measure);
  margin: 0;
  color: var(--ink-2);
}

.section-label {
  margin: 0 0 var(--sp-5);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
  letter-spacing: .04em;
}

/* ---- 文章列表 ---- */

.post-list {
  margin: 0 0 var(--sp-8);
  padding: 0;
  list-style: none;
}
.post-list li + li { margin-top: var(--sp-6); }

.post-list a,
.post-list .post-row {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: var(--sp-5);
  align-items: baseline;
  padding: var(--sp-2) 0;
}

.post-list time {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
  letter-spacing: .02em;
}

.post-list h2 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-item);
  font-weight: 600;
  line-height: 1.45;
}

.post-list p {
  max-width: 34rem;
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--ink-2);
}

.post-list a:hover h2 { text-decoration: underline; text-underline-offset: 3px; }
.post-list a:active { transform: translateY(1px); }

/* 还没写的文章：灰色、不可点，一眼区分 */
.is-pending .post-row h2,
.is-pending .post-row p { color: var(--ink-3); }

.post-badge {
  display: inline-block;
  margin-top: var(--sp-3);
  padding: .1rem .5rem;
  font-family: var(--font-mono);
  font-size: .75rem;
  color: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* ---- 工具箱入口条 ---- */

.strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  /* 1rem 而不是 3rem：首页下面现在并排放着两条（工具箱 + 投稿），
     3rem 会把它们拉得太开。和页脚之间的距离由页脚自己的 margin-top 负责。 */
  margin-bottom: var(--sp-4);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color .15s ease;
}
.strip:hover { border-color: var(--line-strong); }
.strip:active { transform: translateY(1px); }

/* 这三个是 span，必须显式设成 block。
   行内元素不认 margin，也不会换行，
   不设的话标题和描述会挤在同一行糊成一片。 */
.strip-text {
  display: block;
  min-width: 14rem;
}
.strip-title {
  display: block;
  margin: 0 0 var(--sp-1);
  font-size: 1.0625rem;
  font-weight: 600;
}
.strip-desc {
  display: block;
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.strip-arrow {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--ink-3);
  white-space: nowrap;
}
.strip:hover .strip-arrow { color: var(--ink); }

/* =========================================================
   首页筛选
   ========================================================= */

.filter { margin-bottom: var(--sp-6); }   /* 和下面的文章列表拉开一点 */

.filter-input {
  display: block;
  width: 100%;
  max-width: 22rem;
  margin: 0;   /* 它现在是筛选区的第一行，上面不用留间距 */
  padding: .5rem .75rem;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.filter-input::placeholder { color: var(--ink-3); }
.filter-input:focus-visible {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

/* 标签按钮。选中时黑底白字，和主按钮是同一套语言 */
.chip {
  padding: .25rem .7rem;
  font: inherit;
  font-size: var(--fs-xs);
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease;
}
.chip:hover {
  color: var(--ink);
  border-color: var(--line-strong);
}
.chip.is-on {
  color: var(--on-fill);
  background: var(--fill);
  border-color: var(--fill);
}

.filter-info {
  margin: var(--sp-3) 0 0;   /* 跟着搜索框走，别离太远 */
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

/* 筛选项分两行：分类一行，标签一行。
   平时收着 —— 每行只有一个按钮显示当前选中的值；点开才铺成网格。
   整体靠左，和上面的搜索框、下面的文章列表对齐一条线。 */
.filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-3);   /* 分类和标签是一组，挨近些 */
}

.filter-label {
  min-width: 2.75rem;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .04em;
  color: var(--ink-3);
}

/* 分类 / 标签的按钮组。平铺直显，一排摆不下就换行 */
.filter-grid {
  display: flex;
  flex-wrap: wrap;
  flex: 1;
  gap: var(--sp-2);
}

/* ---- 首页上面那两条入口（工具箱 / 投稿）----
   原来是一个通栏的大条，现在改成并排两小块，挪到文章列表上面。 */

.entries {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--sp-4);
  margin: var(--sp-6) 0;
}

.entry {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-4) var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color .15s ease;
}
.entry:hover { border-color: var(--line-strong); }
.entry:active { transform: translateY(1px); }

.entry-title {
  font-size: 1rem;
  font-weight: 650;
}

.entry-desc {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--ink-2);
}

.entry-arrow {
  margin-top: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}
.entry:hover .entry-arrow { color: var(--ink); }

.filter-empty,
.post-empty {
  padding: var(--sp-6) 0;
  color: var(--ink-3);
  text-align: center;
}

/* =========================================================
   文章页 / 关于页
   ========================================================= */

.back {
  display: inline-block;
  margin-bottom: var(--sp-5);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}
.back:hover { color: var(--ink); }

.article {
  max-width: var(--measure);
  padding-bottom: var(--sp-7);
}

.article header { margin-bottom: var(--sp-7); }

.article h1 {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-h1);
  font-weight: 650;
  line-height: 1.4;
  letter-spacing: -.01em;
}

.article .meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

.article h2 {
  margin: var(--sp-7) 0 var(--sp-4);
  font-size: var(--fs-h2);
  font-weight: 600;
  line-height: 1.45;
}

.article p { margin: 0 0 var(--sp-5); }

.article ul,
.article ol {
  margin: 0 0 var(--sp-5);
  padding-left: 1.4em;
}
.article li { margin-bottom: var(--sp-2); }

.article strong { font-weight: 650; }

.article code {
  font-family: var(--font-mono);
  font-size: .875em;
  padding: .1em .38em;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 4px;
}

.article pre {
  margin: 0 0 var(--sp-5);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 2px solid var(--ink);
  border-radius: var(--radius);
  overflow-x: auto;
  line-height: 1.7;
}
.article pre code {
  padding: 0;
  background: none;
  border: 0;
  font-size: var(--fs-sm);
}

.article blockquote {
  margin: 0 0 var(--sp-5);
  padding: var(--sp-1) 0 var(--sp-1) var(--sp-5);
  border-left: 2px solid var(--line-strong);
  color: var(--ink-2);
}
.article blockquote p:last-child { margin-bottom: 0; }

.article table {
  width: 100%;
  margin: 0 0 var(--sp-5);
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.article th,
.article td {
  padding: var(--sp-2) var(--sp-3);
  text-align: left;
  border: 1px solid var(--line);
}
.article th { color: var(--ink-2); font-weight: 600; }

/* =========================================================
   投稿页（submit.html）
   ========================================================= */

.article .lead {
  margin: var(--sp-4) 0 0;
  font-size: 1.0625rem;
  color: var(--ink-2);
}

/* 放在表单前面的提示块。这是整页最该被看到的东西，所以给它加粗的左边线 */
.notice {
  margin: var(--sp-6) 0;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 2px solid var(--ink);
  border-radius: var(--radius);
}
.notice h2 {
  margin: 0 0 var(--sp-4);
  font-size: 1rem;
  font-weight: 650;
}
.notice ul {
  margin: 0;
  padding-left: 1.3em;
  font-size: var(--fs-sm);
  line-height: 1.8;
  color: var(--ink-2);
}
.notice li { margin-bottom: var(--sp-3); }
.notice li:last-child { margin-bottom: 0; }
.notice strong { color: var(--ink); }

/* ---- 长按确认 ----
   按住圆钮 2.5 秒，外圈进度环顺时针走满才算确认；中途松手，环退回去。
   走动本身交给 transition，脚本只管加 / 去 .is-holding 这个开关。 */

.hold-zone {
  display: flex;
  justify-content: center;
  margin-top: var(--sp-5);
}

.hold-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 6rem;
  height: 6rem;
  padding: 0;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  /* 底色比卡片（.notice 是 --surface）沉一档，圆才立得出来；
     边框用 --line-strong 而不是 --line —— 后者在深色下基本看不见。 */
  background: var(--paper);
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;   /* 手机上长按别弹复制菜单 */
  touch-action: none;            /* 按住时别把页面滚起来 */
  transition: color .2s ease, border-color .2s ease;
}
.hold-btn:hover { color: var(--ink); border-color: var(--ink-3); }
/* 按住时边框提到最亮，配合外圈长出来的环一起给反馈 */
.hold-btn.is-holding { color: var(--ink); border-color: var(--ink); }

/* 环画在按钮外圈（inset 取负），整体转 -90° 让起点落在 12 点方向，
   走起来就是顺时针。平时缩到零、看不见，按住才长出来。 */
.hold-ring {
  position: absolute;
  inset: -.45rem;
  transform: rotate(-90deg);
}
.hold-ring-fg {
  fill: none;
  stroke: var(--ink);
  stroke-width: 3;
  /* pathLength="100" 把周长归一成 100。dasharray 给 101 而不是 100：
     正好相等时首尾会在 12 点那儿差出一道肉眼可见的缝，多给 1 让它叠上。
     空环偏移 101，满环偏移 0。端点用默认平头 —— 圆头在空的时候会留个小点。 */
  stroke-dasharray: 101;
  stroke-dashoffset: 101;
  /* 默认是「松手后退回」：短一些、带缓动，看着像自己缩回去 */
  transition: stroke-dashoffset .45s cubic-bezier(.4, 0, .2, 1);
}
/* 按住：2.5 秒匀速爬满 */
.hold-btn.is-holding .hold-ring-fg {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 2.5s linear;
}
/* 走满之后环留在满的位置 */
.hold-btn.is-done .hold-ring-fg {
  stroke-dashoffset: 0;
  transition: none;
}

.hold-idle,
.hold-done {
  position: relative;   /* 压在圆环上面 */
  align-items: center;
}
.hold-done { display: none; }
.hold-btn.is-done .hold-idle { display: none; }
.hold-btn.is-done .hold-done {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  color: var(--ink);
  font-weight: 600;
}
.hold-check {
  width: 1.4rem;
  height: 1.4rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 走满那一下，左右轻震 */
@keyframes hold-shake {
  0%, 100% { transform: translateX(0); }
  15%      { transform: translateX(-4px); }
  35%      { transform: translateX(4px); }
  55%      { transform: translateX(-3px); }
  75%      { transform: translateX(2px); }
}
.hold-btn.is-shaking { animation: hold-shake .5s ease-out; }

/* 没确认就去戳正文区：按钮抖一下、外圈闪一下红，意思是「先看上面」 */
.hold-btn.is-nudge { animation: hold-shake .5s ease-out; }
.hold-btn.is-nudge .hold-ring-fg {
  stroke: #e5484d;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .2s ease, stroke .2s ease;
}

/* 盖在锁着的正文上，专门接住点击。
   inert 会把指针事件整个吞掉，不铺这层就收不到「他在点正文」这个信号。 */
.body-wrap { position: relative; }
.body-lock {
  position: absolute;
  inset: 0;
  z-index: 1;
  cursor: pointer;
}

/* 没确认之前，正文区锁着：淡下去、点不动、也 Tab 不进去（inert 管焦点） */
.is-locked {
  opacity: .45;
  pointer-events: none;   /* inert 的兜底，老浏览器也点不动 */
}
.lock-hint {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--ink-3);
}

/* 开了「减少动效」就别让人等 2.5 秒爬行，也别震 */
@media (prefers-reduced-motion: reduce) {
  .hold-ring-fg,
  .hold-btn.is-holding .hold-ring-fg { transition: none; }
  .hold-btn.is-shaking { animation: none; }
}

.submit-form {
  max-width: var(--measure);
  margin-bottom: var(--sp-7);
}

/* 投稿写的是散文，正文框用正文字体，不用等宽字体 */
.submit-form textarea {
  font-family: var(--font-sans);
  line-height: 1.8;
}

/* 字段标签里的"（必填）"这类小字 */
.field > span em {
  font-style: normal;
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

/* 蜜罐：正常人看不见，机器人会老老实实填上 */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* 「可以写 / 不要写」两栏 */
.rules {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-5);
}

.rules h3 {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: 650;
  color: var(--ink);
}

.rules ul {
  margin: 0;
  padding-left: 1.2em;
  font-size: var(--fs-sm);
  line-height: 1.8;
  color: var(--ink-2);
}
.rules li { margin-bottom: var(--sp-2); }

.rules-note {
  margin: var(--sp-5) 0 0;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm);
  line-height: 1.8;
  color: var(--ink-2);
}

/* 下拉框。和 .field 里的输入框用同一套外观 */
.field select {
  width: 100%;
  padding: .55rem .75rem;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.field select:focus-visible {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

/* =========================================================
   后台（admin.html）
   ========================================================= */

.panel-box {
  max-width: 30rem;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.note-small {
  margin: var(--sp-4) 0 0;
  font-size: var(--fs-xs);
  line-height: 1.7;
  color: var(--ink-3);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
}

.btn {
  display: inline-block;
  padding: .5rem 1rem;
  font: inherit;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s ease, opacity .15s ease;
}
.btn:hover { border-color: var(--ink); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

.btn--primary {
  color: var(--on-fill);
  background: var(--fill);
  border-color: var(--fill);
}
.btn--primary:hover { opacity: .85; }

/* ---- 提交按钮的三段变化 ----
   点下去：文字淡出 → 按钮收成圆 → 中间转圈；
   请求回来后：变绿、画出对勾；停一下再展开回原样。
   宽度是行内样式给的（auto 的宽度没法过渡，得先量出来钉死，
   再由脚本换成一个具体值），这里负责圆角和配色的过渡。 */

.submit-morph {
  position: relative;
  overflow: hidden;
  /* .btn 原来的 transition 里没这些，所以整条重写一遍 */
  transition: width .3s ease-in-out,
              border-radius .3s ease-in-out,
              background .25s ease,
              border-color .25s ease,
              color .25s ease,
              opacity .15s ease;
}
/* 加载中 / 出结果时别被 .btn[disabled] 的 .5 透明度压暗。
   这会儿按钮已经缩成正方形了，圆角跟上补到 50%，才是个正圆。 */
.submit-morph.is-loading,
.submit-morph.is-ok,
.submit-morph.is-bad {
  opacity: 1;
  border-radius: 50%;
}
/* 展开那 320ms 里 disabled 还没摘（防连点），得单独顶住透明度，
   否则按钮会在展开途中半透明。这时圆角已经该往回收了，所以不并进上面那组。 */
.submit-morph.is-restoring { opacity: 1; }

.sm-text {
  /* 收缩时按钮宽度一路掉到 40px 出头，这四个字要是不锁住就会换行 ——
     一个字一行，把按钮活活撑成一根竖条。锁住，让 overflow 去裁。 */
  white-space: nowrap;
  transition: opacity .15s ease;
}
.submit-morph.is-loading .sm-text,
.submit-morph.is-ok .sm-text,
.submit-morph.is-bad .sm-text { opacity: 0; }

/* 图标叠在正中间。用 inset + margin:auto 归位，而不是 translate ——
   把 transform 空出来给旋转动画用。 */
.sm-icon {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 1.25rem;
  height: 1.25rem;
  opacity: 0;
}

.sm-spinner circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linecap: round;
  /* pathLength="100"，所以这就是「70 的线 + 30 的空档」 */
  stroke-dasharray: 70 30;
}
@keyframes sm-spin { to { transform: rotate(360deg); } }
.submit-morph.is-loading .sm-spinner {
  opacity: 1;
  animation: sm-spin .8s linear infinite;
}

/* 对勾和叉都是「藏起来，等结果出来再画出去」 */
.sm-check path,
.sm-cross path {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* 给 31 不给 30：正好相等时首尾会差一道亚像素的缝，跟圆环那儿一个道理 */
  stroke-dasharray: 31;
  stroke-dashoffset: 31;
  transition: stroke-dashoffset .35s ease .08s;
}
.submit-morph.is-ok .sm-check { opacity: 1; }
.submit-morph.is-ok .sm-check path { stroke-dashoffset: 0; }
.submit-morph.is-bad .sm-cross { opacity: 1; }
.submit-morph.is-bad .sm-cross path { stroke-dashoffset: 0; }

/* 成功绿、失败红。这是全站仅有的两个非黑白颜色，只用在这个按钮上 */
.submit-morph.is-ok {
  color: #fff;
  background: #37b24d;
  border-color: #37b24d;
}
.submit-morph.is-bad {
  color: #fff;
  background: #e5484d;
  border-color: #e5484d;
}

/* 开了「减少动效」就不转不画，直接出结果 */
@media (prefers-reduced-motion: reduce) {
  .submit-morph.is-loading .sm-spinner { animation: none; }
  .sm-check path,
  .sm-cross path { transition: none; }
}

.btn--danger { border-color: var(--ink); }

.linkish {
  padding: 0;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  background: none;
  border: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.linkish:hover { color: var(--ink); }
.linkish[disabled] { opacity: .45; cursor: not-allowed; }

.field {
  display: block;
  margin-bottom: var(--sp-4);
}
.field > span {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.field input,
.field textarea {
  width: 100%;
  padding: .55rem .75rem;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.field textarea {
  font-family: var(--font-mono);
  line-height: 1.75;
  resize: vertical;
}
.field input:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}
.field input::placeholder,
.field textarea::placeholder { color: var(--ink-3); }

.status {
  min-height: 1.6em;
  margin: var(--sp-4) 0 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.status[data-kind="error"] {
  padding-left: var(--sp-3);
  border-left: 2px solid var(--ink);
  color: var(--ink);
  font-weight: 600;
}
.status[data-kind="ok"] {
  padding-left: var(--sp-3);
  border-left: 2px solid var(--line-strong);
}

/* ---- 文章列表 ---- */

.admin-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  padding-bottom: var(--sp-5);
  border-bottom: 1px solid var(--line);
}

.admin-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.admin-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--line);
}

.admin-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-4);
  min-width: 0;
}
.admin-item time {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}
.admin-item strong { font-weight: 600; }
.admin-item code {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

.admin-actions { display: flex; gap: var(--sp-4); }

.admin-empty {
  display: block !important;
  padding: var(--sp-6) 0;
  color: var(--ink-3);
  text-align: center;
}

/* ---- 投稿箱里的每一条 ---- */

/* 列表项默认是横排（日期 | 标题 | 操作），
   投稿要竖着堆，所以这一条单独改回块级 */
.admin-list li.sub-item {
  display: block;
  padding: var(--sp-5) 0;
}

.sub-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-4);
  margin-bottom: var(--sp-3);
}
.sub-head time {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}
.sub-head strong { font-weight: 600; }

/* 投稿正文。是纯文本，原样显示，不解析任何标签。
   太长的话内部滚动，免得一条就把整页顶下去。 */
.sub-body {
  max-height: 20rem;
  margin: 0 0 var(--sp-3);
  padding: var(--sp-4);
  overflow-y: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.75;
  white-space: pre-wrap;
  word-break: break-word;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.sub-contact {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

/* ---- 投稿箱里那几样小标记 ---- */

/* 已发表的整条变灰，一眼看出处理过了 */
.sub-item--done { opacity: .62; }
.sub-item--done .sub-body { max-height: 8rem; }

.sub-cat {
  padding: 0 .4rem;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.sub-author {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}

.sub-done {
  padding: 0 .4rem;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--on-fill);
  background: var(--fill);
  border-radius: var(--radius);
}

/* 可视化写的投稿要按正常排版渲染。
   默认那套是给 <pre> 用的（white-space: pre-wrap），
   套在 HTML 上会把每个换行都留成可见的空白。 */
.sub-body--rich {
  font-family: var(--font-sans);
  white-space: normal;
}
.sub-body--rich p { margin: 0 0 .6em; }
.sub-body--rich p:last-child { margin-bottom: 0; }
.sub-body--rich h2,
.sub-body--rich h3 { margin: .8em 0 .4em; font-size: 1.05em; }
.sub-body--rich ul,
.sub-body--rich ol { margin: 0 0 .6em; padding-left: 1.4em; }
.sub-body--rich blockquote {
  margin: 0 0 .6em;
  padding-left: var(--sp-4);
  border-left: 2px solid var(--line-strong);
}
.sub-body--rich table {
  width: 100%;
  margin: 0 0 .6em;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}
.sub-body--rich th,
.sub-body--rich td {
  padding: .3rem .5rem;
  border-bottom: 1px solid var(--line);
  text-align: left;
}
.sub-body--rich code {
  font-family: var(--font-mono);
  font-size: .875em;
}
.sub-body--rich pre {
  margin: 0 0 .6em;
  overflow-x: auto;
}

/* ---- 编辑器 ---- */

.editor { padding-top: var(--sp-6); }
.editor h2 {
  margin: 0 0 var(--sp-5);
  font-size: var(--fs-h2);
  font-weight: 650;
}

.editor-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-5);
}

.cheatsheet {
  margin-top: var(--sp-2);
  padding: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.cheatsheet summary { cursor: pointer; }
.cheatsheet ul { margin: var(--sp-3) 0 0; padding-left: 1.3em; }
.cheatsheet li { margin-bottom: var(--sp-2); }
.cheatsheet code {
  font-family: var(--font-mono);
  font-size: .875em;
  padding: .1em .35em;
  border: 1px solid var(--line);
  border-radius: 4px;
}

/* =========================================================
   正文编辑器（后台）
   ========================================================= */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px;
  padding: var(--sp-2);
  background: var(--paper);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
}

.toolbar button {
  min-width: 2rem;
  padding: .3rem .5rem;
  font: inherit;
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: var(--ink-2);
  background: none;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
}
.toolbar button:hover { color: var(--ink); border-color: var(--line-strong); }
.toolbar button:active { transform: translateY(1px); }
.toolbar button[disabled] { opacity: .4; cursor: not-allowed; }
.toolbar button.is-on {
  color: var(--on-fill);
  background: var(--fill);
  border-color: var(--fill);
}

.tb-sep {
  width: 1px;
  height: 1.1rem;
  margin: 0 var(--sp-2);
  background: var(--line);
}
.tb-spacer { flex: 1; }

/* 编辑区：长得像一张纸，和文章页的排版尽量一致 */
.rich-editor {
  min-height: 22rem;
  max-height: 42rem;
  padding: var(--sp-5);
  overflow-y: auto;
  font-size: var(--fs-body);
  line-height: 1.8;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0 0 var(--radius) var(--radius);
}
.rich-editor:focus-visible { outline: none; border-color: var(--ink); }
/* 空的时候显示一句提示。具体说什么由 editor.js 通过 --ph 传进来，
   没传就用这句兜底。投稿页会按选中的分类换不同的提示。 */
.rich-editor:empty::before {
  content: var(--ph, "在这里写正文……");
  color: var(--ink-3);
}

.rich-editor h2 { margin: 1.2em 0 .6em; font-size: 1.35rem; font-weight: 650; }
.rich-editor h3 { margin: 1.1em 0 .5em; font-size: 1.1rem; font-weight: 650; }
.rich-editor p { margin: 0 0 .9em; }
.rich-editor ul,
.rich-editor ol { margin: 0 0 .9em; padding-left: 1.4em; }
.rich-editor li { margin-bottom: .3em; }
.rich-editor blockquote {
  margin: 0 0 .9em;
  padding-left: var(--sp-5);
  border-left: 2px solid var(--line-strong);
  color: var(--ink-2);
}
.rich-editor code {
  padding: .1em .35em;
  font-family: var(--font-mono);
  font-size: .875em;
  border: 1px solid var(--line);
  border-radius: 4px;
}
.rich-editor pre {
  margin: 0 0 .9em;
  padding: var(--sp-4);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.7;
  border: 1px solid var(--line);
  border-left: 2px solid var(--ink);
  border-radius: var(--radius);
}
.rich-editor img {
  max-width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.rich-editor hr {
  margin: var(--sp-5) 0;
  border: 0;
  border-top: 1px solid var(--line);
}
.rich-editor a { text-decoration: underline; text-underline-offset: 3px; }

/* 编辑器里的表格。样式和 .article 里那套保持一字不差，
   不然"编辑时看到的"和"发布后看到的"会不一样。 */
.rich-editor table {
  width: 100%;
  margin: 0 0 .9em;
  border-collapse: collapse;
  font-size: .95rem;
}
.rich-editor th,
.rich-editor td {
  padding: var(--sp-2) var(--sp-3);
  text-align: left;
  border: 1px solid var(--line);
}
.rich-editor th { color: var(--ink-2); font-weight: 600; }

/* 插入表格的小面板 */
.tb-pop {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.tb-pop label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
}
.tb-pop input[type="number"] {
  width: 4.5rem;
  padding: .3rem .5rem;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* 标记模式下的输入框 */
.editor-source {
  min-height: 22rem;
  font-family: var(--font-mono);
  line-height: 1.75;
  border-radius: var(--radius);
}

/* =========================================================
   页脚
   ========================================================= */

.site-footer {
  margin-top: var(--sp-7);
  padding: var(--sp-5) 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-xs);
  color: var(--ink-3);
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--sp-3);
}
.site-footer p { margin: 0; }
.site-footer a:hover { color: var(--ink); }

/* =========================================================
   窄屏
   ========================================================= */

@media (max-width: 600px) {
  .intro { padding: var(--sp-6) 0 var(--sp-5); }

  /* 文章列表在手机上堆叠，日期移到标题上方 */
  .post-list a,
  .post-list .post-row {
    grid-template-columns: 1fr;
    gap: var(--sp-2);
  }
  .post-list li + li { margin-top: var(--sp-6); }

  .strip { flex-direction: column; align-items: flex-start; }

  /* 后台：编辑器的双栏塌成单栏，列表项竖排 */
  .editor-grid { grid-template-columns: 1fr; gap: 0; }

  /* 投稿页的「可以写 / 不要写」也塌成上下两栏 */
  .rules { grid-template-columns: 1fr; }
  .admin-list li { flex-direction: column; align-items: flex-start; }

  /* 工具栏和编辑区在手机上收一收 */
  .editor,
  .editor-source { min-height: 16rem; }
  .tb-sep { margin: 0 2px; }

  .site-header .wrap { min-height: 3.5rem; }
  .article pre { padding: var(--sp-4); }
}

/* =========================================================
   减少动效
   ========================================================= */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition: none !important;
    animation: none !important;
  }
}
