/* ================================================================================
   云窗拾锦 · 互动游戏公共外观  games.css   v1.0  (2026-09-17)
   --------------------------------------------------------------------------------
   只做三件事，**不重复定义游戏自己的外观**（那仍在 deck.css 第 9 节）：
   ① 大屏适配：教室一体机 / 触摸白板 / 投影 —— 命中区够大、不依赖鼠标悬停、按下即反馈
   ② 游戏外壳：「重来一次」按钮 + 答对整块高亮
   ③ 生成结构与手写结构之间的等价间距（保证换写法后版式不变）

   大屏四条铁律（后面所有游戏都遵守）：
   - 可点元素 **≥ 88px 高**（约 4.4cm@100 吋屏，手指和书写笔都点得中）
   - **不靠 :hover 提示可点** —— 白板手指悬空不触发 hover，提示必须常驻
   - **按下要有反馈**（:active）；误触必须能退回（重来一次）
   - 反馈变化要**全班可见**（整块动/变色），不能只靠一行小字
   ================================================================================ */

:root{
  --hit:88px;        /* 主命中区：卡片 / 选项 / 字块 */
  --hit-sm:64px;     /* 次要按钮：重来一次 */
}

/* 触摸：关掉双击缩放与长按选中（白板上极容易误触发） */
.stage,.game,.game *{touch-action:manipulation}
.game *{-webkit-tap-highlight-color:transparent;user-select:none}

.game{position:relative}

/* ① 命中区撑到 88px，内容居中 */
.game .pc,.game .opt{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--hit)}
.game .tile{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:var(--hit);min-width:var(--hit)}

/* ② 可点提示常驻：一道立体底边（不依赖 hover；按下才压扁） */
.game .pc,.game .opt{box-shadow:0 3px 0 rgba(184,137,59,.32)}
.game .pc:active,.game .opt:active,.game .tile:active{
  transform:translateY(3px);box-shadow:0 0 0 rgba(0,0,0,0)}
.game .pc.done,.game .opt.right{box-shadow:none}

/* ③ 答对 / 全清：整块高亮一下（后排也要看出「对了」） */
.game.solved{animation:gpop .55s ease-out}
@keyframes gpop{0%{transform:scale(1)}34%{transform:scale(1.035)}100%{transform:scale(1)}}

/* ④ 生成结构与手写结构的等价间距（换写法后版式不变） */
.game>.g-feedback{margin-top:.5rem}

/* ⑤ 「重来一次」：放在反馈行右侧，不额外占版面高度（大屏误触必须能退回） */
.game .g-feedback{padding-right:13rem}
.game>.g-reset{
  position:absolute;right:0;bottom:0;height:var(--hit-sm);min-width:11rem;padding:0 1.2rem;
  font-family:var(--serif);font-size:30px;font-weight:600;color:var(--aux);
  background:var(--card);border:1.5px solid var(--mist);border-radius:14px;cursor:pointer;
  box-shadow:0 3px 0 rgba(184,137,59,.20);
  transition:border-color .16s,color .16s}
.game>.g-reset:active{border-color:var(--brand);color:var(--brand-deep);transform:translateY(3px);box-shadow:none}


/* ================================================================================
   二、配对皮肤（game-match.js 的 data-skin）
   --------------------------------------------------------------------------------
   判定只有一份（在 deck.js），这里只管「看起来像什么、答对时发生什么」。
   换皮肤不动判分，所以验收结论与随堂统计不会因为换皮而漂移。
   ================================================================================ */

/* ---------------- 皮肤 cards：两列分组卡片 ----------------
   老师原话：「三个与三个配对，竟然排成一行，也是醉了」。
   原因：两列只有 63px 间隔、各自居中、没有任何"分组"的视觉边界。
   修法：每列做成一张独立的白卡组（列标题 + 淡底 + 圆角），两组之间留出明显空档。 */
