/* 1. 严格中日文字体区分 */
body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", sans-serif;
}

/* 深色模式背景由 <body> 上的 Tailwind 类 bg-[#fcfbf7] dark:bg-stone-900 负责，此处无需干预。
   ⚠️ 历史坑：这里曾写 `body.dark { background-color: transparent }`，但 dark 类加在 <html> 上
   （见 index.html 内联预加载脚本 + script.js 的 toggleTheme），body 上根本没有 dark 类，
   所以那条规则从未命中。千万不要"修正"成 html.dark body —— 一旦生效会把 body 背景设为透明，
   而 <html> 没有背景色，夜间模式会直接露出浏览器白底。故直接删除。 */

/* 专属日文：采用现代无衬线黑体（Gothic），与现代中文黑体风格完美契合 */
.font-japanese {
    font-family: 'Noto Sans JP', "Hiragino Sans", "Hiragino Kaku Gothic ProN", "ヒラギノ角ゴ ProN W3", "Meiryo", "メイリオ", sans-serif;
}

/* 2. 动态物理缩放核心控制变量 (卡片宽高与字体比例关联)
   --card-scale: 卡片物理尺寸系数（滑块直接控制）
   --font-scale: 字号系数（密度模式：缩小时按 0.6 次幂缩得比卡片慢，放大时与卡片等比）
   两者由 changeCardScale() 在 #cards-grid 上联动写入 */
#cards-grid {
    --card-scale: 1.0;
    --font-scale: 1.0;
    --card-width: 300px;
    --card-height: 380px;
}

/* 3. 物理自适应网格 (卡片缩小时，列数会自动增加) */
.adaptive-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--card-width), 1fr));
    gap: 1.5rem;
    width: 100%;
}

/* 专注模式：横向吸附卡片，中心卡清晰，两侧只轻微缩小和淡化。 */
.focus-carousel {
    display: flex;
    gap: 0;
    width: 100%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
    padding: 1.25rem max(1rem, calc((100% - var(--focus-card-width, min(78vw, 420px))) / 2));
    margin: -1.25rem 0;
}
.focus-carousel::-webkit-scrollbar { display: none; }
.focus-carousel > .perspective {
    flex: 0 0 var(--focus-card-width, min(78vw, 420px));
    height: min(62vh, calc(460px * var(--card-scale, 1)));
    min-height: 340px;
    scroll-snap-align: center;
    opacity: .68;
    transition: opacity .25s ease;
}
.focus-carousel > .perspective.is-focused { opacity: 1; }
.focus-carousel > .perspective .card-inner {
    scale: .92;
    transition: transform .5s cubic-bezier(.34, 1.12, .64, 1), scale .25s ease;
}
.focus-carousel > .perspective.is-focused .card-inner { scale: 1; }
@media (prefers-reduced-motion: reduce) {
    .focus-carousel { scroll-behavior: auto; }
    .focus-carousel > .perspective,
    .focus-carousel > .perspective .card-inner { transition: none; }
}

/* 3b. 列表模式：单列，宽度固定 448px（窗口更窄时自动收到窗口宽）。
   宽度刻意不再跟滑块联动：列表横向本来就受窗口限制，窗口窄时滑块的上半段会完全无效，
   看起来像"框不动、只有按钮在动"。滑块在列表模式下改为控制纵向密度（见下面 .list-row-*）。 */
.list-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
    width: 100%;
    max-width: 28rem;
    margin-left: auto;
    margin-right: auto;
}

/* 3c. 列表模式的纵向密度：滑块（--card-scale / --font-scale）越小，行越矮越密。
   --font-scale 由 changeCardScale() 写入：缩小时按 0.6 次幂缩得比卡片慢，放大时等比。 */
.list-grid .list-row-main {
    padding-top: calc(0.75rem * var(--card-scale, 1.0));
    padding-bottom: calc(0.75rem * var(--card-scale, 1.0));
}

.list-grid .list-row-word {
    font-size: calc(1rem * var(--font-scale, 1.0));
}

.list-grid .list-expand-area {
    padding-top: calc(0.875rem * var(--card-scale, 1.0));
    padding-bottom: calc(0.875rem * var(--card-scale, 1.0));
}

/* ==========================================
   3d. 卡片拖拽排序（仅标签筛选态启用）
   没有手柄：长按卡片任意位置 300ms 即可起拖，提示条负责说明这件事。
   ========================================== */

