/* 生成物：由 tools/web/sync-prototype-css.mjs 从 docs/prototypes/2026-09-21-阳光玻璃忠实延展/states.css 逐字复制，勿手改。
   原型是唯一视觉真值；要改视觉先改原型，再跑 `node tools/web/sync-prototype-css.mjs .` 同步。 */
/* 状态原语 · 阳光玻璃（规格 docs/superpowers/specs/2026-09-23-发现页任务卡与全站加载态升级-design.md §4）
   冻结基准 baseline/ 受 SHA256 锁（scripts/check.mjs 第 50～61 行），两条新关键帧放在这里、不进 motion.css；
   本文件只引用基准已定义的 --b-*／--m-* 令牌，自有变量不带这两个前缀（scripts/check.mjs 第 63～84 行）。
   切页节奏：300ms 内不出等待态、旧页停留；超过 300ms 出骨架、至少停 400ms；顶栏 2px 光带在等待超过 100ms 时长出。 */

/* ── 关键帧 ── */
/* 页面退场：m-enter 的镜像，透明 1 → 0、上移 6px */
@keyframes m-exit {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(-6px); }
}
/* 骨架明度呼吸：只动透明度 */
@keyframes m-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .55; }
}

/* ── 忙碌转环：四分之三环，色取 currentColor；减弱动态下静止仍是四分之三环，不补整圈 ── */
.spin {
  display: inline-block;
  flex: none;
  width: var(--spin-size, 16px);
  height: var(--spin-size, 16px);
  border: 1.5px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  vertical-align: -0.125em;
  animation: m-spin var(--m-spin-t) linear infinite;
}

/* ── 行内加载态 <StatusLine> ── */
.status-line {
  --spin-size: 12px;
  display: flex;
  align-items: center;
  gap: var(--b-sp-2);
  margin: 0;
  color: var(--b-text-2);
  font-size: var(--b-fs-13);
  line-height: 1.5;
}

/* ── 错误文字与重试 <ErrorText>／<RetryBlock> ── */
.status-error {
  margin: 0;
  color: var(--b-danger);
  font-size: var(--b-fs-13);
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.retry-block {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--b-sp-3);
}
.retry-block.is-page {
  flex-direction: column;
  justify-content: center;
  min-height: 260px;
  padding: var(--b-sp-8) var(--b-sp-6);
  text-align: center;
}

/* ── 页级空态档 ── */
.empty-plate.is-page {
  flex-direction: column;
  justify-content: center;
  min-height: 260px;
  padding: var(--b-sp-8) var(--b-sp-6);
  text-align: center;
}

/* ── 事务按钮忙碌态：文字保留，前面嵌一枚转环 ── */
.btn.is-busy {
  --spin-size: 14px;
  gap: var(--b-sp-2);
  cursor: progress;
}
/* 与基准的旧忙碌态互斥：baseline styles.css 的 .btn[aria-busy="true"] 把文字设透明、另画居中 ::after 转环，
   page-interactions.css 在 .page-polish 里再设一次透明。不压掉的话，.is-busy 的文字与前置转环会随文字一起透明，
   只剩旧转环（主区、弹层、坞内），或与旧转环叠成两枚（顶栏）。选择器多带 [aria-busy] 以压过两处旧规则，不依赖加载顺序；
   忙碌按钮都同时禁用，文字色取禁用色。未挂 .is-busy、只写 aria-busy 的冻结页按钮仍是旧样式。 */
.btn.is-busy[aria-busy="true"],
.page-polish :is(main, .sheet, .dock) .btn.is-busy[aria-busy="true"] { color: var(--b-text-disabled); }
.btn.is-busy[aria-busy="true"]::after { content: none; }

/* ── 骨架 <Skeleton>：色块落在凹面色上，明度呼吸 ──
   两种色块：.skeleton-block 是块级，尺寸由自身或所在的真卡元素给；.skeleton-inline 不改 display，
   只把背景铺在透明占位字（或所在按钮）上，宽高随字形与真卡样式走、自身不写尺寸。 */
.skeleton-block,
.skeleton-inline {
  border-radius: var(--b-radius-chip);
  background: var(--b-bg-inset);
  animation: m-pulse 1.6s ease-in-out infinite;
}
.skeleton-block { display: block; }
.skeleton-inline { color: transparent; }
.skeleton-line { width: 100%; height: 12px; }
.skeleton-line.is-short { width: 40%; }
.skeleton-line.is-mid { width: 70%; }
.skeleton-title { width: 85%; height: 20px; }
.skeleton-button { width: 104px; height: 40px; border-radius: var(--b-radius-inner); }
.skeleton-panel { width: 100%; min-height: 160px; border-radius: var(--b-radius-inner); }
/* 网格骨架卡（任务、作品两种）沿用真卡的元素结构与类名，几何全由页面样式决定、与真卡相同，本文件不写卡的尺寸。
   骨架卡带 .is-skeleton、aria-hidden，不带真卡用于计数的标记（data-card-motion／data-work-card）；数真卡请用那两个标记或 :not(.is-skeleton)。 */