.mcards{display:grid;grid-template-columns:1fr 1fr;gap:0 5rem;width:100%;align-items:start}
.mcards .pcol{background:rgba(255,255,255,.62);border:1.5px dashed var(--mist);
  border-radius:var(--r-lg);padding:1rem 1.5rem 1.5rem}
.mcards .pcol h5{font-family:var(--serif);font-size:28px;font-weight:700;letter-spacing:.2em;
  color:var(--aux);text-align:center;margin-bottom:.9rem}
.mcards .pchips{display:flex;flex-wrap:wrap;gap:.9rem;justify-content:center}


/* ---------------- 皮肤 line：连线板 ----------------
   左列竖排、右列竖排，中间留一条走廊给线走。
   这么排，物理上就不可能"排成一行"；右列又是错排过的，线会自然交叉。 */
.mline{width:100%;--ml-road:16rem;--ml-rise:2.2rem;--ml-headgap:.34rem;--ml-rowgap:.72rem}
.ml-head{display:grid;grid-template-columns:1fr 1fr;column-gap:var(--ml-road);
  margin-bottom:var(--ml-headgap);padding:0 var(--ml-rise)}
.ml-head h5{font-family:var(--serif);font-size:28px;font-weight:700;letter-spacing:.2em;color:var(--aux)}
.ml-head h5:first-child{text-align:right}
.ml-head h5:last-child{text-align:left}

/* 行距刻意压紧：四行卡片时它是唯一能省的高度（卡片本身有 88px 命中区硬底线不许动）。
   而且连线板本来就该紧凑 —— 线越短，一眼扫完越省事。
   两个间距走令牌，是为了"某一页内容偏高"时能整页收一点空白（不许缩字号）。 */
.ml-cols{position:relative;display:grid;grid-template-columns:1fr 1fr;column-gap:var(--ml-road)}
.mcol{display:flex;flex-direction:column;gap:var(--ml-rowgap)}
.mcol.ml{align-items:flex-end;padding-right:var(--ml-rise)}
.mcol.mr{align-items:flex-start;padding-left:var(--ml-rise)}
.mline .pc{position:relative;box-sizing:border-box;
  min-width:min(15rem,100%)}   /* 放进双栏窄栏时自动收窄，绝不撑破栏宽 */

/* 两侧各一个圆点 —— 线就钉在这里，不会看着像"飘着的线" */
.mline .pc .dot{position:absolute;top:50%;width:26px;height:26px;border-radius:50%;
  background:#fff;border:4px solid var(--mist);transform:translateY(-50%);
  transition:background .18s,border-color .18s,transform .18s}
.mcol.ml .dot{right:-2.4rem}
.mcol.mr .dot{left:-2.4rem}
.mline .pc.sel .dot{border-color:var(--gold);background:var(--gold-soft);
  transform:translateY(-50%) scale(1.4)}
.mline .pc.done .dot{background:var(--pine);border-color:var(--pine)}

/* 覆盖在整块板上的画布。不设 viewBox → 内部单位就是 CSS 像素，坐标可直接用 */
.ml-svg{position:absolute;left:0;top:0;width:100%;height:100%;overflow:visible;pointer-events:none}
.ml-path{fill:none;stroke:var(--pine);stroke-width:7;stroke-linecap:round;
  stroke-dasharray:100;stroke-dashoffset:100;   /* pathLength=100 把总长归一化，不用算真实长度 */
  animation:mlDraw .55s cubic-bezier(.45,0,.25,1) forwards}
@keyframes mlDraw{to{stroke-dashoffset:0}}
.ml-cap{fill:var(--pine);opacity:0;animation:mlCap .3s .42s forwards}
@keyframes mlCap{to{opacity:1}}