/* 跟着指针走的克隆：fixed 挂在 body 上。pointer-events:none 是关键——它让
   elementFromPoint 直接穿透到底下的卡片，判断落点不用维护任何坐标偏移表。 */
.drag-ghost {
    pointer-events: none;
    z-index: 999;
    opacity: .97;
    border-radius: 1rem;
    box-shadow: 0 18px 38px rgba(28, 25, 23, .26);
    will-change: transform;
    cursor: grabbing;
}

/* 松手后克隆滑回占位处，同时把"浮起"的影子收掉 */
.drag-ghost-landing {
    opacity: 1;
    box-shadow: 0 4px 12px rgba(28, 25, 23, .12);
}

/* 拖动中的占位：保留原尺寸供其它卡片让位，但隐藏原卡片，形成空白位置。 */
.drag-placeholder {
    opacity: 0;
    border-radius: 0.75rem;
}

/* 顶部标签整理模式：标签胶囊做错拍摆动，外层包装保留 FLIP 位移动画。 */
.tag-sort-item { display: inline-flex; flex: none; -webkit-touch-callout: none; }
.tag-wiggle-group { position: relative; display: inline-flex; flex: none; }
.tag-edit-badge {
    display: none;
    position: absolute;
    z-index: 2;
    top: -5px;
    right: -5px;
    width: 18px;
    height: 18px;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 9999px;
    color: #28735c;
    background: rgba(5, 150, 105, .09);
    box-shadow: none;
    cursor: pointer;
}
.dark .tag-edit-badge { color: #86efac; background: rgba(52, 211, 153, .12); }
.tag-edit-badge:hover { background: rgba(5, 150, 105, .16); color: #047857; }
.dark .tag-edit-badge:hover { background: rgba(52, 211, 153, .2); color: #a7f3d0; }
.tag-edit-badge:focus-visible { outline: 2px solid #10b981; outline-offset: 2px; }
body.tag-organize-mode #global-tags-filter { column-gap: 1rem; row-gap: 1rem; }
body.tag-organize-mode .tag-edit-badge { display: flex; }
body.tag-organize-mode .tag-wiggle-group > [data-tag-chip] {
    background-color: rgba(5, 150, 105, .055);
    color: #28735c;
}
.dark body.tag-organize-mode .tag-wiggle-group > [data-tag-chip] {
    background-color: rgba(52, 211, 153, .075);
    color: #86efac;
}
body.tag-organize-mode #tag-organize-hint { display: block; }

/* 被拿起的标签克隆跟随指针；原位置保留透明占位。 */
.tag-drag-ghost {
    pointer-events: none;
    z-index: 1000;
    opacity: .97;
    box-shadow: 0 12px 28px rgba(28, 25, 23, .22);
    border-radius: 9999px;
    will-change: transform;
    cursor: grabbing;
}
.tag-drag-landing {
    opacity: 1;
    box-shadow: 0 3px 10px rgba(28, 25, 23, .12);
}
.tag-drag-placeholder { opacity: 0 !important; }
body.tag-dragging,
body.tag-dragging * {
    cursor: grabbing !important;
    user-select: none;
    -webkit-user-select: none;
}
.tag-rename-inline {
    width: 8rem;
    max-width: 60vw;
    padding: .375rem .75rem;
    border: 1px solid rgba(5, 150, 105, .45);
    border-radius: .5rem;
    outline: none;
    color: #065f46;
    background: #fff;
    font-size: .75rem;
    font-weight: 700;
}
.dark .tag-rename-inline { color: #a7f3d0; background: #1c1917; }

/* 拖到哪都显示抓手光标，避免拖拽过程中光标乱跳 */
body.card-dragging,
body.card-dragging * {
    cursor: grabbing !important;
    user-select: none;
}

/* 长按候选阶段就阻止浏览器开始选中文字；只在标签筛选允许拖动卡片时启用。 */
body.card-drag-pending,
body.card-drag-pending * {
    user-select: none;
    -webkit-user-select: none;
}

/* 长按起拖的副作用：系统可能弹"选择/拷贝"菜单或开始选文字，把拖拽打断。
   触屏设备上直接禁掉（桌面端保留选中文字的能力，方便复制单词）。 */
.drag-enabled [data-card-id] {
    -webkit-touch-callout: none;
}
@media (hover: none) {
    .drag-enabled [data-card-id] {
        -webkit-user-select: none;
        user-select: none;
    }
}

/* 3D 卡片翻转容器高度受变量控制 */
.perspective {
    perspective: 1000px;
    height: var(--card-height) !important;
    transition: none;
}
/* 屏外卡片跳过布局与绘制计算，长列表滚动更流畅；
   contain-intrinsic-size 用卡片实际高度作占位估算，避免滚动条跳动 */
.adaptive-grid > .perspective {
    content-visibility: auto;
    contain-intrinsic-size: auto var(--card-height, 380px);
}
.card-inner {
    /* 翻面手感：0.5s + 缓出为主、过冲极轻的曲线。
       原先的纯 rotateY + Material 标准曲线首尾都平，读起来像"一块板子被匀速扳过去"。
       过冲(第二个控制点 y)只负责"弹"，长尾缓出(第三、四个控制点)负责"柔"——两者可拆：
       过冲调大会让注意力被回弹吸走(刷词时很烦)，故压到 1.12(约 1° 过冲，几乎察觉不到)，
       柔和感靠尾段缓出保留。
       调参：0.5s 是时长；1.12 是过冲量：1.0=完全不过冲，1.2 略弹，1.35 明显弹(已嫌吵)。
       想彻底无回弹但保留柔和：cubic-bezier(0.32, 0.72, 0, 1)。 */
    transition: transform 0.5s cubic-bezier(0.34, 1.12, 0.64, 1);
    transform-style: preserve-3d;
    -webkit-transform-style: preserve-3d;
}
.card-inner.is-flipped {
    transform: rotateY(180deg);
}
.card-front, .card-back {
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}
.card-front {
    transform: rotateY(0deg);
}
.card-back {
    transform: rotateY(180deg);
}

/* 4. 优雅的 HTML ruby 假名微调，确保假名在头顶完美对齐且永不遮挡 */
ruby {
    ruby-position: over;
    ruby-align: center;
    line-height: 1.8; /* 增大行高，为头上假名腾出充足的纵向空间 */
}
rt {
    font-family: 'Noto Sans JP', sans-serif;
    font-size: 0.58em;
    letter-spacing: 0em;
    text-align: center;
    color: #8c7e6c; /* 优雅的灰褐色假名 (日间基础色) */
    padding-bottom: 0.1em;
    user-select: none;
}
.dark rt {
    color: #a8a29e; /* 夜间模式：使用 stone-400 暖灰，与日间模式的咖灰保持统一，显眼且不突兀 */
}

/* 5. 卡片背部内容防溢出、防切割的安全滚动层 */
.card-content-scroll {
    overflow-y: auto;
    max-height: 100%;
    padding-right: 4px;
}
/* 极致清爽的浅灰极细微型滚动条 */
.card-content-scroll::-webkit-scrollbar {
    width: 4px;
}
.card-content-scroll::-webkit-scrollbar-track {
    background: transparent;
}
.card-content-scroll::-webkit-scrollbar-thumb {
    background: #e5e3d7;
    border-radius: 4px;
}
.dark .card-content-scroll::-webkit-scrollbar-thumb {
    background: #44403c; /* 夜间卡片内部滚动条颜色 */
}

/* 自定义大背景滚动条 */
::-webkit-scrollbar {
    width: 6px;
}
::-webkit-scrollbar-track {
    background: #f5f4ef;
}
.dark ::-webkit-scrollbar-track {
    background: #1c1917; /* 夜间模式滚动条轨道 */
}
::-webkit-scrollbar-thumb {
    background: #d4cfc1;
    border-radius: 3px;
}
.dark ::-webkit-scrollbar-thumb {
    background: #44403c; /* 夜间模式滚动条滑块 */
}

/* 隐藏滚动条 */
.scrollbar-hide::-webkit-scrollbar {
    display: none;
}
.scrollbar-hide {
    -ms-overflow-style: none;
    scrollbar-width: none;
}

/* 标签栏横向滚动的边缘渐隐遮罩（提示两侧还有内容可滑）
   ⚠️ 这里不用 mask-image：带 mask 的元素会被提升为合成层，其中的文字在栅格化时
   会从亚像素抗锯齿(ClearType)降级为灰度抗锯齿，12px 粗体中文会明显发虚。
   改为在 #global-tags-wrapper 上用绝对定位的渐变覆盖层模拟同样的渐隐效果，
   覆盖层只压住边缘 28px、不参与文字渲染，标签文字保持锐利。
   （.tag-fade-* 三个类仍由 updateTagScrollFade() 打在标签容器上，作为状态标记——
     页面里的其它元素也可能引用，故保留不动。） */
.tag-fade-overlay {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 28px;
    pointer-events: none;
    z-index: 5;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.tag-fade-overlay.is-visible { opacity: 1; }
.tag-fade-overlay-left {
    left: 0;
    background: linear-gradient(to right, #fcfbf7, rgba(252, 251, 247, 0));
}
/* 渐隐停在标签栏右边缘 */
.tag-fade-overlay-right {
    right: 0;
    background: linear-gradient(to left, #fcfbf7, rgba(252, 251, 247, 0));
}
.dark .tag-fade-overlay-left {
    background: linear-gradient(to right, #1c1917, rgba(28, 25, 23, 0));
}
.dark .tag-fade-overlay-right {
    background: linear-gradient(to left, #1c1917, rgba(28, 25, 23, 0));
}

/* 卡片背面顶栏内嵌标签条：位于 BACK 字样同行，右端渐隐让超长标签列自然收尾。
   ⚠️ 同上，这里也不用 mask-image：标签是 10px 中文，被合成层降级后会明显发虚。
   改用挂在标签条自身的绝对定位渐变覆盖层——绝对定位的子元素已脱离文档流，
   不会参与 flex 布局（标签条是 flex 容器，伪元素若在流内会变成一个额外的 flex 项），
   所以布局零影响。渐变色取卡片背面底色：日间 #faf9f4、夜间 stone-900 (#1c1917)。 */
.tag-strip-inline {
    position: relative;
}
.tag-strip-inline::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 24px;
    pointer-events: none;
    background: linear-gradient(to right, rgba(250, 249, 244, 0), #faf9f4);
}
.dark .tag-strip-inline::after {
    background: linear-gradient(to right, rgba(28, 25, 23, 0), #1c1917);
}

/* 所有卡片内部的变量声明，它们会自动继承来自父级 #cards-grid 的等比缩放参数；
   字号 = 字号系数 × fit-to-card 单卡适配系数（溢出的卡片由 JS 逐级调小系数，
   卡片盒子尺寸与网格轨道完全不变，避免任何级联重排）。

   ⚠️ 正反两面各有独立的适配系数，切勿合并成一个：
   正面只展示单词，背面可能有读音+释义+长例句。若共用一个系数，一张背面例句很长的卡
   会把系数一路压到下限（0.55），正面那个孤零零的单词就被连带缩到别人一半大。
   --fit-front 仅由正面自身溢出决定；--fit-scale 仅由背面溢出决定。 */
.card-scale-box {
    /* 正面（单词面）专属 */
    --fit-front: 1.0;
    /* 背面（释义面）专属，背面内的例句等子元素也统一跟随它 */
    --fit-scale: 1.0;
    --card-pad: calc(1.25rem * var(--card-scale, 1.0));
    --fs-title: calc(1.875rem * var(--font-scale, 1.0) * var(--fit-front));
    --fs-sub: calc(1.375rem * var(--font-scale, 1.0) * var(--fit-scale));
    --fs-text: calc(0.875rem * var(--font-scale, 1.0) * var(--fit-scale));
    --fs-small: calc(0.75rem * var(--font-scale, 1.0) * var(--fit-front));
    --fs-tiny: calc(0.625rem * var(--font-scale, 1.0) * var(--fit-scale));
    --fs-tiny-front: calc(0.625rem * var(--font-scale, 1.0) * var(--fit-front));
    --spacing-gap: calc(0.75rem * var(--card-scale, 1.0));
    /* 卡片按压缩放过渡：盖过 .perspective 的 transition:none，让按压有回弹动画（iOS 无震动时的物理替补） */
    transition: transform 0.18s ease;
}

/* —— 卡片反馈：只保留触屏按下微沉，鼠标端无任何悬停/按压反馈 ——
   触屏：按下微沉 0.98，模拟手指把卡片压进纸面（iOS 无震动的物理替补）。
   鼠标：完全静止。曾依次试过并都被用户否决——
     ① 整卡位移（微抬 2px）：密集网格里鼠标扫过会「一张接一张浮起」，很吵；
     ② 悬停换边框色：用户觉得"多一个框反而烦"。
     故鼠标下仅靠 cursor:pointer + 点击后的翻面本身作为反馈。
   用 (hover/pointer) 门控触屏分支，避免 iOS 上 :hover 点完卡住不消失。

   ⚠️ 不要再给卡片加 box-shadow 做悬停反馈：
   .adaptive-grid > .perspective 上有 content-visibility:auto（隐含 paint 包含），
   会把溢出卡片边界的阴影裁掉，圆角处就会露出被切开的硬边阴影。 */

/* 触屏：按下微沉 */
@media (hover: none), (pointer: coarse) {
    .card-scale-box:active,
    .card-press:active {
        transform: scale(0.96);
    }
}

/* 鼠标端不做任何悬停反馈：用户试过「换边框色」后觉得多一个框反而烦，故全部去掉。
   鼠标下卡片保持完全静止，仅靠 cursor:pointer 与点击后的翻面本身作为反馈。
   ⚠️ 不要再尝试给卡片加 box-shadow / 位移 / 边框色做悬停态。 */

/* 正面内的小字（FRONT 标签、来源单词本徽章）跟随正面系数，
   不被背面的长例句连带缩小。背面内的同名小字仍用 --fit-scale。 */
.card-front {
    --fs-tiny: var(--fs-tiny-front);
}

/* Back to top button */
#back-to-top-btn {
    position: fixed;
    right: 1.5rem;
    bottom: 1.5rem;
    z-index: 50;
    width: 3rem;
    height: 3rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid #d6d3d1;
    border-radius: 9999px;
    background: rgba(255, 255, 255, 0.92);
    color: #44403c;
    box-shadow: 0 8px 20px rgba(68, 64, 60, 0.18);
    opacity: 0;
    visibility: hidden;
    transform: translateY(0.75rem);
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}
#back-to-top-btn.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}
#back-to-top-btn:hover {
    background: #f5f5f4;
    transform: translateY(-0.15rem);
}
.dark #back-to-top-btn {
    border-color: #57534e;
    background: rgba(41, 37, 36, 0.92);
    color: #e7e5e4;
}
.dark #back-to-top-btn:hover { background: #44403c; }

/* Floating shuffle button（叠在悬浮栈最上方：shuffle > flip > back-to-top） */
#shuffle-fab {
    position: fixed;
    right: 1.5rem;
    bottom: 8.5rem; /* flip(5rem) + 按钮高(3rem) + 间距(0.5rem) */
    z-index: 50;
    width: 3rem;
    height: 3rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid #d6d3d1;
    border-radius: 9999px;
    background: rgba(255, 255, 255, 0.92);
    color: #44403c;
    box-shadow: 0 8px 20px rgba(68, 64, 60, 0.18);
    opacity: 0;
    visibility: hidden;
    transform: translateY(0.75rem);
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}
#shuffle-fab.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}
#shuffle-fab:hover {
    background: #f5f5f4;
    transform: translateY(-0.15rem);
}
.dark #shuffle-fab {
    border-color: #57534e;
    background: rgba(41, 37, 36, 0.92);
    color: #e7e5e4;
}
.dark #shuffle-fab:hover { background: #44403c; }

/* Floating flip button（翻面/展开：平铺=全卡翻面，列表=全部展开收起，位于栈中间） */
#flip-fab {
    position: fixed;
    right: 1.5rem;
    bottom: 5rem; /* back-to-top(1.5rem) + 按钮高(3rem) + 间距(0.5rem) */
    z-index: 50;
    width: 3rem;
    height: 3rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid #d6d3d1;
    border-radius: 9999px;
    background: rgba(255, 255, 255, 0.92);
    color: #44403c;
    box-shadow: 0 8px 20px rgba(68, 64, 60, 0.18);
    opacity: 0;
    visibility: hidden;
    transform: translateY(0.75rem);
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}
#flip-fab.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}
#flip-fab:hover {
    background: #f5f5f4;
    transform: translateY(-0.15rem);
}
.dark #flip-fab {
    border-color: #57534e;
    background: rgba(41, 37, 36, 0.92);
    color: #e7e5e4;
}
.dark #flip-fab:hover { background: #44403c; }

@media (max-width: 640px) {
    #back-to-top-btn { right: 1rem; bottom: 1rem; }
    #flip-fab { right: 1rem; bottom: 4.5rem; }
    #shuffle-fab { right: 1rem; bottom: 8rem; }
}

/* One-click clear buttons for text inputs and textareas */
.input-clear-wrap {
    position: relative;
    width: 100%;
    min-width: 0;
}
.input-clear-wrap > input,
.input-clear-wrap > textarea {
    padding-right: 2.25rem !important;
}
/* 一键清空按钮：无底色浅灰小 ×，平时半透明常驻（余光可见、不抢戏），
   输入框聚焦或悬停时变清晰，hover 到按钮本身再加深提示可点 */
.input-clear-btn {
    position: absolute;
    right: 0.65rem;
    top: 50%;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    padding: 0;
    border: 0;
    border-radius: 9999px;
    background: transparent;
    color: #a8a29e;
    font-size: 0;
    line-height: 0;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-50%) scale(0.9);
    transition: opacity 0.15s ease, transform 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.input-clear-wrap.has-content .input-clear-btn,
.has-content .input-clear-inline {
    opacity: 0.45;
    pointer-events: auto;
    transform: translateY(-50%) scale(1);
}
.input-clear-wrap.has-content:hover .input-clear-btn,
.input-clear-wrap.has-content:focus-within .input-clear-btn,
.has-content:hover .input-clear-inline,
.has-content:focus-within .input-clear-inline {
    opacity: 1;
}
.input-clear-wrap > textarea + .input-clear-btn {
    top: 0.75rem;
    transform: scale(0.9);
}
.input-clear-wrap.has-content > textarea + .input-clear-btn {
    transform: scale(1);
}
.input-clear-btn svg { width: 0.75rem; height: 0.75rem; pointer-events: none; }
.input-clear-btn:hover { background: rgba(0, 0, 0, 0.06); color: #44403c; }
.dark .input-clear-btn { background: transparent; color: #78716c; }
.dark .input-clear-btn:hover { background: rgba(255, 255, 255, 0.08); color: #e7e5e4; }
.input-clear-inline {
    position: absolute;
    right: 4.7rem;
    top: 50%;
    z-index: 10;
}

#cards-grid[data-compact="true"] .card-scale-box {
    --card-pad: calc(0.9rem * var(--card-scale, 1.0));
    --spacing-gap: calc(0.45rem * var(--card-scale, 1.0));
}
#cards-grid[data-compact="true"] ruby {
    line-height: 1.55;
}

/* —— 防困小改动：标记「已掌握」成功时的浮层小动效 ——
   在点击处弹出一个「✓ 已掌握」徽标，弹性缩放入场 + 柔光，约 0.72s 后淡出并上浮。
   用 fixed 定位、脱离卡片重渲染，因此「复习中」视图下卡片消失也能稳定显示；
   在 iPhone 上（无网页震动）这层视觉奖励即物理震动的替补通道。 */
.mastered-pop {
    position: fixed;
    z-index: 999;
    pointer-events: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 7px 14px;
    border-radius: 9999px;
    /* 配色直接复用卡片右上角「已掌握」对勾按钮：浅绿底 + 绿字，无渐变，跟界面统一 */
    background: #ecfdf5;                 /* emerald-50，与卡片 mastered 按钮底色一致 */
    color: #059669;                      /* emerald-600，与卡片 mastered 对勾同色 */
    border: 1px solid rgba(5, 150, 105, 0.18);
    font-size: 15px;
    font-weight: 800;
    white-space: nowrap;
    box-shadow: 0 6px 16px -8px rgba(5, 150, 105, 0.35);
    transform: translate(-50%, -50%) scale(1);
    /* 注意：不再默认 opacity:0，避免「减弱动态效果」等抑制 CSS 动画的环境里浮层永久不可见。
       元素默认可见，animation 仅做弹入/上浮装饰；动画被禁时也能正常显示，由 setTimeout 兜底移除。 */
    animation: mastered-pop-anim 1.1s cubic-bezier(.2, .85, .25, 1) forwards;
}
.dark .mastered-pop {
    /* 深色模式复用卡片对勾按钮：emerald-900/35 深绿底 + emerald-400 绿字
       （夜间主色已与日间统一为 emerald，勿再写回 teal / #2dd4bf 冷青） */
    background: rgba(6, 78, 59, 0.35);
    color: #34d399;
    border: 1px solid rgba(45, 212, 191, 0.25);
    box-shadow: 0 6px 16px -8px rgba(0, 0, 0, 0.5);
}
.mastered-pop .mp-check {
    font-size: 18px;
    line-height: 1;
}
@keyframes mastered-pop-anim {
    0%   { transform: translate(-50%, -50%) scale(0.3);  opacity: 0; }
    18%  { transform: translate(-50%, -50%) scale(1.22); opacity: 1; }
    34%  { transform: translate(-50%, -50%) scale(1);    opacity: 1; }
    70%  { transform: translate(-50%, -64%) scale(1);    opacity: 1; }
    100% { transform: translate(-50%, -82%) scale(0.96); opacity: 0; }
}