.card.is-skeleton { pointer-events: none; }
/* 任务卡骨架：.task-cover-frame／.task-card-body 里的 .task-card-top、.task-card-meta、.task-card-footer，
   包括 600px 以下「封面＋头部／事实行／页脚」三行、卡高由内容撑出的那一档
   （只让正文纵向排色块时，窄屏骨架卡 165px、真卡 239px，数据到齐第二张卡下跳 74px）。
   事实行与页脚放真卡同一套元素（截止行、金额＋单位＋分账行）撑出同样的行高，连字体度量带来的零头也一致；
   占位字透明，截止行与金额本身画成色块。头部四条色块纵向排开，矮于封面，不影响行高。 */
.extension-card.is-skeleton .task-card-top { display: flex; flex-direction: column; gap: var(--b-sp-2); }
.extension-card.is-skeleton .skeleton-text { color: transparent; }
.extension-card.is-skeleton .task-deadline { width: 120px; }
.extension-card.is-skeleton .task-money strong { width: 96px; }
/* 作品卡骨架：.works-grid 里的 .works-card，封面框 .works-cover 本身画成色块；标题 h2、完成时间 time、
   按钮 .btn 放真卡同一套元素与透明占位字（时间与按钮文字与真卡同格式），三档断点的排法、行高、按钮宽高都由 pages/works.css 给出。
   按钮不挂 .btn-ghost，免得它的底色与描边压过色块；描边宽度来自 .btn，与真卡相同。 */
.skeleton-table {
  display: grid;
  gap: var(--b-sp-4);
  padding: var(--b-sp-6);
  border: 1px solid var(--b-line);
  border-radius: var(--b-radius-card);
  background: var(--b-bg-card);
}
.skeleton-row {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: var(--b-sp-4);
}
.skeleton-row.is-head .skeleton-line { height: 10px; opacity: .7; }
.skeleton-article { display: grid; gap: var(--b-sp-6); }
.skeleton-columns {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--b-sp-6);
}
.skeleton-columns > div { display: grid; gap: var(--b-sp-3); }

/* ── 数据到齐后列表错峰入场：只用 backwards 填充，动画结束后不接管 transform（不压掉卡片悬停抬起） ── */
.m-stagger > * { animation: m-enter var(--m-smooth-t) var(--m-spring-smooth) backwards; }
.m-stagger > :nth-child(2) { animation-delay: 40ms; }
.m-stagger > :nth-child(3) { animation-delay: 80ms; }
.m-stagger > :nth-child(4) { animation-delay: 120ms; }
.m-stagger > :nth-child(5) { animation-delay: 160ms; }
.m-stagger > :nth-child(6) { animation-delay: 200ms; }
.m-stagger > :nth-child(7) { animation-delay: 240ms; }
.m-stagger > :nth-child(n + 8) { animation-delay: 280ms; }

/* ── 顶栏光带：挂在 .topbar 底缘，品牌黄，从左长出；结束时去掉动画、透明度过渡到 0 ── */
.route-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  height: 2px;
  background: var(--b-accent);
  transform-origin: left center;
  pointer-events: none;
  animation:
    m-fill var(--m-smooth-t) var(--m-spring-smooth) both,
    m-pulse 1.6s ease-in-out var(--m-smooth-t) infinite;
  transition: opacity var(--m-snappy-t) var(--m-spring-snappy);
}
.route-progress[data-phase="done"] { animation: none; opacity: 0; }

/* ── 页面交接（View Transitions）：只有 <main> 参与，顶栏与光场不闪。
   <main> 只在过渡进行中命名：常驻 view-transition-name 会让它成为 Backdrop Root，里面的玻璃不再模糊光场。 ── */
.topbar { view-transition-name: topbar; }
.lightfield { view-transition-name: lightfield; }
html:active-view-transition main#main { view-transition-name: page; }
::view-transition-group(topbar),
::view-transition-group(lightfield) { animation-duration: 0s; }
::view-transition-old(root),
::view-transition-new(root) { animation: none; }
::view-transition-old(page) { animation: m-exit var(--m-snappy-t) var(--m-spring-snappy) both; }
::view-transition-new(page) { animation: m-enter var(--m-smooth-t) var(--m-spring-smooth) both; }

@media (prefers-reduced-motion: reduce) {
  .spin, .skeleton-block, .skeleton-inline, .route-progress, .m-stagger > * { animation: none; }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}