/* ---- 手指画线（match-line.js v2.0）----
   ① 板子自己吃掉触摸手势：不然在触摸屏上"拖着画线"会变成"拖着页面滚"
   ② .ml-live  = 跟着指尖走的那条"活线"（还没判定）
      .ml-free  = 判定成功后转正的手绘线（本人画的轨迹，永久留在板上）
   ③ .near     = 指尖掠过的对方卡片要立刻亮起来 —— 大屏上手指会挡住目标，
      没有这层反馈学生不知道自己指到哪了 */
.mline .ml-cols{touch-action:none;user-select:none;-webkit-user-select:none}
.ml-live{fill:none;stroke:var(--brand);stroke-width:7;stroke-linecap:round;
  stroke-linejoin:round;opacity:.9}
.ml-live.ml-bad{stroke:var(--clay)}
.ml-live.ml-miss{opacity:0;transition:opacity .28s}
.ml-free{stroke-dasharray:none;animation:none}
.mline .pc.near{outline:4px solid var(--brand-soft);outline-offset:5px}
.mline .pc.near .dot{border-color:var(--brand);background:var(--brand-soft);
  transform:translateY(-50%) scale(1.5)}


/* ---------------- 皮肤 apple / frog：摘苹果 · 青蛙吃虫 ----------------
   两者结构同构（上方物体 + 下方容器 + 飞入动画），共用 .mcatch 一套骨架，
   靠 .apple / .frog 两个主题类换皮。 */
.mcatch{width:100%}
.mstage{position:relative;width:100%;height:392px;margin-bottom:1.4rem}
.mscene{position:absolute;left:0;top:0;width:100%;height:100%;overflow:visible}
.mobjs{position:absolute;left:0;top:0;width:100%;height:100%}
/* 容器一排：竹筐 / 青蛙。必须显式写 flex —— 只靠 inline-flex 自然横排的话，
   间隙和对齐都跟着文字行走，换个字号就散。 */
.mbar{display:flex;flex-wrap:wrap;justify-content:center;align-items:flex-end;gap:2.8rem}

.mcatch .obj{position:absolute;transform:translate(-50%,-50%);padding:0;border:none}
.mcatch .target{position:relative;flex-direction:column;padding:1.1rem 1.8rem;min-width:min(15rem,100%);
  box-sizing:border-box}

/* 答对：物体沿抛物线飞进容器（中途微微上抬，才有"掉下来/被卷走"的感觉） */
.mcatch .obj.mw-fly{animation:mwFly .68s cubic-bezier(.42,-.16,.74,1) forwards;
  pointer-events:none;z-index:5}
@keyframes mwFly{
  0%  {transform:translate(-50%,-50%) scale(1)}
  50% {transform:translate(calc(-50% + var(--fx) * .48),calc(-50% + var(--fy) * .46 - 62px)) scale(1.08)}
  100%{transform:translate(calc(-50% + var(--fx)),calc(-50% + var(--fy))) scale(.4);opacity:.08}
}

/* 容器被填上：留一个答案文字 + 弹一下，后排也看得出"这个已经摘到了" */
.mcatch .target .got{position:absolute;right:.85rem;top:.5rem;font-family:var(--sans);
  font-size:26px;font-weight:700;color:var(--pine);opacity:0;transform:translateY(-6px);
  transition:opacity .3s .42s,transform .3s .42s}
.mcatch .target.filled{background:var(--pine-soft);border-color:var(--pine)}
.mcatch .target.filled .got{opacity:1;transform:translateY(0)}
.mcatch .target.eating{animation:mwEat .6s ease-out}
@keyframes mwEat{0%{transform:scale(1)}38%{transform:scale(1.09)}100%{transform:scale(1)}}

