/* ============================================================
   DaiZ app mockup — SHARED PARTIAL.
   Loaded by both the marketing site (/) and the live demo (/demo/).
   Do not fork: edit here and both surfaces move together.

   Everything is scoped under .mock-phone, which declares its own token set
   (sourced from mobile/constants/colors.ts). Nothing here reads a host-page
   variable, so it drops cleanly into the demo's oklch design system.
   ============================================================ */

/* ── app mockup — 실제 앱(mobile/) 과 1:1 대응 ─────────────
   토큰 출처 constants/colors.ts / 레이아웃 출처 (tabs)/*.tsx        */
.mock-phone{
  --p:#88C9A1; --pd:#6BAF87; --p50:#E8F5EE; --p700:#3F7A57;
  --slate:#F8FAFC; --line:#F5F5F5; --n400:#A3A3A3; --n500:#737373; --n600:#525252; --n900:#171717;
  /* Inlined from the marketing site's :root so this partial stands alone on
     any host page (the demo runs an entirely different oklch palette). */
  --navy:#1A1A2E; --ease:cubic-bezier(.16,1,.3,1);
  width:375px; height:700px; flex:none;
  transform:scale(var(--s,1)); transform-origin:top left;
  border:10px solid #1F2937; border-radius:44px; background:var(--slate);
  box-shadow:0 30px 70px -30px color-mix(in srgb,var(--navy) 50%,transparent),
             0 0 0 2px rgba(255,255,255,.6) inset;
  overflow:hidden; position:relative; display:flex; flex-direction:column;
  font-size:13px; line-height:1.35;
}
.mock-phone .ic{width:1em;height:1em;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;flex:none}

/* 화면 */
.msc{position:absolute;inset:0;display:flex;flex-direction:column;
  animation:mfade .3s var(--ease)}
.msc[hidden]{display:none}
@keyframes mfade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.mbody{flex:1;overflow-y:auto;padding:14px 14px 84px;scrollbar-width:none}
.mbody::-webkit-scrollbar{display:none}

/* Home 헤더 — bg-primary-500 rounded-b-3xl */
.mtop{background:var(--p);padding:12px 14px 14px;border-radius:0 0 22px 22px;
  display:flex;align-items:center;gap:7px;flex:none;
  box-shadow:0 1px 3px rgba(0,0,0,.06)}