/* —— 主题 apple：苹果挂在树冠弧线上，摘下来落进竹筐 —— */
.mcatch .sc-grass{fill:#DCEBCF}
.mcatch .sc-trunk{fill:#A9793F}
.mcatch .sc-branch{fill:none;stroke:#A9793F;stroke-width:15;stroke-linecap:round}
/* 树冠分两层色：中间那团深一点，才有体积感（同色三个圆叠着会像一张纸片） */
.mcatch .sc-leaf{fill:#7BA767;opacity:.96}
.mcatch .sc-leaf.deep{fill:#6A9A56}
.mcatch .obj.apple{width:134px;height:134px;min-width:134px;height:134px;border-radius:50%;
  font-family:var(--sans);font-size:32px;font-weight:700;color:#fff;
  background:radial-gradient(circle at 34% 26%,#E08A78,#C8564B 58%,#A83E36);
  box-shadow:0 12px 22px rgba(150,50,40,.26),inset -10px -12px 22px rgba(0,0,0,.18)}
.mcatch .obj.apple .olabel{text-shadow:0 2px 6px rgba(0,0,0,.32)}
.mcatch .obj.apple::before{content:'';position:absolute;top:-13px;left:calc(50% - 4px);
  width:8px;height:20px;border-radius:4px;background:#7A5A33;transform:rotate(-10deg)}
.mcatch .obj.apple::after{content:'';position:absolute;top:-15px;left:calc(50% + 2px);
  width:30px;height:18px;background:#6E9C58;border-radius:100% 0 100% 0;transform:rotate(-16deg)}
.mcatch .target.basket{
  background:repeating-linear-gradient(96deg,#D6AC74 0 16px,#C2965C 16px 32px);
  border:3px solid #96703C;border-radius:10px 10px 22px 22px;color:#453014;
  box-shadow:0 8px 16px rgba(120,90,50,.22),inset 0 -10px 18px rgba(120,84,40,.20)}

/* —— 主题 frog：虫子飞在天上，被青蛙卷走 —— */
.mcatch.frog .sc-cloud{fill:#fff;opacity:.78}
.mcatch .sc-water{fill:#CFE3EF}
.mcatch .sc-pad{fill:#8FBF6E;opacity:.92}
.mcatch .obj.bug{width:128px;height:90px;min-width:128px;height:90px;
  border-radius:50% 50% 46% 46%/62% 62% 38% 38%;
  font-family:var(--sans);font-size:30px;font-weight:700;color:#204015;
  background:radial-gradient(circle at 36% 30%,#B6DC88,#7FB855 62%,#5B9038);
  box-shadow:0 10px 18px rgba(60,110,40,.24),inset -8px -10px 18px rgba(0,0,0,.14)}
.mcatch .obj.bug::before,.mcatch .obj.bug::after{content:'';position:absolute;top:20px;
  width:13px;height:13px;border-radius:50%;background:#26361C}
.mcatch .obj.bug::before{left:24px}
.mcatch .obj.bug::after{right:24px}
.mcatch .target.frog{
  background:radial-gradient(circle at 50% 22%,#96CB7C,#5F9E4A 62%,#417F33);
  border:3px solid #356B2A;border-radius:50% 50% 44% 44%;color:#fff;padding-top:1.3rem;
  box-shadow:0 10px 18px rgba(50,100,40,.26)}
.mcatch .target.frog .tlabel{text-shadow:0 2px 6px rgba(0,0,0,.3)}
.mcatch .target.frog::before,.mcatch .target.frog::after{
  content:'';position:absolute;top:-22px;width:46px;height:46px;border-radius:50%;
  background:radial-gradient(circle at 50% 56%,#1F2E1A 0 25%,#EFEFE4 26%);
  border:5px solid #4F9642}
/* 眼睛用百分比定位而不是固定 px —— 容器在双栏里会变窄，固定 px 会让两眼间距忽大忽小 */
.mcatch .target.frog::before{left:27%}
.mcatch .target.frog::after{right:27%}
.mcatch .target.frog .got{color:#1E4A15}

/* 深色页上：卡片组 / 主题容器统一提到浅底，避免"黑底黑字" */
.on-dark .mcards .pcol{background:rgba(255,255,255,.94);border-color:rgba(255,255,255,.5)}
.on-dark .mline .pc .dot{background:#fff}