.mbiz{font-weight:700;font-size:15px;letter-spacing:-.02em;color:var(--n900);white-space:nowrap}
.mrule{flex:1;height:1.5px;background:#fff;border-radius:2px}
.mbrand{font-weight:700;font-size:15px;letter-spacing:-.04em;color:var(--n900)}
.mbrand i{font-style:normal;color:rgba(23,23,23,.4)}
.mlive{display:inline-flex;align-items:center;gap:4px;font-size:9px;font-weight:700;
  color:rgba(23,23,23,.7);letter-spacing:.02em}
.mlive i{width:6px;height:6px;border-radius:50%;background:#10B981;animation:mpulse 1.8s ease-in-out infinite}
@keyframes mpulse{0%,100%{opacity:1}50%{opacity:.3}}
.mrefresh{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  color:var(--n900);font-size:13px}

/* 섹션 라벨 — text-2xs bold neutral-400 uppercase tracking-widest */
.mlabel{font-size:9px;font-weight:700;color:var(--n400);text-transform:uppercase;
  letter-spacing:.12em;margin:14px 0 7px 4px}
.mbody>.mlabel:first-child{margin-top:2px}

/* 카드 */
.mcard{background:#fff;border-radius:20px;border:1px solid var(--line);overflow:hidden}
.mdiv{height:1px;background:var(--line);margin-left:48px}
.mdiv.inset{margin:0 14px}

/* Needs You 행 — AttentionRow */
.mrow{display:flex;align-items:center;gap:11px;width:100%;background:none;border:none;
  padding:12px 14px;font:inherit;text-align:left;cursor:pointer;color:inherit;
  transition:background .15s}
.mrow:hover{background:#FAFAFA}
.mrico{width:20px;display:grid;place-items:center;color:var(--n600);font-size:17px;flex:none}
.mrico.alt{color:var(--pd)}
.mrmain{flex:1;min-width:0}
.mrline{display:flex;align-items:baseline;gap:6px}
.mrline b{font-size:19px;font-weight:700;letter-spacing:-.02em;color:var(--p700)}
.mrline span{font-size:12px;font-weight:500;color:var(--n600)}
.mrmain em{display:block;font-style:normal;font-size:10px;color:var(--n400);margin-top:1px}
.mchev{color:#D4D4D4;font-size:14px}

/* CallFlowHero */
.mhero{display:block;width:100%;text-align:left;background:#fff;border:1px solid var(--line);
  border-radius:20px;padding:14px;margin-top:12px;font:inherit;color:inherit;cursor:pointer;
  transition:background .15s}
.mhero:hover{background:#FAFAFA}
.mhero .mlabel{margin:0 0 5px}
.mherorow{display:flex;align-items:flex-end;gap:8px}
.mherobig{font-size:34px;font-weight:700;letter-spacing:-.03em;line-height:1;color:var(--p700)}
.mherotxt{flex:1;font-size:11.5px;color:var(--n500);padding-bottom:3px}
.mflow{display:flex;align-items:center;gap:7px;margin-top:11px;padding-top:11px;
  border-top:1px solid var(--line)}
.mflow i{width:8px;height:8px;border-radius:50%;background:#2563EB;transition:background .2s}
.mflow em{font-style:normal;font-size:11px;font-weight:600;color:#2563EB;transition:color .2s}
.mflow.direct i,.mflow.direct em{background:#059669;color:#059669}
.mflow.direct i{background:#059669}
.mflow.off i{background:#E11D48}.mflow.off em{color:#E11D48}

/* MiniTile */
.mtiles{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}
.mtiles.two{grid-template-columns:repeat(2,1fr);margin-top:7px}
.mtile{background:#fff;border:1px solid var(--line);border-radius:15px;padding:9px 11px}
.mtile b{display:block;font-size:19px;font-weight:700;letter-spacing:-.02em;color:var(--p700)}
.mtile span{font-size:10px;font-weight:500;color:var(--n500)}

/* 화면 제목 (Calls / Messages) */
.mh{font-size:17px;font-weight:700;letter-spacing:-.02em;color:var(--n900);margin:2px 0 9px 2px}
.mh span{font-size:11px;font-weight:400;color:var(--n400);margin-left:5px}

/* 검색 */
.msearch{display:flex;align-items:center;gap:7px;background:#fff;border:1px solid #F0F0F0;
  border-radius:14px;padding:8px 11px;color:#A3A3A3;font-size:11.5px}
.msearch .ic{font-size:14px}

/* 세그먼트 필터 */
.mseg{display:flex;gap:3px;background:#fff;border:1px solid var(--line);border-radius:14px;
  padding:4px;margin-top:8px}
.mseg button{flex:1;background:none;border:none;font:inherit;font-size:10.5px;font-weight:600;
  color:var(--n600);padding:5px 2px;border-radius:10px;cursor:pointer;transition:all .18s}
.mseg button.on{background:var(--n900);color:#fff}

/* 리스트 */
.mlist{list-style:none;margin:9px 0 0;display:grid;gap:7px}
.mlist.flush{background:#fff;border:1px solid var(--line);border-radius:18px;
  overflow:hidden;gap:0}
.mitem{background:#fff;border:1px solid var(--line);border-radius:15px;overflow:hidden}
.mlist.flush .mitem{border:none;border-radius:0}
.mlist.flush .mitem+.mitem{border-top:1px solid var(--line)}
.mitem[hidden]{display:none}
.mitem-head{display:flex;align-items:center;gap:9px;width:100%;background:none;border:none;
  padding:11px;font:inherit;text-align:left;color:inherit;cursor:pointer;transition:background .15s}
.mitem-head:hover{background:#FAFAFA}
.mitem-head.conv{padding:12px}   /* 대화 행 — ConversationItem p-4 */
.mav{width:32px;height:32px;border-radius:11px;display:grid;place-items:center;font-size:15px;flex:none}
.mav.in{background:var(--p50);color:var(--pd)}
.mav.out{background:#EFF6FF;color:#3B82F6}
.mav.miss{background:#FEF2F2;color:#E53935}
.mit-main{flex:1;min-width:0}
.mit-main b{display:block;font-size:12px;font-weight:700;color:var(--n900);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.mit-sub{display:flex;align-items:center;gap:6px;margin-top:2px}
.mit-sub em{font-style:normal;font-size:10px;font-weight:500}
.mit-sub em.ok{color:var(--pd)}
.mit-sub em.warn{color:#D97706}
.mit-sub i{font-style:normal;font-size:10px;color:var(--n400)}
.mit-right{text-align:right;flex:none;display:flex;flex-direction:column;align-items:flex-end;gap:3px}
.mit-right i{font-style:normal;font-size:9.5px;color:var(--n400)}
.tag{font-style:normal;font-size:8.5px;font-weight:700;padding:1px 6px;border-radius:999px;
  letter-spacing:.03em}
.tag.ai{background:#ECFDF5;color:#059669}
.tag.staff{background:#F5F3FF;color:#7C3AED}

/* 전사 / 스레드 */
.mtranscript,.mthread{padding:0 11px 11px 52px;font-size:11px;line-height:1.5;
  animation:mfade .25s var(--ease)}
.mthread{padding-left:11px}
.mtranscript[hidden],.mthread[hidden]{display:none}
.tc,.bc{color:var(--n600);margin-bottom:5px}
.td,.bd{color:var(--p700);font-weight:600;margin-bottom:5px}
.bc,.bd{background:#F5F5F5;border-radius:12px;padding:6px 9px;display:inline-block;max-width:88%}
.bd{background:var(--p50);margin-left:12%}
.tbooked{display:flex;align-items:center;gap:5px;margin-top:7px;padding-top:7px;
  border-top:1px solid var(--line);font-size:10px;font-weight:700;color:#059669}
.tbooked.warn{color:#D97706}
.tbooked .ic{font-size:12px}
.bnote{font-size:9.5px;font-weight:700;color:#059669;margin-top:5px;letter-spacing:.02em}

/* 메시지 채널 아바타 */
.mch{width:32px;height:32px;border-radius:50%;display:grid;place-items:center;font-size:15px;flex:none;
  background:#E5E5E5;color:var(--n500)}
.mch.sms.unread{background:var(--p);color:#fff}
.mch.ig{background:#F3E8FF;color:#9333EA}
.mch.ig.unread{background:#E1306C;color:#fff}
.mch.fb{background:#EFF6FF;color:#2563EB}
.mch.fb.unread{background:#1877F2;color:#fff}
.mprev{display:block;font-size:10.5px;color:var(--n400);margin-top:1px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.unread-dot{font-style:normal;background:var(--p);color:#fff;font-size:9px;font-weight:700;
  width:16px;height:16px;border-radius:50%;display:grid;place-items:center}

/* Dial */
.dialpad{display:flex;flex-direction:column;padding-top:14px}
.mdialnum{margin-top:auto}   /* 아래로 밀어 붙인다 — 실제 앱과 동일 */
.mdialnum{text-align:center;font-size:30px;font-weight:700;letter-spacing:.04em;color:#0F172A;
  min-height:38px}
.mdialhint{text-align:center;font-size:10.5px;color:var(--n400);margin:2px 0 4px;min-height:14px}
.mkeys{display:grid;grid-template-columns:repeat(3,1fr);gap:14px 24px;
  width:100%;max-width:286px;margin:0 auto}
.mkeys button{aspect-ratio:1;border-radius:50%;background:#fff;border:1px solid #EDEFF2;font:inherit;
  font-size:24px;font-weight:600;color:#0F172A;cursor:pointer;display:grid;place-items:center;
  line-height:1;transition:transform .1s,background .15s;
  box-shadow:0 1px 2px rgba(0,0,0,.05)}
.mkeys button:active{background:#EFEFEF;transform:scale(.94)}
.mdialbar{display:flex;align-items:center;justify-content:center;gap:28px;margin-top:18px}
.mspacer{width:40px}
.mcallbtn{width:58px;height:58px;border-radius:50%;background:#22C55E;color:#fff;border:none;
  font-size:22px;display:grid;place-items:center;cursor:pointer;transition:transform .12s,opacity .2s;
  box-shadow:0 6px 16px -6px rgba(34,197,94,.8)}
.mcallbtn:hover{transform:scale(1.06)}
.mcallbtn:disabled{opacity:.35;box-shadow:none;transform:none;cursor:default}
.mback{width:40px;height:40px;background:none;border:none;color:var(--n400);font-size:20px;
  display:grid;place-items:center;cursor:pointer}

/* 통화 중 */
.minCall{position:absolute;inset:0;background:var(--slate);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:5px;padding:0 20px 84px;animation:mfade .3s var(--ease)}
.minCall[hidden]{display:none}
.mavatar{width:72px;height:72px;border-radius:50%;background:#E2E8F0;color:#64748B;
  display:grid;place-items:center;font-size:30px;margin-bottom:14px}
.mincall-num{font-size:20px;font-weight:700;letter-spacing:.05em;color:#0F172A}
.mincall-state{font-size:12px;font-weight:600;color:#F59E0B}
.mincall-state.live{color:var(--pd);font-variant-numeric:tabular-nums}
.mincall-ctrls{display:flex;gap:34px;margin:26px 0 22px}
.mincall-ctrls span{display:flex;flex-direction:column;align-items:center;gap:6px;
  font-size:10px;color:var(--n500)}
.mctrl{width:46px;height:46px;border-radius:50%;background:#fff;color:#64748B;font-size:18px;
  display:grid;place-items:center;box-shadow:0 1px 3px rgba(0,0,0,.06)}
.mendbtn{width:56px;height:56px;border-radius:50%;background:#EF4444;color:#fff;border:none;
  font-size:24px;display:grid;place-items:center;cursor:pointer;
  box-shadow:0 6px 16px -6px rgba(239,68,68,.8)}
.mendlbl{font-size:10px;color:var(--n400);margin-top:7px}

/* Settings */
.mtoggle-row{display:flex;align-items:center;gap:11px;padding:12px 14px}
.mtitle-sm{font-size:12px;font-weight:700;color:var(--n900)}
.msw{width:40px;height:23px;border-radius:999px;background:#E5E5E5;border:none;position:relative;
  cursor:pointer;transition:background .22s var(--ease);flex:none}
.msw i{position:absolute;top:2.5px;left:2.5px;width:18px;height:18px;border-radius:50%;
  background:#fff;transition:left .22s var(--ease);box-shadow:0 1px 3px rgba(0,0,0,.2)}
.msw.on{background:var(--p)}
.msw.on i{left:19.5px}
.mflowbox{margin:0 14px 14px;background:var(--p50);border:1px solid #C8E6D5;border-radius:13px;
  padding:9px 11px}
.mflowbox span{display:block;font-size:10px;font-weight:500;color:var(--p700);margin-bottom:2px}
.mflowbox b{font-size:12px;font-weight:700;color:var(--pd)}
.mnav{display:flex;align-items:center;gap:11px;padding:12px 14px}

/* 떠 있는 알약 탭바 — height 58, radius 22, margin 16/12 (실제 앱 수치) */
.mtabs{position:absolute;left:14px;right:14px;bottom:11px;height:52px;
  background:#fff;border:1px solid rgba(15,23,42,.06);border-radius:20px;
  display:flex;box-shadow:0 2px 8px rgba(0,0,0,.05)}
.mtabs button{flex:1;background:none;border:none;font:inherit;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  color:#94A3B8;font-size:9px;font-weight:600;letter-spacing:.02em;position:relative;
  transition:color .18s}
.mtabs button .ic{font-size:18px}
.mtabs button.on{color:var(--p)}
.tbadge,.tdot{position:absolute;font-style:normal;background:#EF4444;color:#fff}
.tbadge{top:5px;right:calc(50% - 18px);font-size:8px;font-weight:700;min-width:14px;height:14px;
  border-radius:7px;display:grid;place-items:center;padding:0 3px}
.tdot{top:7px;right:calc(50% - 12px);width:7px;height:7px;border-radius:50%}

/* 폰은 340×700 고정 설계 — 화면에 맞춰 통째로 축소한다(내부 치수 그대로) */
.mock-fit{--s:1;width:calc(375px * var(--s));height:calc(700px * var(--s))}
@media(max-height:960px){.mock-fit{--s:.94}}
@media(max-height:880px){.mock-fit{--s:.88}}
@media(max-height:800px){.mock-fit{--s:.82}}
@media(max-height:720px){.mock-fit{--s:.76}}
@media(max-height:640px){.mock-fit{--s:.68}}
@media(max-width:900px){.mock-fit{--s:.88}}
@media(max-width:420px){.mock-fit{--s:.84}}
@media(max-width:350px){.mock-fit{--s:.72}}

/* ── Live-call states — demo only ──────────────────────────────
   The marketing site mounts this mockup static; the demo drives it from the
   real call's data messages, so these states only ever appear there. */

/* The in-progress call sitting at the top of Calls. */
.mock-phone .mitem.is-live{
  background:var(--p50);border-radius:12px;
  animation:mfade .3s var(--ease)}
.mock-phone .mitem.is-live .mit-sub em.live{color:var(--p700);font-weight:700}
.mock-phone .mitem.is-live .mav{background:var(--p);color:#fff}
/* Its transcript is open from the start — watching it fill is the point. */
.mock-phone .mitem.is-live .mtranscript{padding-top:2px}

/* A counter that just changed. Brief, single flash — this fires while the
   visitor is mid-call and must not pull focus from the conversation. */
.mock-phone .mtile b.bumped,
.mock-phone .mrline b.bumped,
.mock-phone .mherobig.bumped{
  animation:mbump .9s var(--ease)}
@keyframes mbump{
  0%{color:var(--p700);transform:scale(1)}
  22%{color:var(--p700);transform:scale(1.16)}
  100%{color:inherit;transform:scale(1)}
}

/* "Checking the calendar..." shimmer on the appointment tiles. */
.mock-phone .mtiles.is-busy .mtile{position:relative;overflow:hidden}
.mock-phone .mtiles.is-busy .mtile::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,rgba(136,201,161,.28),transparent);
  animation:mshimmer 1.15s linear infinite}
@keyframes mshimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}

/* Live pill in the home header, pulsing only while a call is up. */
.mock-phone .mlive.is-active i{animation:mlivedot 1.4s var(--ease) infinite}
@keyframes mlivedot{0%,100%{opacity:1}50%{opacity:.3}}

/* Empty-state line for the zeroed demo phone. The lists start empty there —
   a blank tab reads as broken, so say why it is blank. */
.mock-phone .mempty{
  list-style:none;padding:18px 4px;text-align:center;
  color:var(--n400);font-size:12px}

/* ── A counter changing has to be catchable ─────────────────────
   Booked going 0 -> 1 is the moment the demo exists to produce, and it lands
   on a phone the visitor is not looking at. The number alone was too quiet:
   the tile flashes, and a "↑+1" floats up out of it and fades. */
.mock-phone .mtile,
.mock-phone .mhero,
/* The "Needs You" rows count too, and their chip has to float out of the line
   it belongs to. Without this the nearest positioned ancestor is the phone
   itself and the +1 lands in the far corner, next to nothing. */
.mock-phone .mrline{position:relative}
.mock-phone .tile-bumped{animation:mtileflash 1.5s var(--ease)}
@keyframes mtileflash{
  0%   {background:var(--p50);box-shadow:0 0 0 0 var(--p)}
  12%  {background:var(--p50);box-shadow:0 0 0 3px color-mix(in srgb,var(--p) 55%,transparent)}
  100% {background:#fff;      box-shadow:0 0 0 0 transparent}
}
/* The "Needs You" rows are now washed whole (.mrow.is-spot-flash, added by
   flashDelta). mtileflash lands on an opaque white plate, which inside a mint
   row paints a white rectangle over it and reads as a rendering bug. Keep the
   ring around the number, drop the plate. Tiles and the hero sit on white
   anyway, so they keep mtileflash unchanged. */
.mock-phone .mrline.tile-bumped{animation:mlineflash 1.5s var(--ease)}
@keyframes mlineflash{
  0%   {box-shadow:0 0 0 0 var(--p)}
  12%  {box-shadow:0 0 0 3px color-mix(in srgb,var(--p) 55%,transparent)}
  100% {box-shadow:0 0 0 0 transparent}
}
.mock-phone .bump-chip{
  position:absolute;right:6px;top:5px;
  font-size:14px;font-weight:800;line-height:1;letter-spacing:-.01em;
  /* Mint plate, ink type. The old 11px mint-on-white chip read as part of the
     number it was floating out of; a filled pill at the size of the label next
     to it is the smallest thing that is unmistakably NEW. */
  color:var(--n900);background:var(--p);
  padding:4px 7px;border-radius:999px;
  pointer-events:none;
  animation:mbumpchip 1.6s var(--ease) forwards}
@keyframes mbumpchip{
  0%   {opacity:0;transform:translateY(6px) scale(.85)}
  18%  {opacity:1;transform:translateY(0)   scale(1)}
  65%  {opacity:1;transform:translateY(-8px)}
  100% {opacity:0;transform:translateY(-18px)}
}
@media (prefers-reduced-motion: reduce){
  .mock-phone .tile-bumped{animation:none;background:var(--p50)}
  .mock-phone .mrline.tile-bumped{animation:none;background:none;box-shadow:0 0 0 2px var(--p)}
  .mock-phone .bump-chip{animation:none;opacity:1}
  /* mbump scales the figure. Keep the colour flash, drop the movement, rather
     than losing the only signal a counter changed. */
  .mock-phone .mtile b.bumped,
  .mock-phone .mrline b.bumped,
  .mock-phone .mherobig.bumped{animation:mbumpflat .9s var(--ease)}
}
@keyframes mbumpflat{0%,22%{color:var(--p700)}100%{color:inherit}}

/* ── Spotlight: where the change landed ─────────────────────────
   The counter says something happened. These say WHERE, for about two
   seconds, while app-mock.js walks the phone to it and back. Three marks:

     .is-spot        the one row / bubble that changed
     .is-spot-flash  a wash across the container it lives in
     .is-spot-pulse  the Booked tile, the one counter with no row behind it

   Mint only, no glow, no gradient: mint is this UI's own "active" colour, so
   a mint wash reads as the app doing something, which is exactly the claim. */
.mock-phone .mmc.is-spot{
  /* cardHTML writes the status colour inline, so the spotlight border has to
     out-rank it. This is the one !important in the file and it is why. */
  border-left-color:var(--p700)!important;
  animation:mspotwash 2.2s var(--ease) forwards}
@keyframes mspotwash{
  0%,55%{background:var(--p50)}
  100%  {background:#fff}
}
/* A chat bubble already owns its background, so the mark is a ring. */
.mock-phone .mthread p.is-spot{
  animation:mspotring 2.2s var(--ease) forwards}
@keyframes mspotring{
  0%,55%{box-shadow:0 0 0 2px var(--p)}
  100%  {box-shadow:0 0 0 0 transparent}
}
/* Booked. Twice, because one pulse inside a two-second window is easy to blink
   past, and 1.08 because a counter tile that jumps further looks broken. */
.mock-phone .mtile.is-spot-pulse{
  position:relative;z-index:1;
  animation:mspotpulse 1.1s var(--ease) 2}
@keyframes mspotpulse{
  0%  {transform:scale(1);    box-shadow:0 0 0 0 var(--p)}
  35% {transform:scale(1.08); box-shadow:0 0 0 3px var(--p)}
  100%{transform:scale(1);    box-shadow:0 0 0 0 transparent}
}
/* The band the tile sits in, a "Needs You" row, the Messages tab. */
.mock-phone .is-spot-flash{
  border-radius:15px;
  animation:mspotflash 1.6s var(--ease) forwards}
@keyframes mspotflash{
  0%,60%{background:var(--p50)}
  100%  {background:transparent}
}
@media (prefers-reduced-motion: reduce){
  /* spotlight() bails out under this too, so nothing should ever wear these.
     Belt and braces, and no transforms if anything does. */
  .mock-phone .mmc.is-spot,
  .mock-phone .mthread p.is-spot,
  .mock-phone .is-spot-flash{animation:none;background:var(--p50)}
  .mock-phone .mtile.is-spot-pulse{animation:none;transform:none;box-shadow:0 0 0 3px var(--p)}
}

/* ── Appointments screen ────────────────────────────────────────
   Reached by tapping a counter tile on Home; the tile passes its own filter
   through so "Booked" opens the booked list, not an unfiltered one. */
.mock-phone .mtile{text-align:left;font:inherit;border:none;cursor:pointer;
  transition:background .15s var(--ease)}
/* Every other tappable thing in here answers a mouse (.mrow, .mhero,
   .mitem-head all take :hover). The counter tiles were the one that did not,
   so half the phone went dead under the pointer and the whole thing read as a
   picture. Kept above :active so a press still wins over a hover. */
.mock-phone .mtile:hover{background:#FAFAFA}
.mock-phone .mtile:active{background:var(--p50)}
.mock-phone .mappt{display:flex;align-items:center;gap:10px;
  padding:11px 4px;border-top:1px solid var(--line);list-style:none}
.mock-phone .mappt:first-child{border-top:none}
.mock-phone .mappt-time{flex:none;width:46px;font-weight:700;font-size:13px;
  color:var(--n900);line-height:1.15}
.mock-phone .mappt-time i{display:block;font-style:normal;font-weight:600;
  font-size:9px;letter-spacing:.06em;color:var(--n400)}
.mock-phone .mappt-main{flex:1;min-width:0}
.mock-phone .mappt-main b{display:block;font-size:13px;color:var(--n900);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mock-phone .mappt-main span{display:block;font-size:11px;color:var(--n500);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mock-phone .mappt-pill{flex:none;font-style:normal;font-size:9.5px;font-weight:700;
  letter-spacing:.04em;padding:3px 7px;border-radius:999px}
.mock-phone .mappt-pill.booked{background:var(--p50);color:var(--p700)}
.mock-phone .mappt-pill.moved{background:#FFF7ED;color:#B45309}
.mock-phone .mappt-pill.cancelled{background:#F5F5F5;color:var(--n500)}
.mock-phone .mappt-pill.cp{background:#EEF2FF;color:#4338CA}
/* The one the caller just made. */
.mock-phone .mappt.is-new{animation:mfade .35s var(--ease)}
.mock-phone .mappt.is-new .mappt-main b{color:var(--p700)}

/* ── ambient "you can touch this" hint ──────────────────────────
   Opt-in: nothing here applies until .hint-press / .tap-ring are added, and
   the only caller is Mock.startAmbientHint(), which runs solely when a host
   mounts with { ambientHint: true }. The marketing auto-mount does; /demo/
   does not, because a real call already drives the phone there and a
   synthetic press would land on top of live events.

   Why it exists: on / nothing feeds this mock, so it holds perfectly still
   until clicked, and a motionless UI is read as a screenshot. Pressing real
   rows says "these are buttons" without faking a data change.

   Neutral ink, not mint: mint is this UI's own state colour (hover, pressed,
   selected and the header are all mint), so a mint hint would read as the app
   doing something rather than as a pointer at it. Kept faint on purpose — it
   loops, and anything stronger turns into a blinking ad. The pressed tint is
   a step deeper than the #FAFAFA hover so the two do not look identical. */
.mock-phone .hint-press{position:relative;background:#F1F1F1}
.mock-phone .tap-ring{
  /* Sits over the chevron, which is where a finger would actually land to open
     the row. .mcard is overflow:hidden, so the ring clips against the card edge
     at full scale — that reads as a surface-bounded ripple, not a bug. */
  position:absolute;top:50%;right:8px;width:34px;height:34px;margin-top:-17px;
  border-radius:50%;background:var(--n900);pointer-events:none;
  animation:mtapring .75s var(--ease) forwards;
}
/* Counter tiles have no chevron to aim at, so centre the ring on them. */
.mock-phone .tap-ring.mid{right:auto;left:50%;margin-left:-17px}
/* Peak opacity is low because the fill is near-black and reads much heavier
   than a tint would: .24 over white lands around #D2D2D2, which is the weight
   this wants. Raising it makes a looping animation feel like an alert. */
@keyframes mtapring{
  0%{transform:scale(.35);opacity:.24}
  70%{opacity:.10}
  100%{transform:scale(1.5);opacity:0}
}
@media(prefers-reduced-motion:reduce){
  /* startAmbientHint() bails out under this too; belt and braces if a host
     ever adds the classes itself. */
  .mock-phone .tap-ring{display:none}
  .mock-phone .hint-press{background:none}
}

/* ═══════════ Home 모달 — mobile/components/dashboard/*Modal.tsx 1:1 ═══════════
   The Home dashboard does NOT navigate on tap in the real app: every row, the
   hero and every tile open a pageSheet Modal (DashboardContent.tsx). The mock
   used to jump to a tab instead, which is why everything past the first screen
   looked like a different product.

   Sizes are the mock's own scale (~0.8x of the app's Tailwind steps), the same
   ratio the Home screen above already uses — copying the app's px values 1:1
   here would make the modal type bigger than the dashboard behind it.
   Sources: DashboardContent.tsx (shell), CallListModal / CallbackListModal /
   AppointmentListModal / FollowUpListModal / OutreachListModal /
   ClassPassListModal (bodies). */
.mock-phone .mmodal{
  position:absolute;left:0;right:0;top:22px;bottom:0;z-index:20;
  background:var(--slate);border-radius:20px 20px 0 0;overflow:hidden;
  display:flex;flex-direction:column;
  box-shadow:0 -8px 30px rgba(0,0,0,.16);
  transform:translateY(100%);transition:transform .32s var(--ease);
}
.mock-phone .mmodal.on{transform:none}
/* pageSheet leaves the screen behind visible and dimmed at the top edge. */
.mock-phone .mscrim{position:absolute;inset:0;z-index:19;background:rgba(0,0,0,.28);
  opacity:0;pointer-events:none;transition:opacity .32s var(--ease)}
.mock-phone .mscrim.on{opacity:1;pointer-events:auto}

.mock-phone .mmhead{flex:none;display:flex;align-items:center;justify-content:space-between;
  gap:8px;background:#fff;padding:13px 14px 11px;border-bottom:1px solid var(--line)}
.mock-phone .mmtitle{display:flex;align-items:center;gap:7px;min-width:0}
.mock-phone .mmtitle b{font-size:15px;font-weight:700;letter-spacing:-.02em;color:var(--n900);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mock-phone .mmcount{flex:none;background:var(--line);border-radius:999px;padding:1px 7px;
  font-size:9px;font-weight:700;color:var(--n500)}
.mock-phone .mmclose{flex:none;width:30px;height:30px;border-radius:50%;border:none;
  background:var(--line);color:var(--n500);display:grid;place-items:center;
  cursor:pointer;font-size:15px;transition:background .15s}
.mock-phone .mmclose:hover{background:#EBEBEB}
.mock-phone .mmbody{flex:1;overflow-y:auto;padding:14px;scrollbar-width:none}
.mock-phone .mmbody::-webkit-scrollbar{display:none}

/* Filter pills — a horizontal row of rounded chips, active is solid ink.
   Not .mseg: that is the segmented control the Calls/Messages TABS use, and
   these modals use free chips. Keeping them distinct keeps both honest. */
.mock-phone .mfils{display:flex;gap:6px;margin-bottom:11px;overflow-x:auto;
  scrollbar-width:none;padding:1px}
.mock-phone .mfils::-webkit-scrollbar{display:none}
.mock-phone .mfil{flex:none;background:var(--line);border:none;border-radius:999px;
  padding:5px 10px;font:inherit;font-size:10.5px;font-weight:600;color:var(--n600);
  cursor:pointer;transition:background .15s,color .15s;white-space:nowrap}
.mock-phone .mfil:hover{background:#EBEBEB}
.mock-phone .mfil.on{background:var(--n900);color:#fff}

/* Card — the one shape every modal in the app repeats. The 3px left border is
   the status colour and is the fastest read in the whole list. */
.mock-phone .mmlist{display:grid;gap:11px}
.mock-phone .mmc{background:#fff;border:1px solid var(--line);border-left:3px solid #9CA3AF;
  border-radius:12px;padding:13px;overflow:hidden}
.mock-phone .mmc-top{display:flex;align-items:center;gap:6px;margin-bottom:4px}
.mock-phone .mmc-top b{flex:1;min-width:0;font-size:13px;font-weight:700;color:var(--n900);
  letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mock-phone .mmc-time{flex:none;font-size:9px;color:var(--n400)}
.mock-phone .mmc-top .mchev{flex:none;font-size:13px}
.mock-phone .mmc-tags{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:7px}
.mock-phone .mtag{font-size:9px;font-weight:600;border-radius:999px;padding:2px 7px;line-height:1.5}
.mock-phone .mmc-rows{display:grid;gap:5px}
.mock-phone .mmc-r{display:flex;align-items:center;gap:7px;font-size:11px;color:var(--n600)}
.mock-phone .mmc-r .ic{font-size:12px;color:var(--n400);flex:none}
.mock-phone .mmc-r.strong{color:#404040;font-weight:500}
.mock-phone .mmc-r em{font-style:normal;color:#D4D4D4}
/* Card body + right-hand action buttons (Callbacks / Leads carry them). */
.mock-phone .mmc-split{display:flex;align-items:flex-start;gap:10px}
.mock-phone .mmc-split>div:first-child{flex:1;min-width:0}
.mock-phone .mmc-btns{flex:none;display:grid;gap:6px}
.mock-phone .mmc-btn{width:30px;height:30px;border-radius:50%;border:none;cursor:pointer;
  display:grid;place-items:center;font-size:14px;transition:filter .15s}
.mock-phone .mmc-btn:hover{filter:brightness(.94)}
.mock-phone .mmc-btn.call{background:var(--p50);color:var(--p700)}
.mock-phone .mmc-btn.done{background:#FFF7ED;color:#EA580C}

.mock-phone .mmempty{display:grid;justify-items:center;gap:5px;padding:52px 0;text-align:center}
.mock-phone .mmempty .ic{font-size:34px;color:#D4D4D4}
.mock-phone .mmempty b{font-size:12px;font-weight:600;color:var(--n500)}
.mock-phone .mmempty span{font-size:10px;color:var(--n400)}

/* Badge palette — Tailwind's 100/800 pairs, the same ones the app's
   getStatusStyle/getSourceStyle/getTypeBadge helpers return. */
.mock-phone .t-green {background:#DCFCE7;color:#166534}
.mock-phone .t-red   {background:#FEE2E2;color:#991B1B}
.mock-phone .t-blue  {background:#DBEAFE;color:#1E40AF}
.mock-phone .t-gray  {background:#F5F5F5;color:#525252}
.mock-phone .t-orange{background:#FFEDD5;color:#9A3412}
.mock-phone .t-purple{background:#F3E8FF;color:#6B21A8}
.mock-phone .t-emerald{background:#D1FAE5;color:#065F46}
.mock-phone .t-sky   {background:#E0F2FE;color:#075985}
.mock-phone .t-amber {background:#FEF3C7;color:#92400E}
.mock-phone .t-indigo{background:#E0E7FF;color:#3730A3}
.mock-phone .t-teal  {background:#CCFBF1;color:#115E59}
.mock-phone .t-violet{background:#EDE9FE;color:#5B21B6}
.mock-phone .t-yellow{background:#FEF9C3;color:#854D0E}

@media(prefers-reduced-motion:reduce){
  .mock-phone .mmodal,.mock-phone .mscrim{transition:none}
}
