/* ═══════════ TOKENS ═══════════ */
:root{
  --ink:#191F28; --ink-2:#4E5968; --ink-3:#6B7684; --ink-4:#8B95A1;
  /* 화살표는 글씨가 아니다. 글씨 회색을 그대로 쓰면 여덟 개가 줄줄이 서서 시끄럽다. */
  --chev:#C2CAD4;
  --line:#E5E8EB; --line-2:#F2F4F6;
  --surface:#FFFFFF; --surface-2:#F9FAFB; --surface-3:#F2F4F6; --ground:#FFFFFF;
  --blue:#3182F6; --blue-ink:#1B64DA; --blue-wash:#E8F3FF;
  --ok:#00B27A;
  /* 아래줄에서 지금 켜진 칸의 색. 구슬 파랑과 같은 계열이라 따로 놀지 않는다 */
  --tab-on:#3182F6; --ok-wash:#E4F8F0;
  --warn:#FF9500; --warn-wash:#FFF4E0;
  --stop:#F04452; --stop-wash:#FFEBEE;
  --p1:#7C5CFF; --p2:#3182F6; --p3:#22D3EE; --p4:#FF7BC5;
  /* 말풍선은 오브 색을 따라가지 않는다. 오브는 얼굴이고, 말풍선은 글이다.
     탭과 같은 파랑 하나로 통일해서 화면에 색이 둘이 되지 않게 한다. */
  --bub-me:#3182F6; --bub-you:rgba(238,241,246,.9);
  /* glass */
  --g1-bg:rgba(255,255,255,.55); --g2-bg:rgba(255,255,255,.72); --g3-bg:rgba(255,255,255,.82);
  --g-rim:rgba(255,255,255,.35);
  /* 떠 있는 탭 알약만 조금 더 맑게 — 밑으로 지나가는 목록 색이 비쳐야 유리로 읽힌다 */
  /* 애플이 하는 방식. 뒤가 「읽히면」 유리가 아니다 —
     알약 밑을 지나는 글자는 뭉개진 얼룩이어야 한다. 휘는 건 위·아래 모서리에서만.
     한때 흐림을 1px 까지 내려 본 적이 있는데, 그러면 뒤 글자가 그대로 읽혀서
     휘는 순간 굴절이 아니라 「깨진 글자」로 보였다. 그게 버벅임의 정체였다.
     18px = 뒤 색은 살아 있고 글자는 안 읽히는 자리. */
  --nav-bg:rgba(252,253,255,.12);
  --nav-icon-halo:rgba(255,255,255,.8);
  --nav-blur:blur(7px) saturate(150%);
  --nav-edge-blur:blur(14px) saturate(160%);
  /* 손을 멈췄을 때(커진 상태)는 색을 조금 더 머금는다. 아이폰이 그렇게 한다. */
  --nav-bg-big:rgba(252,253,255,.17);
  --lens-fx:saturate(122%) brightness(.99);
  --lens-edge:rgba(25,31,40,.14); --lens-hot:rgba(255,255,255,.9);
  --nav-lens:rgba(255,255,255,.8);
  --nav-lens-2:rgba(255,255,255,.28);
  /* 시트(모달)도 알약과 같은 유리. 밝을 때는 연할수록 예쁘다 — 뒤 색이 배어 나온다 */
  --sheet-bg:rgba(252,253,255,.22);
  /* 가장자리만 두껍게 흐리고, 가운데는 거의 맑다.
     가운데까지 흐리면 뭉개진 것이 그냥 「배경」이 돼서 유리로 안 보인다. */
  --sheet-blur:blur(14px) saturate(190%);
  --sheet-core:blur(2px) saturate(150%);
  --rim-warp:blur(1px) saturate(150%) brightness(1.04);
  --rim-out:rgba(25,31,40,.1); --rim-in:rgba(255,255,255,.42);
  /* 알림 알약. 글이 짧고 한 번 스치니 뒤를 꽤 눌러 담는다 */
  --toast-bg:rgba(28,33,42,.78); --toast-ink:#fff;
  --toast-rim:rgba(255,255,255,.26);
  --nav-hair:rgba(25,31,40,.07);
  --nav-floor:rgba(25,31,40,.1);
  --sh-c:0 1px 2px rgba(25,31,40,.04);
  --sh-a:0 12px 32px rgba(25,31,40,.08);
  /* 제목은 본문과 다른 계열로 간다. 굵기만 다르면 「같은 글씨를 굵게 한 것」으로 보이고,
     그게 목업처럼 보이는 가장 큰 이유였다. */
  --font:'Pretendard Variable',Pretendard,-apple-system,BlinkMacSystemFont,'Apple SD Gothic Neo',system-ui,sans-serif;
  --mono:'SF Mono',ui-monospace,Menlo,monospace;
  --safe-t:env(safe-area-inset-top,0px);
  --safe-b:env(safe-area-inset-bottom,0px);
}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]){
  --ink:#F2F4F6; --ink-2:#C3CAD3; --ink-3:#9AA4B0; --ink-4:#7A8494;
  --chev:#4C5563;
  --line:#2A3038; --line-2:#21262D;
  --surface:#1A1F27; --surface-2:#161A21; --surface-3:#21262D; --ground:#0F1319;
  --blue:#4C8EF7; --blue-ink:#82B1FF; --blue-wash:#16253C;
  --ok:#2ACF9A;
  /* 어두운 바탕에선 같은 파랑이 가라앉는다. 한 톤 밝게 올린다 */
  --tab-on:#5B9DFF; --ok-wash:#10291F;
  --warn:#FFAA33; --warn-wash:#2E2110;
  --stop:#FF6B75; --stop-wash:#2E1518;
  --bub-you:rgba(36,42,56,.72);
  --g1-bg:rgba(28,32,40,.60); --g2-bg:rgba(30,35,44,.68); --g3-bg:rgba(32,38,48,.78);
  --g-rim:rgba(255,255,255,.14);
  --nav-bg:rgba(18,23,32,.2);
  --nav-icon-halo:rgba(10,14,20,.75);
  --nav-blur:blur(8px) saturate(140%);
  --nav-edge-blur:blur(15px) saturate(150%);
  --nav-bg-big:rgba(18,23,32,.28);
  --lens-fx:saturate(118%) brightness(1.06);
  --lens-edge:rgba(0,0,0,.16); --lens-hot:rgba(255,255,255,.2);
  --nav-lens:rgba(255,255,255,.4);
  --nav-lens-2:rgba(255,255,255,.12);
  --sheet-bg:rgba(22,27,36,.26);
  --sheet-blur:blur(16px) saturate(165%);
  --sheet-core:blur(3px) saturate(140%);
  --rim-warp:blur(1px) saturate(140%) brightness(1.12);
  --rim-out:rgba(0,0,0,.3); --rim-in:rgba(255,255,255,.15);
  --toast-bg:rgba(238,241,246,.82); --toast-ink:#12161d;
  --toast-rim:rgba(255,255,255,.5);
  --nav-hair:rgba(0,0,0,.42);
  --nav-floor:rgba(0,0,0,.34);
  --sh-c:0 1px 2px rgba(0,0,0,.3); --sh-a:0 12px 32px rgba(0,0,0,.4);
}}
:root[data-theme=dark]{
  --ink:#F2F4F6; --ink-2:#C3CAD3; --ink-3:#9AA4B0; --ink-4:#7A8494;
  --chev:#4C5563;
  --line:#2A3038; --line-2:#21262D;
  --surface:#1A1F27; --surface-2:#161A21; --surface-3:#21262D; --ground:#0F1319;
  --blue:#4C8EF7; --blue-ink:#82B1FF; --blue-wash:#16253C;
  --ok:#2ACF9A; --ok-wash:#10291F; --warn:#FFAA33; --warn-wash:#2E2110;
  --tab-on:#5B9DFF;
  --stop:#FF6B75; --stop-wash:#2E1518;
  --bub-you:rgba(36,42,56,.72);
  --g1-bg:rgba(28,32,40,.60); --g2-bg:rgba(30,35,44,.68); --g3-bg:rgba(32,38,48,.78);
  --g-rim:rgba(255,255,255,.14);
  --nav-bg:rgba(18,23,32,.2);
  --nav-icon-halo:rgba(10,14,20,.75);
  --nav-blur:blur(8px) saturate(140%);
  --nav-edge-blur:blur(15px) saturate(150%);
  --nav-bg-big:rgba(18,23,32,.28);
  --lens-fx:saturate(118%) brightness(1.06);
  --lens-edge:rgba(0,0,0,.16); --lens-hot:rgba(255,255,255,.2);
  --nav-lens:rgba(255,255,255,.4);
  --nav-lens-2:rgba(255,255,255,.12);
  --sheet-bg:rgba(22,27,36,.26);
  --sheet-blur:blur(16px) saturate(165%);
  --sheet-core:blur(3px) saturate(140%);
  --rim-warp:blur(1px) saturate(140%) brightness(1.12);
  --rim-out:rgba(0,0,0,.3); --rim-in:rgba(255,255,255,.15);
  --toast-bg:rgba(238,241,246,.82); --toast-ink:#12161d;
  --toast-rim:rgba(255,255,255,.5);
  --nav-hair:rgba(0,0,0,.42);
  --nav-floor:rgba(0,0,0,.34);
  --sh-c:0 1px 2px rgba(0,0,0,.3); --sh-a:0 12px 32px rgba(0,0,0,.4);
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
/* 아이폰 홈화면 앱에서 상태창(다이내믹 아일랜드 둘레)은 body 가 아니라
   맨 바깥 html 색을 쓴다. 여기가 비어 있으면 그 띠만 검게 남는다. */
/* 사파리의 「당겨서 새로고침」은 body 가 아니라 맨 바깥 html 을 보고 움직인다.
   여기에 안 걸어두면 목록을 당길 때 사파리가 페이지를 통째로 다시 읽어버린다. */
html,body{height:100%;background:var(--ground);overscroll-behavior:none}
body{margin:0;background:var(--ground);color:var(--ink);font-family:var(--font);
  font-size:15px;line-height:1.6;letter-spacing:-.012em;-webkit-font-smoothing:antialiased;
  overscroll-behavior:none}
button{font-family:inherit;border:none;background:none;color:inherit;cursor:pointer}
input,textarea{font-family:inherit;border:none;outline:none;background:none;color:inherit}
:focus-visible{outline:2px solid var(--blue);outline-offset:2px;border-radius:6px}

/* 상태창 자리에는 아무것도 덮지 않는다.
   예전에는 여기를 --ground 로 칠했다. 그런데 본문은 그 위에 색기운(mesh, 5%)이
   한 겹 더 얹혀 있어서, 칠한 자리만 그 기운이 빠졌다 —
   상태창 255,255,255 · 머리글 252,253,255. 그 1~3 차이가 「미세하게 다른 색」이었다.
   비워 두면 상태창 자리도 머리글도 똑같이 「바탕 + 색기운」이라 어긋날 수가 없다. */

/* prism mesh — 유리가 읽히려면 뒤에 뭔가 있어야 함 (불투명도 5%) */
.mesh{position:fixed;inset:0;z-index:0;pointer-events:none;opacity:.05;
  background:
    radial-gradient(46% 38% at 18% 12%,var(--p1),transparent 62%),
    radial-gradient(42% 34% at 84% 22%,var(--p3),transparent 60%),
    radial-gradient(50% 40% at 72% 86%,var(--p4),transparent 64%),
    radial-gradient(44% 36% at 12% 78%,var(--p2),transparent 60%)}

/* ═══════════ GLASS ═══════════ */
.g1{background:var(--g1-bg);-webkit-backdrop-filter:blur(20px) saturate(180%);
  backdrop-filter:blur(20px) saturate(180%)}
.g2{background:var(--g2-bg);-webkit-backdrop-filter:blur(14px) saturate(160%);
  backdrop-filter:blur(14px) saturate(160%);border:.5px solid var(--g-rim);
  box-shadow:inset 0 1px .5px rgba(255,255,255,.6),inset 0 -1px .5px rgba(255,255,255,.15),
    var(--sh-c),0 8px 24px rgba(25,31,40,.06)}
.g3{background:var(--g3-bg);-webkit-backdrop-filter:blur(28px) saturate(200%);
  backdrop-filter:blur(28px) saturate(200%);border:.5px solid rgba(255,255,255,.45);
  box-shadow:inset 0 1.5px 1px rgba(255,255,255,.75),inset 0 -1px 1px rgba(255,255,255,.2),
    0 2px 6px rgba(25,31,40,.06),0 20px 48px rgba(25,31,40,.14)}
@media (prefers-reduced-transparency:reduce){
  .g1,.g2,.g3{backdrop-filter:none;-webkit-backdrop-filter:none;background:var(--surface)}
  /* 투명 효과를 끈 사람에게는 유리도 빛도 없다 */
  .sheet.g3{background:var(--surface)}
  .sheet.g3::before,.sheet.g3::after{display:none}
  .toast{backdrop-filter:none;-webkit-backdrop-filter:none}
}

/* ═══════════ SHELL ═══════════ */
#app{position:relative;z-index:1;height:100dvh;display:flex;flex-direction:column;
  max-width:520px;margin:0 auto;overflow:hidden}
/* 시트·배지가 뷰 밖으로 나가는 게 있어서 자르지 않는다 */
.view{flex:1;display:flex;flex-direction:column;min-height:0;position:relative;overflow:visible}
.view[hidden]{display:none}

/* appbar */
.appbar{display:flex;align-items:center;gap:11px;flex:none;
  padding:calc(18px + var(--safe-t)) 20px 14px;
  /* 바탕은 칠하지 않는다. 예전에는 여기만 --ground 로 덮었는데,
     뒤에 깔린 mesh(색기운 5%)가 머리글에서만 가려져서
     머리글 255,255,255 · 본문 251,254,255 로 경계선이 보였다.
     비워 두면 머리글도 본문도 같은 mesh 위에 앉는다. */
  background:none;-webkit-backdrop-filter:none;backdrop-filter:none;
  /* 밑줄은 평소엔 없다. 아무것도 지나가지 않는데 선부터 그으면 서식 종이처럼 보인다.
     목록이 제목 밑으로 들어가는 순간에만(.lift) 바닥이 생긴다. */
  border-bottom:.5px solid transparent;transition:border-color .18s;
  position:relative;z-index:5}
.appbar.lift{border-bottom-color:var(--line)}
/* 스크롤 통 안으로 들어간 제목줄. 본문과 같이 밀려 올라간다.
   좌우 여백은 app.js 가 통의 안쪽 여백만큼 음수로 상쇄해 준다 —
   화면마다 여백이 달라서 CSS 한 값으로는 못 맞춘다. */
.appbar.inflow{padding-bottom:6px;border-bottom-color:transparent!important}
/* 눌리는 칸은 44, 보이는 그림은 24. 크기를 안 정하면 32로 나와서 화살표가 뭉툭해진다. */
.ab-back{width:44px;height:44px;display:grid;place-items:center;margin-left:-13px;
  color:var(--ink-3);border-radius:12px}
.ab-back svg{width:24px;height:24px;stroke-width:1.9}
.ab-a button svg{width:22px;height:22px;stroke-width:1.9}
.comp .ab-back svg{width:23px;height:23px;stroke-width:1.9}
.send svg{width:20px;height:20px;stroke-width:1.9}
/* 제목 묶음. 작은 머리글이 「위」, 큰 제목이 「아래」로 오게 순서를 뒤집는다.
   글자 순서를 바꾸는 게 아니라 보이는 자리만 바꾸는 거라 본문 코드는 그대로 둔다. */
.appbar>div:not(.ab-a){display:flex;flex-direction:column-reverse;min-width:0}
/* 글자 크기 층: 제목 30 · 이름 16 · 설명 12.5 · 머리글 11.
   예전엔 17 / 15.5 / 13.5 / 12.5 라 5px 안에 다 몰려 있었다 — 그래서 위계가 안 보였다. */
/* 제목은 본문과 같은 글씨체다. 한때 명조(Hahmlet)를 썼는데,
   화면마다 튀어나오는 「정리 · 설정」 두 글자가 앱 성격과 안 맞았다.
   층은 글씨체가 아니라 크기(30 vs 16)와 굵기로 낸다. */
.ab-t{font-size:23px;font-weight:800;
  letter-spacing:-.036em;line-height:1.2;word-break:keep-all}
/* 제목 위 한 줄. 여기만 「작고 또렷하게」 — 설명글이 아니라 이름표다. */
.ab-s{font-size:11px;font-weight:600;color:var(--ink-3);margin:0 0 5px;display:flex;align-items:center;gap:5px;
  letter-spacing:.01em;font-variant-numeric:tabular-nums}
/* 뒤로가기가 있는 화면은 「속 화면」이다. 제목을 작게 줄여서 첫 화면과 층을 나눈다. */
/* 속 화면은 제목줄이 짧다. 뒤로가기 다음이 바로 얼굴이라 그 사이만 좁힌다. */
.appbar:has(.ab-back){gap:9px}
.appbar:has(.ab-back) .ab-back+*{margin-left:-2px}
.appbar:has(.ab-back) .ab-t{font-family:var(--font);font-size:17.5px;font-weight:600;letter-spacing:-.034em}
.appbar:has(.ab-back) .ab-s{font-size:11.5px;font-weight:500;color:var(--ink-4)}
.dot-on{width:5px;height:5px;border-radius:50%;background:var(--ok);display:inline-block}
.ab-a{margin-left:auto;margin-right:-8px;display:flex;gap:2px;color:var(--ink-3)}
/* 머리글이 제목 위로 올라가면서 오른쪽 단추가 허공에 떴다. 제목 줄에 맞춰 내린다 */
.appbar:not(:has(.ab-back)) .ab-a{align-self:flex-end;margin-bottom:1px}
.ab-a button{width:44px;height:44px;display:grid;place-items:center;border-radius:12px}
.ab-a button:active{background:var(--surface-3)}

/* 안쪽 14 + 줄 자체 여백 6 = 왼쪽 20. 제목·설정줄·목록이 전부 같은 세로줄에 선다.
   16 이면 얼굴이 제목보다 4px 오른쪽으로 밀려서, 딱 그 한끗이 어설퍼 보였다. */
.body{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:14px;
  display:flex;flex-direction:column;gap:10px;
  /* 사파리는 맨 위에서 손을 내리는 순간 자기 「고무줄」을 먼저 시작한다.
     그 뒤로는 우리 손짓이 막히지 않아서 당겨서 새로고침이 반만 듣는다.
     고무줄을 끄면 그 손짓이 온전히 우리 것이 된다. */
  overscroll-behavior-y:none}
.body.pad-nav{padding-bottom:20px}
/* 떠 있는 탭 알약이 목록 끝을 가린다. 그만큼 끝에 빈 칸을 하나 붙인다.
   padding 이 아니라 칸으로 넣는 이유 — 화면마다 padding 을 따로 덮어쓰기 때문이다. */
/* 알약(50) + 바닥 틈(6) 만 비우면, 알약 위로 21px 솟아 있는 가운데 구슬 자리에
   마지막 줄이 그대로 걸친다. 구슬 뒤로 글자가 비쳐 보이던 게 이것 때문이었다.
   구슬 꼭대기까지 비워 둔다. */
.body.pad-nav::after{content:'';flex:none;height:calc(80px + var(--safe-b) * .6)}

/* ═══════════ WORDMARK (L-3) ═══════════ */
/* ı 의 점이 m → l → y 꼭대기를 밟고 마침표 자리로 굴러간다.
   숫자는 글자 획을 실제로 재서 넣었다 (42px 기준, 기준선 y=35.9).
   획 꼭대기: m 13.2 · l 6.2 · y 팔 13.4 — 점 바닥이 딱 그 높이에 닿는다. */
.wm{position:relative;display:inline-block;line-height:1}
.wm-t{font-size:42px;font-weight:700;letter-spacing:-.05em;color:#FFFFFF}
/* 시작 자리 = ı 바로 위 (ı 가운데 37.5, 점 반지름 3.5) */
.wm-dot{position:absolute;left:34px;top:4px;animation:glimDotX 4.2s linear infinite}
.wm-dot>i{display:block;animation:glimDotY 4.2s linear infinite}
.wm-dot>i>b{display:block;width:7px;height:7px;border-radius:50%;background:#FFFFFF;
  transform-origin:50% 100%;animation:glimDotSquash 4.2s linear infinite}
/* 가로: ı(0) → m 가운데 획(17.5) → l(43) → y 오른팔(66.5) → 마침표(73.5) */
@keyframes glimDotX{0%,24%{transform:translateX(0)}36%{transform:translateX(17.5px)}
  52%{transform:translateX(43px)}68%{transform:translateX(66.5px)}
  80%,100%{transform:translateX(73.5px)}}
/* 세로: 0=ı 위, 2=m 꼭대기, -5=l 꼭대기, 2=y 팔 꼭대기, 25=기준선(마침표) */
@keyframes glimDotY{0%,24%{transform:translateY(0);animation-timing-function:cubic-bezier(.17,.67,.5,1)}
  30%{transform:translateY(-16px);animation-timing-function:cubic-bezier(.5,0,.83,.33)}
  36%{transform:translateY(2px);animation-timing-function:cubic-bezier(.17,.67,.5,1)}
  44%{transform:translateY(-20px);animation-timing-function:cubic-bezier(.5,0,.83,.33)}
  52%{transform:translateY(-5px);animation-timing-function:cubic-bezier(.17,.67,.5,1)}
  60%{transform:translateY(-18px);animation-timing-function:cubic-bezier(.5,0,.83,.33)}
  68%{transform:translateY(2px);animation-timing-function:cubic-bezier(.17,.67,.5,1)}
  74%{transform:translateY(-4px);animation-timing-function:cubic-bezier(.5,0,.83,.33)}
  80%{transform:translateY(25px);animation-timing-function:cubic-bezier(.17,.67,.5,1)}
  83%{transform:translateY(21px);animation-timing-function:cubic-bezier(.5,0,.83,.33)}
  86%,100%{transform:translateY(25px)}}
/* 눌림 — 닿는 순간에만. 밑면을 축으로 눌러야 바닥을 짚는 느낌이 난다 */
@keyframes glimDotSquash{0%,34%{transform:scale(1)}36%{transform:scale(1.3,.7)}39%{transform:scale(1)}
  50%{transform:scale(1)}52%{transform:scale(1.25,.75)}55%{transform:scale(1)}
  66%{transform:scale(1)}68%{transform:scale(1.28,.72)}71%{transform:scale(1)}
  78%{transform:scale(1)}80%{transform:scale(1.35,.65)}84%,100%{transform:scale(1)}}
@media (prefers-reduced-motion:reduce){
  .wm-dot{animation:none;transform:translateX(73.5px)}
  .wm-dot>i{animation:none;transform:translateY(25px)}
  .wm-dot>i>b{animation:none}
}

/* 가입 중 안내 줄 — 카드 대신 글줄로. 읽는 것뿐이라 상자가 필요 없다 */
.ob-lines{display:flex;flex-direction:column;gap:7px;width:100%;max-width:320px;margin:0 auto 4px}
.ob-line{font-size:13px;color:var(--ink-3);line-height:1.5;padding-left:13px;position:relative;
  word-break:keep-all}
.ob-line::before{content:"";position:absolute;left:2px;top:8px;width:3px;height:3px;
  border-radius:50%;background:var(--ink-4)}
.ob-line b{color:var(--ink);font-weight:600}

/* ═══════════ ONBOARDING ═══════════ */
.ob{position:fixed;inset:0;z-index:30;overflow:hidden;background-color:#0B0E14;
  background-image:radial-gradient(120% 90% at 50% 8%,#151A26 0%,#0B0E14 62%)}
/* 이미 쓰던 사람의 시작 화면 — 검은 덮개 없이 앱 배경 그대로.
   상태창 색도 안 튄다. 입자·후광도 끈다. */
.ob.quiet{background-color:var(--ground);background-image:none}
.ob.quiet::before,.ob.quiet::after{display:none}
/* 부팅이 대답을 못 받았을 때. 스플래시가 굳는 대신 여기로 온다.
   ob-h / ob-p 는 검은 덮개 위에 얹는 흰 글씨라 밝은 바탕에서는 안 보인다 — 그래서 따로 둔다. */
/* 새로고침 직후 잠깐 서 있는 틀. 위 제목줄과 아래 알약은 이미 제자리에 있고
   가운데만 비어 있다. 화면 전체가 하얘지지 않는 이유가 이거다. */
.booting .body{opacity:0;animation:btIn .25s ease .12s forwards}
@keyframes btIn{to{opacity:1}}
/* 오래 걸리는 날에만 나오는 한 줄. 갑자기 튀어나오지 않게 천천히 켠다. */
.bt-note{animation:btNote .45s ease both}
@keyframes btNote{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .booting .body{opacity:1;animation:none} .bt-note{animation:none} }

.boot-stuck .ob-in{justify-content:center;padding-bottom:8vh}
.boot-stuck .ob-mid{flex:none;height:auto;display:flex;flex-direction:column;
  align-items:center;text-align:center}
.bs-h{font-size:17px;font-weight:700;letter-spacing:-.034em;color:var(--ink);margin:0}
.bs-p{font-size:13.5px;color:var(--ink-3);line-height:1.6;margin:7px 0 24px}
.boot-stuck .bs-b{width:auto;padding-left:34px;padding-right:34px}
/* 별처럼 흩어진 미세 입자 — 존재가 태어나는 공간 */
.ob::before{content:'';position:absolute;inset:-20%;opacity:.5;
  background:
    radial-gradient(1.5px 1.5px at 18% 22%,rgba(255,255,255,.55),transparent),
    radial-gradient(1px 1px at 72% 14%,rgba(255,255,255,.4),transparent),
    radial-gradient(1.5px 1.5px at 34% 68%,rgba(124,92,255,.5),transparent),
    radial-gradient(1px 1px at 86% 54%,rgba(34,211,238,.45),transparent),
    radial-gradient(1.5px 1.5px at 58% 84%,rgba(255,255,255,.35),transparent),
    radial-gradient(1px 1px at 12% 88%,rgba(255,123,197,.4),transparent);
  animation:drift 26s linear infinite}
@keyframes drift{to{transform:translate3d(-30px,-40px,0) rotate(3deg)}}
/* 오브 뒤 후광 */
.ob::after{content:'';position:absolute;left:50%;top:38%;width:340px;height:340px;
  transform:translate(-50%,-50%);border-radius:50%;pointer-events:none;
  background:radial-gradient(circle,rgba(124,92,255,.16),transparent 62%);
  filter:blur(28px);animation:halo 7s ease-in-out infinite}
@keyframes halo{0%,100%{opacity:.5;transform:translate(-50%,-50%) scale(1)}
  50%{opacity:.85;transform:translate(-50%,-50%) scale(1.12)}}

.ob-in{position:relative;z-index:2;height:100%;overflow:hidden;display:flex;flex-direction:column;
  align-items:center;padding:calc(clamp(16px,5.4vh,46px) + var(--safe-t)) 26px
    calc(clamp(10px,2.4vh,20px) + var(--safe-b));gap:clamp(8px,1.7vh,14px)}
/* 약관·인디케이터는 화면 맨 아래에 붙는다 */
.ob-foot{flex:1 1 auto;min-height:0;width:100%;display:flex;flex-direction:column;
  align-items:center;justify-content:flex-end;
  gap:clamp(6px,1.2vh,10px);padding-top:clamp(6px,1.4vh,16px)}
.ob-mid{flex:none;height:clamp(150px, calc(100vh - 508px), 356px);
  display:flex;flex-direction:column;
  align-items:center;justify-content:center;width:100%;gap:clamp(10px,2.4vh,20px)}
/* 오브도 같이 줄어든다 — 인라인 width/height를 덮어쓴다 */
.ob-mid .orbwrap{width:clamp(88px, calc(100vh - 676px), 168px)!important;
  height:clamp(88px, calc(100vh - 676px), 168px)!important}
.ob-btm{width:100%;flex:none;display:flex;flex-direction:column;gap:clamp(8px,1.5vh,12px)}

/* 대화 단계 — 말풍선은 아래에서 쌓인다. 위에 뜨면 대화가 아니라 안내문으로 읽힌다 */
.ob-in.talk .ob-mid{flex:1 1 auto;min-height:0;height:auto}
.ob-in.talk .ob-btm{flex:none;justify-content:flex-end}
.ob-in.talk .ob-foot{flex:none}
.ob-in.talk .ob-talk{align-items:flex-start;gap:9px;margin-bottom:6px}
/* 오브는 대화의 시작 — 말풍선 바로 위, 같은 왼쪽 줄에 선다 */
.ob-in.talk .ob-talk .orbwrap,.ob-in.talk .ob-talk .seep{align-self:flex-start;margin-left:2px}
/* 첫 형질이 드러나는 순간 — 크기는 orbHTML 인자로 준다 */
.ob-in.talk .ob-talk .seep{margin-bottom:2px}
.ob-talk{width:100%;display:flex;flex-direction:column;gap:7px;
  justify-content:flex-end;margin-bottom:4px}

/* 단계 진입 — 요소가 아래에서 올라오며 선명해진다 */
.ob-step{animation:stepIn .52s cubic-bezier(.32,.72,0,1) both}
.d0{animation-delay:0s}.d1{animation-delay:.09s}.d2{animation-delay:.18s}
.d3{animation-delay:.27s}.d4{animation-delay:.36s}
@keyframes stepIn{from{opacity:0;transform:translateY(14px);filter:blur(8px)}
  to{opacity:1;transform:none;filter:blur(0)}}

.ob-h{font-size:16.5px;font-weight:700;letter-spacing:-.034em;color:rgba(255,255,255,.82);
  width:100%;line-height:1.35}
.ob-p{font-size:13.5px;color:rgba(255,255,255,.46);line-height:1.65;width:100%}
.ob-tiny{font-size:11.5px;color:rgba(255,255,255,.3);line-height:1.6;text-align:center}
/* AI 고지 — 법으로 먼저 알려야 하는 한 줄(AI기본법 31조).
   작게 두되 회색에 묻히지 않게 테두리를 준다. 조용하지만 분명히 보이는 자리. */
.ob-ai{font-size:11px;letter-spacing:-.01em;color:rgba(255,255,255,.5);text-align:center;
  align-self:center;padding:4px 10px;border-radius:99px;
  border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.03)}
/* 카톡 안에서 나가는 길 — 안내만으로는 못 나간다. 누를 게 있어야 한다.
   이름을 esc 로 쓴다. ob-out 은 화면이 사라질 때 쓰는 다른 클래스다. */
.ob-esc{display:flex;flex-direction:column;align-items:center;gap:7px;margin-bottom:10px}
.ob-esc-t{font-size:12px;color:#FFC46B;letter-spacing:-.02em;word-break:keep-all}
.ob-esc-b{padding:9px 18px;border-radius:999px;border:1px solid rgba(255,196,107,.42);
  background:rgba(255,196,107,.1);color:#FFD79A;font-size:13px;font-weight:600;
  letter-spacing:-.02em;cursor:pointer}
.ob-esc-b:active{transform:scale(.97)}

/* 입력 — 포커스 시 테두리가 살아난다 */
.ob-f{width:100%;background:rgba(255,255,255,.06);border:1.5px solid rgba(255,255,255,.14);
  border-radius:14px;padding:14px 16px;color:#fff;font-size:16px;letter-spacing:-.02em;
  transition:border-color .22s,background .22s,box-shadow .22s}
.ob-f::placeholder{color:rgba(255,255,255,.26)}
.ob-f:focus{border-color:rgba(143,184,255,.75);background:rgba(255,255,255,.09);
  box-shadow:0 0 0 4px rgba(124,92,255,.14)}
.ob-f.code{text-align:center;letter-spacing:.42em;font-size:22px;font-weight:700;
  font-variant-numeric:tabular-nums;padding-left:.42em}

.ob-btn{width:100%;padding:16px;border-radius:16px;font-size:16px;font-weight:700;
  letter-spacing:-.024em;background:linear-gradient(148deg,#7C5CFF,#5B6FF0);color:#fff;
  box-shadow:0 4px 16px rgba(124,92,255,.36);position:relative;overflow:hidden;
  transition:transform .12s,opacity .2s}
.ob-btn::after{content:'';position:absolute;inset:0;
  background:linear-gradient(135deg,rgba(255,255,255,.34) 0%,transparent 52%);
  mix-blend-mode:screen;pointer-events:none}
.ob-btn:active{transform:scale(.98)}
.ob-btn:disabled{opacity:.5}
.ob-ghost{width:100%;padding:14px;border-radius:16px;font-size:14.5px;font-weight:600;
  color:rgba(255,255,255,.5);background:transparent}
.ob-ghost:active{background:rgba(255,255,255,.05)}

/* 성격 선택 — 카드형 */
.ob-grid{display:grid;grid-template-columns:1fr 1fr;gap:9px;width:100%}
.ob-card{padding:17px 14px;border-radius:17px;background:rgba(255,255,255,.055);
  border:1.5px solid rgba(255,255,255,.1);color:#E8EBF0;text-align:left;
  transition:transform .14s,border-color .2s,background .2s}
.ob-card:active{transform:scale(.97)}
.ob-card.sel{border-color:rgba(143,184,255,.8);background:rgba(124,92,255,.16);
  box-shadow:0 0 0 4px rgba(124,92,255,.12)}
.ob-card-t{font-size:15px;font-weight:700;letter-spacing:-.03em}
.ob-card-d{font-size:11.5px;color:rgba(255,255,255,.4);margin-top:3px;line-height:1.45}

/* 말풍선 — 타이핑 후 등장 */
.ob-bub{align-self:flex-start;max-width:84%;padding:12px 16px;
  border-radius:17px 17px 17px 6px;background:rgba(255,255,255,.09);
  color:#E8EBF0;font-size:15px;line-height:1.52;
  animation:bubIn .46s cubic-bezier(.32,.72,0,1) both}
@keyframes bubIn{from{opacity:0;transform:translateX(-16px) scale(.96)}}

/* 진행 표시 */
.ob-dots{display:flex;gap:5px;justify-content:center;padding-top:2px}
.ob-dots i{width:5px;height:5px;border-radius:99px;background:rgba(255,255,255,.16);
  transition:all .38s cubic-bezier(.32,.72,0,1)}
.ob-dots i.on{width:18px;background:rgba(143,184,255,.85)}

/* t0 → 색이 스며드는 순간 */
.seep{animation:seep 2.2s cubic-bezier(.4,0,.2,1) both}
@keyframes seep{0%{filter:saturate(0) brightness(1.5);transform:scale(.82)}
  55%{filter:saturate(.4) brightness(1.2)}
  100%{filter:saturate(1) brightness(1);transform:scale(1)}}
.ob-flash{position:absolute;inset:0;pointer-events:none;z-index:3;
  background:radial-gradient(circle at 50% 38%,rgba(255,255,255,.5),transparent 42%);
  animation:flash 1.1s ease-out both}
@keyframes flash{0%{opacity:0}18%{opacity:1}100%{opacity:0}}

@media (prefers-reduced-motion:reduce){
  .ob::before,.ob::after,.ob-step,.ob-bub,.seep,.ob-flash{animation:none!important}
  .ob-tag i{transition:none}
  .ob-step,.ob-bub{opacity:1;transform:none;filter:none}
}

/* 스플래시 — 1회만 재생 */
.wm.once .wm-dot{animation-iteration-count:1;animation-fill-mode:forwards}
.wm.once .wm-dot>i{animation-iteration-count:1;animation-fill-mode:forwards}
.wm.once .wm-dot>i>b{animation-iteration-count:1;animation-fill-mode:forwards}
.ob-out{animation:obOut .42s cubic-bezier(.4,0,1,1) both}
@keyframes obOut{to{opacity:0;transform:scale(1.06);filter:blur(10px)}}

/* 입력 + 버튼 한 줄 */
.ob-row{display:flex;gap:8px;width:100%;align-items:stretch}
.ob-row .ob-f{flex:1;min-width:0}
.ob-row .ob-btn{width:auto;flex:none;padding:0 19px;white-space:nowrap;font-size:14.5px;
  border-radius:14px}
.ob-row .ob-btn:disabled{opacity:.35}

.orbwrap{display:grid;place-items:center;flex:none;animation:bob 6.5s ease-in-out infinite}
.orbwrap svg{width:100%;height:100%;transition:opacity .5s ease}
.orbwrap.drift svg{animation:morphIn 1.4s cubic-bezier(.32,.72,0,1) both}
@keyframes morphIn{from{opacity:.3;transform:scale(.92) rotate(-6deg);filter:blur(4px)}
  to{opacity:1;transform:none;filter:blur(0)}}

/* ═══════════ OTP 입력 ═══════════ */
.otp{display:flex;gap:8px;width:100%;justify-content:center;direction:ltr;margin-top:2px}
.otp-c{position:relative;flex:1;max-width:52px;aspect-ratio:1/1.18}
.otp-c input{position:absolute;inset:0;width:100%;height:100%;text-align:center;
  font-size:24px;font-weight:700;color:#fff;background:rgba(255,255,255,.05);
  border:1.5px solid rgba(255,255,255,.14);border-radius:15px;
  font-variant-numeric:tabular-nums;caret-color:transparent;
  transition:border-color .2s,background .2s,box-shadow .25s,transform .18s}
.otp-c input:focus{outline:none;border-color:rgba(143,184,255,.9);
  background:rgba(255,255,255,.09);box-shadow:0 0 0 4px rgba(124,92,255,.18),
  0 0 24px rgba(124,92,255,.28);transform:translateY(-2px)}
.otp-c.filled input{border-color:rgba(143,184,255,.55);background:rgba(124,92,255,.13)}
/* 커서 — 빈 칸에만 깜빡임 */
.otp-c .car{position:absolute;left:50%;top:50%;width:2px;height:24px;margin-left:-1px;
  margin-top:-12px;background:#8FB8FF;border-radius:2px;opacity:0;pointer-events:none}
.otp-c.on:not(.filled) .car{animation:otpCar 1.05s step-end infinite}
@keyframes otpCar{0%,49%{opacity:1}50%,100%{opacity:0}}
/* 입력 시 팝 */
.otp-c.pop input{animation:otpPop .26s cubic-bezier(.2,1.5,.4,1)}
@keyframes otpPop{0%{transform:scale(1)}45%{transform:scale(1.14)}100%{transform:scale(1)}}

/* 오류 — 흔들림 */
.otp.err{animation:otpShake .42s cubic-bezier(.36,.07,.19,.97)}
.otp.err .otp-c input{border-color:rgba(255,107,117,.85);background:rgba(240,68,82,.14)}
@keyframes otpShake{10%,90%{transform:translateX(-2px)}20%,80%{transform:translateX(4px)}
  30%,50%,70%{transform:translateX(-7px)}40%,60%{transform:translateX(7px)}}

/* 성공 — 숫자가 사라지고 체크가 그려진다 */
.otp.ok .otp-c input{color:transparent;border-color:rgba(42,207,154,.7);
  background:rgba(42,207,154,.14);transition:all .3s ease}
.otp.ok .otp-c .car{display:none}
.otp-ck{position:absolute;inset:0;display:grid;place-items:center;opacity:0;pointer-events:none}
.otp.ok .otp-ck{opacity:1}
.otp-ck svg{width:22px;height:22px}
.otp-ck path{stroke:#2ACF9A;stroke-width:2.6;fill:none;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:26;stroke-dashoffset:26}
.otp.ok .otp-ck path{animation:otpDraw .34s cubic-bezier(.2,.8,.3,1) forwards}
.otp.ok .otp-c:nth-child(1) .otp-ck path{animation-delay:0s}
.otp.ok .otp-c:nth-child(2) .otp-ck path{animation-delay:.05s}
.otp.ok .otp-c:nth-child(3) .otp-ck path{animation-delay:.1s}
.otp.ok .otp-c:nth-child(4) .otp-ck path{animation-delay:.15s}
.otp.ok .otp-c:nth-child(5) .otp-ck path{animation-delay:.2s}
.otp.ok .otp-c:nth-child(6) .otp-ck path{animation-delay:.25s}
@keyframes otpDraw{to{stroke-dashoffset:0}}

.otp-hint{font-size:12px;color:rgba(255,255,255,.4);text-align:center;
  font-variant-numeric:tabular-nums;min-height:18px}
.otp-hint b{color:#8FB8FF}
.otp-hint.warn b{color:#FF9F6B}
.otp-hint.bad{color:#FF9F6B}
@media (prefers-reduced-motion:reduce){
  .otp-c input,.otp.err,.otp-c.pop input,.otp.ok .otp-ck path{animation:none!important}
  .otp-c .car{animation:none;opacity:1}
}

/* ═══════════ OTP 카드 ═══════════ */50%{transform:translateY(-7px)}}
/* 성공 시 카드 전체가 초록으로 */

#otpcard.done .ob-btn{background:linear-gradient(148deg,#2ACF9A,#12A87C);
  box-shadow:0 4px 16px rgba(42,207,154,.42)}

/* 오브 아래 태그라인 — 한 줄씩 조용히 교대 */
.ob-tag{font-size:13px;color:rgba(255,255,255,.42);letter-spacing:-.02em;text-align:center;
  margin-top:-4px;line-height:1.5;min-height:2.2em;max-width:20em;margin-left:auto;margin-right:auto;
  word-break:keep-all;overflow-wrap:break-word;
  display:flex;align-items:center;justify-content:center}
.ob-tag i{font-style:normal;display:block;
  transition:opacity .34s ease, transform .34s cubic-bezier(.32,.72,0,1)}
.ob-tag i.out{opacity:0;transform:translateY(-5px)}

/* 안내 — 입력창 바로 위에 붙어 아래를 가리키는 한 줄 */
.tipwrap{display:flex;flex-direction:column;gap:9px;width:100%}
.tip{position:relative;align-self:flex-start;max-width:100%;
  padding:8px 12px;border-radius:11px;background:rgba(124,92,255,.15);
  border:.5px solid rgba(143,184,255,.2);font-size:11.5px;line-height:1.45;
  letter-spacing:-.01em;color:rgba(255,255,255,.62)}
.tip b{color:#C7D6FF;font-weight:600}
.tip::after{content:'';position:absolute;left:20px;bottom:-4px;width:8px;height:8px;
  background:rgba(124,92,255,.15);border-right:.5px solid rgba(143,184,255,.2);
  border-bottom:.5px solid rgba(143,184,255,.2);transform:rotate(45deg)}

/* 구분선 */
.ob-or{display:flex;align-items:center;gap:12px;margin:2px 0;width:100%}
.ob-or::before,.ob-or::after{content:'';flex:1;height:1px;background:rgba(255,255,255,.09)}
.ob-or span{font-size:11px;color:rgba(255,255,255,.28);letter-spacing:-.01em}

/* 번호 연결 잠금 카드 */
.lk-row{display:flex;gap:8px;align-items:stretch;margin-top:4px}
.lk-f{flex:1;min-width:0;padding:12px 14px;font-size:15px;letter-spacing:-.02em;
  border-radius:13px;background:var(--surface-2);border:.5px solid var(--line);
  color:var(--ink);font-variant-numeric:tabular-nums}
.lk-f::placeholder{color:var(--ink-4)}
.lk-f:focus{border-color:var(--blue);box-shadow:0 0 0 3px rgba(49,130,246,.18);outline:none}
.lk-b{flex:none;padding:0 18px;font-size:14px;font-weight:700;letter-spacing:-.02em;
  border-radius:13px;background:var(--blue);color:#fff;transition:opacity .18s,transform .12s}
.lk-b:active{transform:scale(.97)}
.lk-b:disabled{opacity:.35}

/* 소셜 — Apple 가이드라인상 로고 + 텍스트가 필요하다. 아이콘 단독은 쓰지 않는다 */
.sso{display:flex;flex-direction:column;gap:8px;width:100%}
.sso-b{width:100%;height:48px;border-radius:14px;
  display:flex;align-items:center;justify-content:center;gap:9px;
  font-size:14.5px;font-weight:600;letter-spacing:-.024em;
  transition:transform .12s,opacity .2s}
.sso-b:active{transform:scale(.985)}
.sso-b:disabled{opacity:.5}
.sso-b.g{background:rgba(255,255,255,.94);color:#1F1F1F}
.sso-b.a{background:#000;color:#fff;border:.5px solid rgba(255,255,255,.22)}
.sso-c{font-size:11.5px;color:rgba(255,255,255,.3);text-align:center;letter-spacing:-.01em;
  line-height:1.55}

/* ═══════════ 앱 내부 UI ═══════════
   771580a 커밋에서 실수로 지워졌던 구간. 온보딩을 지나면 쓰는 화면들이
   전부 여기에 기대고 있어서, 없으면 앱이 통째로 무너져 보인다. */

@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}
@keyframes pop{from{opacity:0;transform:translateY(8px) scale(.97)}}

/* ── 대화 ── */
.thread{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:12px 20px 14px;
  display:flex;flex-direction:column;justify-content:flex-end;gap:0;min-height:0}
.thread>*{flex:none}
/* 날짜는 카톡처럼 가운데 알약으로 */
/* 날짜는 대화가 아니다. 상자를 씌우면 말풍선이 하나 더 있는 것처럼 보인다.
   글자만 작게 — 눈이 훑고 지나가면 그걸로 충분하다. */
.day{font-size:11.5px;font-weight:500;color:var(--ink-3);text-align:center;margin:20px auto 10px;
  font-variant-numeric:tabular-nums;letter-spacing:.01em;align-self:center;width:max-content}
/* 한 사람이 연달아 말하면 한 묶음으로 본다.
   사진과 이름은 묶음 맨 위에 한 번, 시간은 마지막 말풍선 옆에 한 번. */
.row{display:flex;align-items:flex-start;gap:8px;max-width:100%;margin-top:4px}
.row.me{justify-content:flex-end}
.row+.row{margin-top:10px}
.av-c{flex:none;border-radius:50%;overflow:hidden}
.grp{display:flex;flex-direction:column;gap:3px;min-width:0;max-width:calc(100% - 50px)}
.row.me .grp{align-items:flex-end;max-width:78%}
.bl{display:flex;align-items:flex-end;gap:5px;max-width:100%}
.row.me .bl{flex-direction:row-reverse}
.bub{padding:10px 14px;font-size:15.5px;line-height:1.52;letter-spacing:-.018em;min-width:0;
  word-break:keep-all;overflow-wrap:break-word;white-space:pre-wrap;
  animation:pop .28s cubic-bezier(.32,.72,0,1) both}
.row.you .bl+.bl .bub{border-top-left-radius:16px}
.row.me .bl+.bl .bub{border-top-right-radius:16px}
/* 말풍선에 그림자를 넣으면 대화가 아니라 「떠 있는 카드」가 된다.
   상대 말은 바탕에 살짝 얹힌 정도로만 — 그림자 없이 색 하나로 구분한다. */
.row.you .bub{background:var(--bub-you);-webkit-backdrop-filter:blur(12px) saturate(150%);
  backdrop-filter:blur(12px) saturate(150%);border:.5px solid rgba(255,255,255,.5);
  border-radius:6px 17px 17px 17px}
.row.me .bub{background:var(--bub-me);
  color:#fff;border:0;border-radius:17px 6px 17px 17px}
:root[data-theme=dark] .row.you .bub,
:root[data-theme=dark] .typing{border-color:rgba(255,255,255,.08)}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .row.you .bub,
  :root:not([data-theme=light]) .typing{border-color:rgba(255,255,255,.08)}}
.meta{font-size:11px;color:var(--ink-4);font-variant-numeric:tabular-nums;flex:none;
  padding-bottom:2px;white-space:nowrap}
.meta b{color:var(--blue);font-weight:700}
.sys{font-size:12px;color:var(--ink-4);text-align:center;padding:6px 0}
.typing{display:flex;gap:4px;align-items:center;padding:11px 14px;align-self:flex-start;
  background:var(--bub-you);border-radius:6px 17px 17px 17px;border:.5px solid rgba(255,255,255,.5)}
.typing i{width:5px;height:5px;border-radius:50%;background:var(--ink-4);display:block;
  animation:blink 1.2s ease-in-out infinite}
.typing i:nth-child(2){animation-delay:.16s} .typing i:nth-child(3){animation-delay:.32s}
@keyframes blink{0%,60%,100%{opacity:.3;transform:translateY(0)}30%{opacity:1;transform:translateY(-2px)}}

/* ── 입력줄 ── */
/* 입력줄은 화면 맨 아래에 붙는다. 아래에 아무것도 없으니
   아이폰 홈 막대에 깔리지 않게 그만큼을 직접 비워 준다. */
.comp{display:flex;align-items:flex-end;gap:9px;flex:none;
  padding:10px 14px calc(10px + var(--safe-b));
  border-top:.5px solid var(--line);position:relative;z-index:5}
/* 입력줄 왼쪽 + 는 뒤로가기 모양을 빌려 쓴다. 그 음수 여백을 여기서 되돌린다 —
   안 그러면 화면 끝에 붙어서 잘린 것처럼 보인다. */
.comp .ab-back{margin-left:-6px;color:var(--ink-3);border-radius:12px}
.comp .ab-back:active{background:var(--surface-3)}
.comp-f{flex:1;background:var(--surface-3);border-radius:20px;padding:10px 15px;min-width:0;
  border:.5px solid var(--line-2);display:flex;align-items:center}
.comp-f textarea{width:100%;font-size:15px;line-height:1.45;letter-spacing:-.018em;resize:none;
  max-height:96px;min-height:21px;display:block}
.comp-f textarea::placeholder{color:var(--ink-4)}
.send{width:40px;height:40px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--bub-me);color:#fff;transition:transform .12s,opacity .15s}
/* 쓸 게 없을 때는 파랑을 아예 지운다. 흐린 파랑은 「고장난 파랑」으로 보인다. */
.send:disabled{background:var(--surface-3);color:var(--ink-4);opacity:1}
.send:active:not(:disabled){transform:scale(.92)}
.ab-back:active,.ab-a button:active{transform:scale(.9)}
.ab-back,.ab-a button{transition:transform .12s,background .12s}
.send:active:not(:disabled){transform:scale(.9)}

/* ── 아래 탭 ──
   진짜로 떠 있다. 줄 한 칸을 차지하지 않고 화면 위에 얹힌다 —
   그래서 아래쪽에 색 깔린 띠(푸터)가 아예 없고, 목록이 알약 밑으로 지나간다.
   대화창에는 이 알약이 없으므로 입력줄과 겹칠 일도 없다.
   가려지는 만큼은 .body.pad-nav::after 가 끝에 빈 칸으로 채워 준다.
   글자는 없앴다. 다섯 칸이 똑같이 나뉘고, 글림 구슬도 그 한 칸 안에 같은 높이로 앉는다. */
.tabbar{position:absolute;left:0;right:0;bottom:calc(6px + var(--safe-b) * .6);
  z-index:20;display:flex;align-items:center;
  margin:0 14px;padding:5px 6px;border-radius:24px;
  transform-origin:50% 100%;
  /* 들어갈 때도 나올 때도 천천히 시작해 천천히 멈춘다.
     한쪽만 부드러우면 「띡」 하고 튀는 느낌이 남는다.
     돌아오는 쪽을 조금 더 길게 둬서 손을 뗀 뒤 관성처럼 느긋하게 제자리로 간다. */
  transition:transform .42s cubic-bezier(.33,0,.15,1),opacity .42s cubic-bezier(.33,0,.15,1)}
/* will-change:transform 을 알약에 걸면 안 된다.
   알약이 자기만의 층으로 떠 버려서, 그 안의 흐림이 「뒤에 있는 목록」을 못 본다.
   유리가 여태 한 번도 흐려지지 않았던 진짜 원인이 이 한 줄이었다.
   움직이는 동안에만 올려 두기도 해 봤는데, 그러면 작아졌다 커질 때 유리가
   갑자기 뿌예졌다 맑아진다. 크기와 상관없이 늘 똑같이 비치는 쪽을 택했다. */
.tab-in{position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  /* 흐림·색은 여기서 한다. 안쪽 자식(.tab-glass)에 걸면 뒤가 안 보여서 흐림이 통째로 무시된다.
     밝을 때와 어두울 때는 아예 다른 유리다 —
     밝을 때는 하얗게 빛을 머금은 젖빛, 어두울 때는 뒤를 눌러 담는 짙은 유리. */
  -webkit-backdrop-filter:var(--nav-blur);
  backdrop-filter:var(--nav-blur);
  background:var(--nav-bg);
  overflow:hidden}
/* ── 가장자리 한 줄 ──
   전에는 여기에 반사광(빗금 그라데이션)을 깔았다. 그게 오히려 뿌옇게 만들었다 —
   유리 위에 흰 칠을 한 겹 더 얹은 셈이라, 흐림이 아니라 「흰 판」으로 보였다.
   지금은 반사광을 다 뺐다. 대신 테두리 한 줄만 두르고,
   그 줄을 위·아래에서만 보이게 가린다(mask). 옆면은 사라진다.
   진짜 유리는 위아래 모서리에서만 빛이 몰리기 때문이다.
   (같은 방식: showniverse 홈 메뉴 인디케이터) */
/* 가운데는 맑아야 한다. 뭉개면 그게 그냥 배경이 돼서 유리로 안 읽힌다.
   그래서 두꺼운 흐림은 이 한 장으로 떼어내 가장자리(위·아래·양끝)에만 남긴다. */
.tab-in::before{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  -webkit-backdrop-filter:var(--nav-edge-blur);backdrop-filter:var(--nav-edge-blur);
  -webkit-mask:
    linear-gradient(180deg,transparent 0,#000 7px,#000 15px,transparent 30px),
    linear-gradient(0deg,transparent 0,#000 7px,#000 15px,transparent 30px),
    linear-gradient(90deg,#000 0,#000 6px,transparent 22px),
    linear-gradient(270deg,#000 0,#000 6px,transparent 22px);
  mask:
    linear-gradient(180deg,transparent 0,#000 7px,#000 15px,transparent 30px),
    linear-gradient(0deg,transparent 0,#000 7px,#000 15px,transparent 30px),
    linear-gradient(90deg,#000 0,#000 6px,transparent 22px),
    linear-gradient(270deg,#000 0,#000 6px,transparent 22px);
  -webkit-mask-composite:source-over;mask-composite:add}
.tab-in::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--nav-lens);
  -webkit-mask:linear-gradient(180deg,#000 0%,transparent 46%,transparent 54%,#000 100%);
  mask:linear-gradient(180deg,#000 0%,transparent 46%,transparent 54%,#000 100%)}
/* 그림자를 크게 퍼뜨리면 알약 둘레가 안개처럼 뿌예진다.
   흐림을 6px 로 줄여도 「여전히 블러가 심하다」로 보였던 게 실은 이 안개였다.
   지금은 바닥에 가깝게, 짧고 진하게만 깐다 — 떠 있는 건 알겠고 뿌옇지는 않다. */
/* ── 위·아래 빛 한 줄 ──
   유리의 「두께」는 이 줄이 만든다. 맨 끝은 어둡게 눌리고,
   바로 안쪽에서 빛이 한 줄로 모여 맺힌다. 어둡고→밝고, 그 두 줄이다.
   여기에 흐림은 걸지 않는다. 알약 본체가 이미 흐리므로
   여기서 또 흐리면 흐림이 두 겹으로 쌓여 테두리가 뿌옇게 번진다. */
/* 상자를 알약과 똑같은 크기로 둔다.
   전에는 높이를 18% 로 줄이고 라운드 24px 을 줬는데,
   라운드가 높이보다 크면 브라우저가 라운드를 통째로 깎아 버린다(10px 쯤 된다).
   그래서 이 줄만 알약보다 덜 휘어서 모서리 밖으로 넘어갔다.
   지금은 상자를 키워 라운드를 그대로 살리고, 띠는 mask 로만 잘라 낸다. */
.tab-lens{position:absolute;inset:0;max-width:none;border-radius:inherit;
  pointer-events:none;z-index:0}
.tab-lens.t{
  /* 맨 끝은 유리가 제일 두껍다. 빛이 다 꺾여 나가 어둡게 눌리고,
     바로 안쪽에서 그 빛이 한 줄로 모여 맺힌다. 어둡고→밝고 이 두 줄이 「두께」다. */
  background:linear-gradient(180deg,var(--lens-edge) 0,var(--lens-hot) 1.4px,transparent 4.5px);
  -webkit-mask:linear-gradient(180deg,#000 0,rgba(0,0,0,.8) 2.5px,rgba(0,0,0,.24) 6px,transparent 11px);
  mask:linear-gradient(180deg,#000 0,rgba(0,0,0,.8) 2.5px,rgba(0,0,0,.24) 6px,transparent 11px)}
.tab-lens.b{
  background:linear-gradient(0deg,var(--lens-edge) 0,var(--lens-hot) 1.4px,transparent 4.5px);
  -webkit-mask:linear-gradient(0deg,#000 0,rgba(0,0,0,.8) 2.5px,rgba(0,0,0,.24) 6px,transparent 11px);
  mask:linear-gradient(0deg,#000 0,rgba(0,0,0,.8) 2.5px,rgba(0,0,0,.24) 6px,transparent 11px)}
/* 굴절(displacement)은 뺐다.
   지도를 여덟 판 고쳐 봤지만 어떻게 맞춰도 「억지로 비튼 것」으로 보였다.
   진짜 유리는 뒤에 무늬가 있어야 휜 게 보이는데, 이 앱 뒤는 대개 단색 카드다.
   무늬가 없으면 아무리 밀어도 색이 그대로고, 보이게 세게 밀면 글자가 뭉갠다.
   그 사이에 「적당한 값」이 없다. 그래서 흐림 하나로 간다.
   (필터 정의는 index.html 에 남겨 뒀다. 모달 쪽 #gl-sheet 가 아직 쓴다.) */
/* 시트 뒤 화면이 시트 테두리에서 휜다 — 시트 자신은 #app 밖이라 안 휜다 */
#app.slens{filter:url(#gl-sheet)}
.tabbar{box-shadow:0 .5px 1px rgba(25,31,40,.13),
  0 3px 7px -3px rgba(25,31,40,.16),
  0 8px 18px -10px rgba(25,31,40,.18)}
/* 유리는 알약 자체가 아니라 그 안에 깔린 한 장이다.
   물방울이 유리를 「덮은」 채로 움직이면 사파리가 매 칸마다 뒤를 다시 흐리게 계산한다 —
   그게 버벅임의 진짜 원인이었다. 유리를 따로 떼어 두면 물방울만 따로 움직인다. */
.tab-glass{position:absolute;inset:0;border-radius:inherit;box-sizing:border-box;pointer-events:none;
  /* 테두리 그라데이션은 뺐다. 위 .tab-in::after 가 이미 가장자리 한 줄을 맡는다.
     두 겹이 겹치면 그만큼 하얘져서 「불투명한 판」이 된다.
     여기 남는 건 두께감을 주는 안쪽 그림자 두 줄과, 바닥에서 떼어 주는 실선 한 겹뿐이다. */
  box-shadow:inset 0 1px 0 var(--nav-lens-2),
    inset 0 -1px 0 var(--nav-floor),
    0 0 0 .5px var(--nav-hair)}
/* 고르는 칸을 따라 흐르는 물방울. 다섯 칸이 정확히 같은 너비다.
   어디에 멈춰 있을지만 여기서 정하고, 흘러가는 그림은 app.js(tabFlowRun)가 그린다.
   유리로 만들면 알약 유리 위에 유리가 한 겹 더 얹혀서 뭐가 켜졌는지 안 보인다.
   그래서 그냥 회색 자국 하나다 — 빛도 테두리도 그림자도 없다. */
.tab-drop{position:absolute;left:6px;top:5px;bottom:5px;width:calc((100% - 12px)/4);
  border-radius:19px;opacity:0;pointer-events:none;
  background:rgba(25,31,40,.075);
  transition:opacity .2s}
/* 떨어져 나가는 한 방울. 칸 한가운데 앉은 작은 알약이고,
   움직일 때 app.js 가 이걸 앞으로 튕겨 보냈다가 도착한 자국에 도로 합친다.
   그림자·흐림은 안 쓴다 — 움직이는 내내 다시 그려서 버벅인다. */
.tab-tail{position:absolute;left:6px;top:calc(50% - 9px);height:18px;
  width:calc((100% - 12px)/4);border-radius:99px;opacity:0;pointer-events:none;
  background:rgba(25,31,40,.11);
  /* 99px 같은 큰 수를 쓰면 안 된다. 높이(18px)보다 커서 브라우저가 넘치는 만큼
     가로 반지름까지 같이 깎는다 — 그래서 각진 상자가 됐다.
     반반(50%)이면 언제나 딱 맞는 타원이라, 가로로 눌러도 끝이 동그랗다. */
  border-radius:50%}
/* 스크롤할 때는 살짝 작아져서 뒤로 물러난다. 손가락이 지나갈 자리를 비켜 준다 */
.tabbar.small{transform:scale(.86) translateY(3px);
  transition:transform .26s cubic-bezier(.4,0,.2,1)}
/* 아이폰 탭바가 하는 두 가지: 내리면 작아지고, 멈추면(=올리면) 커지면서
   색을 조금 더 머금는다. 크기만 바뀌면 그냥 작아진 판으로 보인다. */
.tab-in{transition:background .3s cubic-bezier(.33,0,.15,1)}
.tabbar:not(.small) .tab-in{background:var(--nav-bg-big)}
.tabbar[data-tab="sort"] .tab-drop,.tabbar[data-tab="talk"] .tab-drop,
.tabbar[data-tab="week"] .tab-drop,.tabbar[data-tab="settings"] .tab-drop{opacity:1}
/* 유리를 맑게 하니 뒤가 다 비친다 — 그만큼 아이콘이 배경에 묻힌다.
   색을 한 단계 진하게 쓰고, 아이콘 뒤에 옅은 그림자를 깔아 어떤 배경에서도 읽히게 한다. */
.tab{flex:1 1 0;min-width:0;display:flex;align-items:center;justify-content:center;
  height:48px;color:var(--ink-2);position:relative;z-index:1;
  filter:drop-shadow(0 0 3px var(--nav-icon-halo));
  transition:color .2s,transform .18s cubic-bezier(.3,1.4,.5,1)}
/* ── 보이지 않는 손가락 칸 ──
   엄지는 아이콘 한가운데를 못 짚는다. 늘 조금씩 아래로·바깥으로 흐른다.
   그런데 여태 닿는 데가 아이콘 언저리뿐이라, 살짝만 빗나가도 아무 데도 안 닿아
   「안 눌린다」가 됐다. 이제 알약 한 칸이 통째로 단추다 — 빈 데가 없다.
   옆칸끼리 6px 씩 겹쳐 두어서 경계에 죽은 틈이 안 생긴다.
   그림(아이콘)은 그대로라 눈에는 아무 변화가 없다.
   아래로 6px 만 여는 이유: 그보다 더 내려가면 앱 바깥이라 어차피 잘린다. */
.tab::before{content:'';position:absolute;left:-3px;right:-3px;top:-13px;bottom:-9px}
/* 맨 끝 두 칸은 화면 가장자리 쪽으로 더 크게 연다. 손이 늘 그쪽으로 흐른다. */
.tab:first-of-type::before{left:-20px}
.tab:last-of-type::before{right:-20px}
/* ── 렌즈가 밀어낸다 (splay) ──
   --d 는 이 칸이 켜진 칸에서 몇 칸 떨어졌나. 지금은 쓰는 데가 없지만
   나중에 칸별로 뭘 달리 하려면 여기서 꺼내 쓴다. */
.tab{--d:calc(var(--i,0) - var(--a,0))}
/* 아이콘은 안 휜다.
   전에 여기서 아이콘을 밀고 눌렀는데, 그건 거꾸로였다 —
   유리가 휘게 만드는 건 「유리 뒤에 지나가는 것」이지 「유리 위에 인쇄된 것」이 아니다.
   아이콘은 알약 표면에 찍힌 글자다. 휘어야 하는 건 그 밑을 지나가는 목록이다.
   그 일은 위쪽 .tab-lens 두 장이 맡는다. */
/* 켜진 칸은 색으로 말한다. 지금 어디 있는지 한눈에 보여야 한다. */
.tab.on{color:var(--tab-on)}
.tab:active{transform:scale(.9)}
/* 선 굵기 1.7. 2 면 24px 안에서 획이 서로 붙어 뭉툭한 도장처럼 보인다.
   요즘 앱 아래줄은 다 이 얇기다 — 얇을수록 켜졌을 때 「속이 찬」 아이콘과 대비가 크다. */
.tab svg{width:24px;height:24px;stroke-width:1.7}
/* 속이 찬 짝은 획이 없다. 굵기 규칙이 남아 있으면 면 둘레에 테가 한 겹 더 생긴다. */
.tab svg[fill="currentColor"]{stroke-width:0}
.fab{width:52px;height:52px;border-radius:50%;position:relative;display:grid;place-items:center}
.fab-i{width:52px;height:52px;display:grid;place-items:center}
.fab-i svg{width:100%;height:100%}
.badge{position:absolute;top:-25px;right:8px;min-width:18px;height:18px;border-radius:99px;
  background:var(--stop);color:#fff;font-size:10px;font-weight:700;display:grid;place-items:center;
  padding:0 5px;border:2px solid var(--surface);font-variant-numeric:tabular-nums;z-index:2;
  animation:badgePop .28s cubic-bezier(.2,1.5,.4,1) both}
@media (prefers-reduced-motion:reduce){
  .tab svg{transition:none}
  .tabbar{transition:none}
  .tab-drop{transition:none}
  .tab-tail{display:none}
  .tabbar.small{transform:none}
}
@media (prefers-reduced-transparency:reduce){
  .tab-in{backdrop-filter:none;-webkit-backdrop-filter:none;background:var(--surface)}
  .tab-in::after{display:none}
  .tab-lens{display:none}
  .body.lens{filter:none}
  #app.slens{filter:none}
  .tab-glass{box-shadow:0 0 0 1px var(--line)}
  .tab-drop{background:var(--surface-3)}
}
/* 어두울 때. 유리 자체(--nav-*)는 토큰이 이미 갈라 놨다.
   여기서는 그림자와 「켜진 칸 자국」만 어둠에 맞춘다. */
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .tab-drop{
  background:rgba(255,255,255,.13)}}
:root[data-theme=dark] .tab-drop{
  background:rgba(255,255,255,.13)}
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .tabbar{
  box-shadow:0 1px 2px rgba(0,0,0,.52),0 4px 10px -4px rgba(0,0,0,.5),
    0 10px 22px -12px rgba(0,0,0,.55)}}
:root[data-theme=dark] .tabbar{
  box-shadow:0 1px 2px rgba(0,0,0,.52),0 4px 10px -4px rgba(0,0,0,.5),
    0 10px 22px -12px rgba(0,0,0,.55)}
/* 떨어져 나간 방울도 어두울 때는 옅은 흰 회색 */
@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .tab-tail{
  background:rgba(255,255,255,.15)}}
:root[data-theme=dark] .tab-tail{
  background:rgba(255,255,255,.15)}

@keyframes badgePop{from{opacity:0;transform:scale(.3)}}

/* ── 밀어서 지우기 ──
   줄을 왼쪽으로 밀면 오른쪽에서 단추가 줄 위로 미끄러져 들어온다.
   줄은 제자리에 있어서 누구를 지우는지 끝까지 보인다. */
.sw{position:relative;overflow:hidden;touch-action:pan-y}
.sw-bg{position:absolute;top:0;bottom:0;right:0;z-index:2;display:flex;align-items:stretch;
  will-change:transform}
.sw-bg button{width:78px;border:0;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:3px;font-size:11.5px;font-weight:600;letter-spacing:-.02em;
  color:#fff;cursor:pointer}
.sw-bg .sw-keep{background:var(--blue)}
.sw-bg .sw-del{background:var(--stop)}
.sw-bg svg{width:17px;height:17px}
.sw-fg{position:relative;will-change:transform}
.sw.snap .sw-bg{transition:transform .22s cubic-bezier(.2,.8,.3,1)}

/* 글줄 한 줄 — 상자도 실선도 없다. 아바타 크기와 여백만으로 나눈다 */
.row-l{display:flex;align-items:center;gap:13px;padding:10px 6px;width:100%;
  text-align:left;background:none;border:0;border-radius:14px}
.row-l:active{background:var(--surface-3)}
/* 아바타는 줄의 기둥이다. 작으면 목록에 리듬이 안 생긴다 */
/* 첫 글자만 있는 줄은 회색 네모 대신 옅은 파란 동그라미.
   네모가 줄줄이 서면 목록이 격자처럼 보여서 무겁다. */
.rl-av{width:52px;height:52px;flex:none;border-radius:50%;display:grid;place-items:center;
  font-size:18px;font-weight:600;background:var(--surface-3);color:var(--ink-3);overflow:hidden}
/* 오브가 들어오면 배경을 아예 없앤다. 오브는 그 자체로 얼굴이라
   뒤에 상자를 깔면 「그림 위에 그림」이 된다.
   캔버스로 그릴 때는 .orbwrap 이 감싸므로 그것도 같이 본다. */
.rl-av:has(svg),.rl-av:has(canvas),.rl-av:has(.orbwrap){
  background:none;border-radius:0;overflow:visible}
/* 오브는 후광까지 그려서 실제 알맹이가 작다. 칸보다 크게 그리고 가운데로 겹친다 */
.rl-av>svg{width:68px;height:68px;margin:-8px}
.row-l .rl-b{min-width:0;flex:1}
.rl-t{font-size:16px;font-weight:600;letter-spacing:-.028em;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rl-s{font-size:13px;color:var(--ink-3);margin-top:2px;line-height:1.4;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
/* 오른쪽 칸 — 위에 시각, 아래에 안 읽은 수 */
.rl-r{flex:none;margin-left:auto;align-self:stretch;display:flex;flex-direction:column;
  align-items:flex-end;justify-content:center;gap:6px;padding-left:8px}
/* 이름만 있는 한 줄짜리 — 얼굴을 조금 줄여 목록이 덜 무겁게 */
.row-l.one{padding:5px 6px;gap:12px}
.row-l.one .rl-av{width:40px;height:40px;border-radius:50%;font-size:15px;font-weight:600}
.rl-time{font-size:11.5px;color:var(--ink-4);white-space:nowrap;font-variant-numeric:tabular-nums}
.rl-n{min-width:19px;height:19px;padding:0 5px;border-radius:99px;background:var(--blue);
  color:#fff;font-size:11px;font-weight:700;display:grid;place-items:center;
  font-variant-numeric:tabular-nums}
/* 안 읽었으면 두 번 알린다 — 글자를 진하게, 그리고 동그라미 */
.row-l.un .rl-t{font-weight:700}
.row-l.un .rl-s{color:var(--ink-2)}
/* 숫자 없이 점 하나. 몇 개인지는 알 필요 없고 "왔다" 만 알면 된다 */
.rl-new{width:8px;height:8px;border-radius:99px;background:var(--blue);flex:none}
/* ── 대화 목록의 얼굴 ──
   여기 들어가는 건 그 사람 사진이다. 사진이 없으면 이름 첫 글자.
   :has(svg) 규칙이 배경을 지워 버리면 글자만 허공에 뜨므로, 이 칸은 규칙을 되돌린다. */
.rl-av.rl-face{background:var(--surface-3);border-radius:50%;overflow:hidden}
.rl-ph{width:100%;height:100%;object-fit:cover;display:block}
/* 그 사람의 글림. 얼굴 옆이 아니라 줄 끝에 조용히 앉는다 —
   있는지 없는지 궁금하면 보이지만, 이름을 읽는 데는 안 끼어든다. */
.rl-orb{flex:none;width:26px;height:26px;margin-left:9px;display:grid;place-items:center;
  opacity:.9}
.rl-orb>svg{width:34px;height:34px;margin:-4px}
.row-l.un .rl-orb{opacity:1}
/* ── 대화 목록 맨 위, 내 글림 한 줄 ──
   아래줄 가운데에 박혀 있던 구슬이 여기로 왔다.
   사람 목록과 같은 모양이라 「대화는 다 여기 있다」가 한눈에 읽히고,
   그 위에 얇은 밑선 하나만 그어서 이 줄만 늘 맨 위에 붙어 있다고 알린다.
   상자로 감싸거나 색을 깔면 광고 띠처럼 보인다 — 선 하나면 충분하다. */
.glimrow{margin:-4px 0 2px;padding-bottom:8px;border-bottom:.5px solid var(--line-2)}
/* 이 줄은 목록이 아니라 「고정」이다. 밀어서 지우기도 안 걸린다.
   구슬은 가로로 넓게 자라는 모양이라 세로가 남는다. 조금만 키워 사람 사진과 눈높이를 맞춘다. */
.row-l.pinned .rl-av{overflow:visible;background:none}
.row-l.pinned .orbwrap{width:58px!important;height:58px!important;margin:-3px}
/* 이름 옆 작은 이름표. 사람 이름과 헷갈리지 않게 「이건 내 글림」이라고 한 번 말해 준다. */
.rl-me{font-size:10.5px;font-weight:600;color:var(--blue);background:var(--blue-wash);
  border-radius:5px;padding:2px 5px;margin-left:5px;vertical-align:2px;letter-spacing:-.01em}
/* 탭 위의 점 — 배지처럼 숫자를 달면 아래 탭바가 시끄러워진다 */
.tab-dot{position:absolute;top:6px;right:calc(50% - 12px);width:6px;height:6px;
  border-radius:99px;background:var(--blue)}
/* 묶음 이름표 — 작은 회색 글씨 + 숫자 */
.sec-h{display:flex;align-items:baseline;gap:6px;padding:20px 6px 8px;
  font-size:12px;font-weight:600;color:var(--ink-3);letter-spacing:.01em}
/* 오른쪽에 붙는 손짓 안내는 이름표가 아니다. 같은 크기·같은 색이면 제목처럼 읽힌다. */
.sec-h>span{font-size:11.5px;color:var(--ink-4);letter-spacing:-.01em}
.sec-h b{color:var(--ink-4);font-weight:500;font-variant-numeric:tabular-nums}
/* 목록 위 안내 한 줄 — 배너 상자 대신 */
.list-hint{font-size:11.5px;color:var(--ink-3);padding:2px 6px 10px;letter-spacing:-.01em;word-break:keep-all}

/* ── 카드 · 목록 ── */
.card{border-radius:16px;padding:16px}
.list{display:flex;flex-direction:column;gap:2px}
/* ── 정리 목록을 카드로 보기 ──
   한 줄에 두 개. 색은 이름에서 뽑아서 늘 같은 색이 나온다 — 얼굴처럼 기억된다.
   목록은 「훑는」 화면이고 카드는 「고르는」 화면이다. 그래서 카드는 밀어서 지우기를 안 건다. */
.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:2px 0}
.fcard{position:relative;aspect-ratio:1/1.12;border:0;border-radius:20px;overflow:hidden;
  display:flex;flex-direction:column;justify-content:flex-end;
  padding:14px;text-align:left;color:#fff;
  background:linear-gradient(150deg,var(--ca),var(--cb));
  box-shadow:0 1px 2px rgba(25,31,40,.1),0 8px 20px -14px rgba(25,31,40,.5);
  transition:transform .12s cubic-bezier(.2,.8,.3,1)}
.fcard:active{transform:scale(.965)}
/* 첫 글자를 크게 깔아 배경처럼 쓴다. 아바타 동그라미를 또 그리면 카드가 시끄럽다. */
.fc-i{position:absolute;top:-14px;right:2px;font-size:88px;font-weight:800;
  letter-spacing:-.06em;line-height:1;color:rgba(255,255,255,.26);pointer-events:none}
.fc-n{position:relative;font-size:15.5px;font-weight:700;letter-spacing:-.03em;
  text-shadow:0 1px 3px rgba(25,31,40,.28);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (prefers-reduced-motion:reduce){ .fcard{transition:none} .fcard:active{transform:none} }
.item{display:flex;align-items:center;gap:11px;padding:12px 14px;border-radius:14px;
  text-align:left;width:100%;transition:transform .1s}
.item:active{transform:scale(.985)}
.av{width:38px;height:38px;border-radius:13px;flex:none;display:grid;place-items:center;
  font-size:14px;font-weight:700;background:var(--surface-3);color:var(--ink-4);overflow:hidden}
/* 오브가 든 아바타는 자르지 않는다. 후광이 원 밖으로 번지는 게 오브의 생김새다 */
.av:has(svg){overflow:visible;background:none;border-radius:0}
img.av{object-fit:cover}
.av.b{background:var(--blue-wash);color:var(--blue)}
.it-b{min-width:0;flex:1}
.it-t{font-size:15px;font-weight:600;letter-spacing:-.028em;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.it-s{font-size:13px;color:var(--ink-3);margin-top:2px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.it-r{margin-left:auto;flex:none;display:flex;flex-direction:column;align-items:flex-end;gap:4px}
.tag{font-size:10.5px;font-weight:700;padding:3px 7px;border-radius:6px;white-space:nowrap}
.t-w{background:var(--warn-wash);color:var(--warn)}
.t-o{background:var(--ok-wash);color:var(--ok)}
.t-b{background:var(--blue-wash);color:var(--blue-ink)}
.time{font-size:11px;color:var(--ink-4);font-variant-numeric:tabular-nums}

/* ── 버튼 ── */
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip{font-size:13.5px;font-weight:600;padding:9px 15px;border-radius:99px;
  background:var(--surface-3);color:var(--ink-2);border:.5px solid var(--g-rim);
  transition:transform .1s,background .15s}
.chip:active{transform:scale(.96)}
/* 지우기 같은 되돌릴 수 없는 일은 단추처럼 보이면 안 된다.
   평소엔 조용한 글자, 누를 때만 빨갛게 — 대신 눌리는 칸은 44px 로 넉넉히. */
.quiet-d{align-self:center;margin-top:20px;min-height:44px;padding:0 16px;
  font-size:12.5px;font-weight:500;color:var(--ink-4);letter-spacing:-.01em;
  background:none;border:0;border-radius:12px}
.quiet-d:active{color:var(--stop);background:var(--stop-wash)}
/* 화면 맨 위 안내 한 줄. 카드를 씌우면 목록보다 커져서 주인공이 뒤바뀐다. */
.note-l{font-size:12.5px;color:var(--ink-3);line-height:1.6;word-break:keep-all;
  padding:2px 6px 14px}
/* 화면 맨 아래 깨알 설명. 가운데 정렬 + 좁은 폭이라 한글이 알아서 접힌다. */
.fine-p{font-size:11.5px;color:var(--ink-4);line-height:1.7;text-align:center;
  max-width:24em;margin:0 auto 8px;word-break:keep-all}
.chip.on,.chip.pri{background:var(--blue);color:#fff;border-color:transparent}
.chip.ghost{background:transparent;color:var(--blue);border:1px solid var(--blue)}
/* 신고할 때 "차단도 같이" — 체크박스는 손가락으로 누르기 어렵다. 줄 전체가 눌린다 */
.rblk{display:flex;align-items:center;gap:10px;padding:11px 2px;font-size:13.5px;
  color:var(--ink-2);cursor:pointer}
.rblk input{width:20px;height:20px;accent-color:var(--blue);flex:none}
.btn{padding:14px 20px;border-radius:14px;font-size:15px;font-weight:700;letter-spacing:-.024em;
  text-align:center;width:100%;transition:transform .1s,opacity .15s}
.btn:active{transform:scale(.98)}
.btn:disabled{opacity:.4}
.btn.pri{background:var(--blue);color:#fff}
.btn.sec{background:var(--surface-3);color:var(--ink-2)}

/* ── 구독 ── */
/* 세 칸을 나란히 놓지 않는다. 위아래로 쌓아서 하나씩 읽게 한다 */
.pl{border-radius:16px;padding:18px;background:var(--surface);border:.5px solid var(--line)}
.pl.on{border-color:var(--blue);background:var(--blue-wash)}
.pl-h{display:flex;align-items:center;gap:8px}
.pl-n{font-size:16px;font-weight:700;letter-spacing:-.034em}
.pl-cur{font-size:11px;font-weight:700;color:var(--blue-ink);background:var(--surface);
  border-radius:99px;padding:3px 9px}
.pl-p{font-size:23px;font-weight:800;letter-spacing:-.04em;margin-top:6px;
  font-variant-numeric:tabular-nums}
.pl-u{font-size:13px;font-weight:600;color:var(--ink-4);margin-left:3px}
.pl-l{margin-top:12px;font-size:13px;color:var(--ink-3);line-height:1.85;word-break:keep-all}
/* 한도 안내 — 대화 흐름 안에 조용히 놓는다. 덮지 않는다 */
.pw{margin:16px 12px 4px;padding:16px;border-radius:16px;
  background:var(--surface-2);border:.5px solid var(--line)}
.pw-t{font-size:14.5px;font-weight:700;letter-spacing:-.03em}
.pw-d{font-size:12.5px;color:var(--ink-3);line-height:1.6;margin-top:5px;word-break:keep-all}
.pw-s{font-size:12px;color:var(--ink-3);text-align:center;padding:0 18px 6px}

/* ── 이번 주 3명 ── */
/* 아바타 자리는 비워 둔다. 채우면 그게 곧 얼굴이 된다 */
.wk{border-radius:16px;padding:16px;background:var(--surface);border:.5px solid var(--line)}
.wk-h{display:flex;align-items:center;gap:12px}
.wk-a{width:44px;height:44px;border-radius:15px;flex:none;display:grid;place-items:center;
  background:var(--surface-3);color:var(--ink-4)}
.wk-a svg{width:22px;height:22px;stroke-width:1.6}
.wk-t{font-size:15.5px;font-weight:700;letter-spacing:-.03em}
.wk-s{font-size:13px;color:var(--ink-3);margin-top:2px;font-variant-numeric:tabular-nums}
/* 남기기를 고른 뒤 — 상대가 뭘 골랐는지는 여기 절대 안 나온다 */
.wk-w{font-size:12.5px;color:var(--ink-3);line-height:1.6;padding:12px 14px;border-radius:12px;
  background:var(--surface-3);word-break:keep-all}

/* ── 알림줄 · 빈 화면 ── */
.banner{padding:13px 15px;border-radius:14px;margin-bottom:4px}
.bn-b{background:var(--blue-wash);border:.5px solid var(--blue)}
.bn-t{font-size:13.5px;font-weight:700;color:var(--blue-ink)}
.bn-d{font-size:12px;color:var(--blue-ink);opacity:.8;margin-top:2px}
.empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:12px;text-align:center;padding:40px 24px}
/* 아무것도 없는 화면의 아이콘. 회색 상자를 깔면 「빈 칸이 하나 더」로 보인다.
   상자를 없애고 선만 옅게 남긴다. */
.empty-i{width:52px;height:52px;display:grid;place-items:center;
  background:none;color:var(--ink-4);opacity:.5}
.empty-i svg{width:38px;height:38px;stroke-width:1.4}
.empty-t{font-size:16px;font-weight:700;letter-spacing:-.03em}
.empty-d{font-size:13.5px;color:var(--ink-3);line-height:1.55;max-width:26ch;word-break:keep-all}
.sk{border-radius:12px;background:linear-gradient(90deg,var(--surface-3) 25%,var(--line-2) 50%,var(--surface-3) 75%);
  background-size:400px 100%;animation:shim 1.4s linear infinite}
@keyframes shim{0%{background-position:-200px 0}100%{background-position:260px 0}}

/* ── 올라오는 시트 ── */
.sheet-bg{position:fixed;inset:0;z-index:40;background:rgba(25,31,40,.28);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  animation:fade .28s ease both}
.sheet{position:fixed;left:0;right:0;bottom:0;z-index:41;border-radius:22px 22px 0 0;
  padding:12px 20px calc(24px + var(--safe-b));max-width:520px;margin:0 auto;
  animation:sheetIn .28s cubic-bezier(.32,.72,0,1) both}
.sheet.out{animation:sheetOut .12s ease-in-out both}
/* ── 시트도 알약과 같은 유리 ──
   흐림은 색만 뭉갠다. 뒤에 있는 것을 「휘게」 하지는 못한다 — 그래서 유리처럼 안 보였다.
   휘게 하는 건 feDisplacementMap 하나뿐이다(index.html #gl-sheet).
   흐림 한 장, 굴절 한 장, 빛 한 줄. 이 셋을 다른 층에 두는 게 핵심이다.
   한 장에 같이 두면 위 모서리를 맑게 뚫는 mask 가 빛줄까지 잘라 버린다. */
.sheet.g3{background:none;border:none;isolation:isolate;
  /* .g3 본체 흐림을 끈다. 안 끄면 두 겹이 돼서 토큰을 바꿔도 계속 뿌옇다. */
  -webkit-backdrop-filter:none;backdrop-filter:none;
  /* 빛줄·두께 모두 본체 한 겹에서 그린다. inset 이라 border-radius 를 따라 휜다. */
  box-shadow:inset 0 .4px 0 var(--lens-edge), inset 0 1.2px 0 var(--lens-hot),
    inset 0 5px 9px -7px var(--rim-in), inset 0 0 14px -6px var(--rim-in),
    0 -.5px 1px rgba(25,31,40,.1),0 -8px 28px -12px rgba(25,31,40,.22)}
/* (1) 틴트 한 장. 가운데는 거의 안 흐리다 —
   뭉개 놓으면 그게 그냥 배경이 돼 버려서, 투명해도 유리로 안 보인다.
   맨 위 2px 은 아예 건드리지 않는다. 흐린 데서는 굴절이 안 보인다. */
.sheet.g3::before{content:'';position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;z-index:0;
  -webkit-backdrop-filter:var(--sheet-core);backdrop-filter:var(--sheet-core);
  background:var(--sheet-bg);
  -webkit-mask:linear-gradient(180deg,transparent 0,transparent 1.2px,#000 2.4px);
  mask:linear-gradient(180deg,transparent 0,transparent 1.2px,#000 2.4px)}
/* (2) 두꺼운 흐림 한 장. 가장자리에만 남긴다 — 위·왼쪽·오른쪽 세 줄의 합집합.
   진짜 유리도 가장자리가 두꺼워서 거기만 뭉개진다. 판은 시트에 딱 맞아서(inset:0)
   테두리가 두 줄로 보이지 않는다. */
.sheet.g3::after{content:'';position:absolute;inset:0;border-radius:inherit;
  pointer-events:none;z-index:0;
  -webkit-backdrop-filter:var(--sheet-blur);backdrop-filter:var(--sheet-blur);
  -webkit-mask:
    linear-gradient(180deg,transparent 0,transparent 1.2px,#000 2.4px,#000 24px,transparent 66px),
    linear-gradient(90deg,#000 0,#000 12px,transparent 54px),
    linear-gradient(270deg,#000 0,#000 12px,transparent 54px);
  mask:
    linear-gradient(180deg,transparent 0,transparent 1.2px,#000 2.4px,#000 24px,transparent 66px),
    linear-gradient(90deg,#000 0,#000 12px,transparent 54px),
    linear-gradient(270deg,#000 0,#000 12px,transparent 54px);
  -webkit-mask-composite:source-over;mask-composite:add}
/* 굴절 판을 따로 두지 않는다.
   예전엔 시트보다 14px 큰 판을 한 장 더 깔았는데, 제 모서리(36px)가 시트 모서리(22px)와
   달라서 테두리가 두 줄로 보였다 — 유리가 두 겹처럼 보이던 원인.
   휘는 일은 #app.slens 가 전부 한다(app.js sheetLens). 두께는 위 box-shadow 안쪽 빛으로 낸다. */
/* 시트 안 내용은 빛 위에 올라온다 */
.sheet.g3>*{position:relative;z-index:1}
/* 손잡이는 잡을 수 있게 생겼으면 실제로 잡혀야 한다.
   시트를 세로로 끌 때 브라우저가 스크롤로 가로채지 않도록 막는다. */
.sheet{touch-action:pan-y}
.grab{position:relative}
.grab::after{content:'';position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:120px;height:34px}
.sheet-bg.out{animation:fade .12s ease reverse both}
@keyframes fade{from{opacity:0}}
@keyframes sheetIn{from{transform:translateY(12%) scale(.97);opacity:0;filter:blur(6px)}}
@keyframes sheetOut{to{transform:scale(1.03);opacity:0;filter:blur(12px)}}
.grab{width:36px;height:4px;border-radius:99px;background:var(--line);margin:0 auto 16px}

/* ── 짧은 알림 ── */
/* ── 당겨서 새로고침 ──
   인스타·카톡처럼 목록 자체가 아래로 밀려 내려가고, 그 위에 빈 자리가 드러난다.
   드러난 빈 자리 한가운데에 동그란 것이 앉는다.
   더 끌수록 진해지고 점 사이가 벌어지다가, 놓으면 튀기 시작한다.
   빙글 도는 원은 어느 앱에나 있다. 이 앱의 점은 이 앱 것이다. */

/* 목록이 통째로 내려간다. 끄는 동안은 손가락을 그대로 따라가야 하니 애니메이션을 끈다. */
.body.pull{transition:none;will-change:transform}
.body.pull-back{transition:transform .34s cubic-bezier(.22,1,.36,1)}

/* --top 은 제목줄 바로 아래. 드러난 빈 자리가 거기서부터 시작한다. */
.ptr{position:fixed;left:50%;top:var(--top,0px);z-index:19;
  width:30px;height:30px;margin-left:-15px;pointer-events:none;
  opacity:0;transform:translateY(0);
  transition:opacity .18s ease,transform .3s cubic-bezier(.22,1,.36,1)}
.ptr.on{opacity:calc(.25 + var(--p,0) * .75);transform:translateY(var(--y,0))}
/* 끄는 중에는 빈 자리와 같이 움직여야 한다 — 늦게 따라오면 어긋나 보인다 */
.ptr.drag{transition:opacity .18s ease}
/* 놓았다 — 점이 튀기 시작한다 */
.ptr.spin{opacity:1}
/* 「움직임 줄이기」를 켜도 새로고침은 남긴다. 꾸밈이 아니라 기능이다.
   대신 튀는 것만 멈추고 색으로만 알린다. */
@media (prefers-reduced-motion:reduce){ .ptr{transition:none} }

.toast{position:fixed;left:50%;bottom:calc(96px + var(--safe-b));transform:translateX(-50%);
  z-index:60;padding:11px 18px;border-radius:99px;
  /* 알림도 알약이다. 탭 알약과 같은 유리를 쓰되 글자는 반드시 읽혀야 하니
     뒤를 더 눌러 담는다. 테두리 한 줄은 위·아래에서만 보인다 — 탭과 같은 방식. */
  background:var(--toast-bg);color:var(--toast-ink);
  -webkit-backdrop-filter:blur(18px) saturate(180%);
  backdrop-filter:blur(18px) saturate(180%);
  font-size:13px;font-weight:600;
  box-shadow:0 .5px 1px rgba(25,31,40,.16),0 6px 18px -8px rgba(25,31,40,.34);
  animation:pop .28s cubic-bezier(.32,.72,0,1) both;
  white-space:nowrap;max-width:90vw}
.toast::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:1px solid var(--toast-rim);
  -webkit-mask:linear-gradient(180deg,#000 0%,transparent 44%,transparent 56%,#000 100%);
  mask:linear-gradient(180deg,#000 0%,transparent 44%,transparent 56%,#000 100%)}

@media (prefers-reduced-motion:reduce){
  .bub,.toast,.sheet,.sheet-bg,.badge{animation:none}
  .typing i,.sk{animation:none}
}

/* ── 설정 · 텍스트 줄 목록 (카드 없음) ─────────────────────
   인스타그램처럼: 아이콘은 얇게, 글자가 주인공, 줄 사이는 머리카락 선 하나. */
.sgrp{margin-top:32px}
.sgrp:first-child{margin-top:8px}
.sh{font-size:12px;font-weight:600;color:var(--ink-3);letter-spacing:.01em;
  padding:0 20px 8px}
.srow{display:flex;align-items:center;gap:14px;width:100%;text-align:left;
  padding:13px 20px;min-height:56px;color:var(--ink);position:relative;
  transition:background .12s}
/* 선을 줄 전체에 긋고 색까지 옅으면 「있는지 없는지 모를 선」이 된다.
   아이콘은 건너뛰고 글자 밑에서만, 대신 또렷하게 — 종이 목록처럼 보이는 방법이다. */
.srow+.srow::before{content:'';position:absolute;left:55px;right:0;top:0;height:.5px;
  background:var(--line)}
.sgrp>.srow:first-child::before{display:none}
.srow:active{background:var(--surface-3)}
.srow svg{width:21px;height:21px;flex:none;color:var(--ink-2);stroke-width:1.7}
.srow-b{min-width:0;flex:1}
.srow-t{font-size:16px;font-weight:500;letter-spacing:-.028em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.srow-s{font-size:13px;color:var(--ink-3);margin-top:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.srow-v{margin-left:auto;font-size:14px;font-weight:500;color:var(--ink-3);flex:none;
  white-space:nowrap;max-width:44%;overflow:hidden;text-overflow:ellipsis}
/* 17px · 굵기 2.1 · 글씨 회색이면 여덟 개가 세로로 서서 화면을 흔든다.
   누르는 건 줄 전체지 이 표시가 아니다. 작고 옅게 — 방향만 알려주면 된다. */
.srow-c{margin-left:auto;flex:none;width:15px;height:15px;color:var(--chev);
  stroke-width:2}
.srow.stop,.srow.stop svg{color:var(--stop)}

/* 켜고 끄는 줄 — 오른쪽 끝에 스위치.
   진짜 체크박스를 눈에만 안 보이게 숨기고 그 옆 막대에 색을 칠한다.
   그래야 키보드로도 눌리고 화면을 읽어주는 프로그램도 알아본다. */
.srow-g{cursor:pointer}
.tg{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
.tg-t{margin-left:auto;flex:none;position:relative;display:block;
  width:51px;height:31px;border-radius:16px;background:var(--line);
  transition:background .22s ease}
.tg-t::after{content:'';position:absolute;left:2px;top:2px;width:27px;height:27px;
  border-radius:50%;background:#fff;box-shadow:0 2px 5px rgba(25,31,40,.2);
  transition:transform .24s cubic-bezier(.32,1.2,.4,1)}
.tg:checked+.tg-t{background:var(--blue)}
.tg:checked+.tg-t::after{transform:translateX(20px)}
.tg:focus-visible+.tg-t{outline:2px solid var(--blue);outline-offset:2px}
.srow-g:active .tg-t::after{width:31px}
@media (prefers-reduced-motion:reduce){
  .tg-t,.tg-t::after{transition:none}
}
.snote{font-size:12.5px;color:var(--ink-3);line-height:1.65;padding:10px 20px 0}
/* 맨 아래 약관 줄. 글자가 14px 높이라 손가락으로 못 눌렀다 —
   눌리는 칸을 44px 로 키우되, 보이는 글씨 크기는 그대로 둔다. */
.sfoot{text-align:center;padding:34px 20px calc(4px + var(--safe-b))}
.sfoot-b{font-size:12px;font-weight:700;color:var(--ink-4);letter-spacing:.2em;
  text-transform:uppercase;opacity:.65}
.sfoot-l{display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:2px;margin-top:2px}
/* 밑줄은 본문 안에서 「여기가 링크」를 알리는 표시다. 링크만 세 개 서 있는 줄에서는
   밑줄이 셋 다 그어져서 지저분해진다. 대신 사이에 가운뎃점을 찍는다. */
.sfoot-l a{display:inline-flex;align-items:center;min-height:44px;padding:0 9px;
  font-size:12.5px;color:var(--ink-3);letter-spacing:-.01em;text-decoration:none}
.sfoot-l a+a::before{content:'·';color:var(--ink-4);opacity:.5;margin-right:9px}
.sfoot-l a:active{color:var(--ink-2)}
.sfoot-n{font-size:11.5px;color:var(--ink-4);opacity:.8;margin-top:-6px}
/* 안내 밑에 붙는 작은 까닭 한 줄. <br> 대신 이걸로 줄을 바꾼다. */
.hint-sub{display:block;font-size:11px;opacity:.6;margin-top:2px}

/* 프로필 줄 — 설정 맨 위, 사진/오브 크게 */
.sme{display:flex;align-items:center;gap:14px;width:100%;text-align:left;
  padding:16px 20px;transition:background .12s}
.sme:active{background:var(--surface-3)}
.sme-av{width:56px;height:56px;border-radius:50%;flex:none;display:grid;place-items:center;
  overflow:hidden;background:var(--surface-3);color:var(--ink-4);font-size:20px;font-weight:700}
.sme-av:has(svg),.sme-av:has(.orbwrap){overflow:visible;background:none}
.sme-t{font-size:18px;font-weight:700;letter-spacing:-.036em}
.sme-s{font-size:13px;color:var(--ink-3);margin-top:3px}

/* 내 프로필 — 사진 한 장이 화면의 주인공이다.
   나머지는 조용히. 사진 위 카메라 배지 하나만 눈에 띄면 된다. */
.me-top{display:grid;place-items:center;padding:26px 0 6px;gap:9px}
.me-avb{position:relative;width:104px;height:104px;border-radius:50%;
  background:none;border:0;padding:0;cursor:pointer;display:block}
.me-avb:active{transform:scale(.97)}
.me-av{width:104px;height:104px;border-radius:50%;display:block;object-fit:cover;
  background:var(--surface-3)}
.me-ini{display:grid;place-items:center;font-size:38px;font-weight:700;
  letter-spacing:-.04em;color:var(--ink-3)}
.me-cam{position:absolute;right:-1px;bottom:-1px;width:33px;height:33px;border-radius:50%;
  background:var(--blue);color:#fff;display:grid;place-items:center;
  border:2.5px solid var(--ground)}
.me-cam svg{width:16px;height:16px}
.me-hint{font-size:12.5px;color:var(--ink-3);letter-spacing:-.02em}
.sme-ini{font-size:22px;color:var(--ink-3)}

/* 이어둔 계정 — 끊을 수 없는 마지막 하나는 눌리지 않는다 */
.srow[disabled]{opacity:.5;cursor:default}
.srow[disabled]:active{background:none}

/* 프로필 편집 */
.fld{padding:6px 20px 18px}
.fld-l{font-size:12.5px;font-weight:700;color:var(--ink-3);letter-spacing:-.02em;
  padding:0 0 8px}
.fld-i{width:100%;font-size:16px;letter-spacing:-.024em;color:var(--ink);
  background:var(--surface-3);border:.5px solid var(--g-rim);border-radius:14px;
  padding:14px 15px;transition:border-color .15s}
.fld-i:focus{outline:none;border-color:var(--blue)}
.psl{display:flex;flex-direction:column}
/* 안 고른 성격은 아이콘 없이 빈칸. 체크 하나만 눈에 띄면 된다 */
.psl-b{width:21px;flex:none}
/* 글 옆에 붙는 작은 아이콘 — 크기를 안 주면 칸 전체로 늘어난다 */
.i-sm{width:14px;height:14px;flex:none}
.psl .srow.on{color:var(--blue)}
.psl .srow.on svg{color:var(--blue)}

/* 씨앗 한 줄 — 글림이 물어보고 허락받아 심은 것 */
.seed-r{display:flex;align-items:center;gap:10px;padding:9px 0;
  border-top:.5px solid var(--line-2)}
.sec-h + .seed-r{border-top:0}
.seed-r>span{flex:1;min-width:0;font-size:14px;color:var(--ink);line-height:1.5;
  letter-spacing:-.02em;word-break:keep-all}
.seed-r>button{flex:none;width:38px;height:38px;display:grid;place-items:center;
  border:0;background:none;color:var(--ink-4);border-radius:10px}
.seed-r>button:active{background:var(--surface-3);color:var(--stop)}

/* ═══════════ 컴퓨터 화면 ═══════════
   글림리는 폰 앱이다. 넓은 화면에서 늘어나면 그건 다른 물건이 된다.
   그래서 컴퓨터에서는 늘리지 않고, 폰 크기 그대로 가운데 세운다 — 거울처럼.

   까다로운 점: 온보딩·시트·알림은 position:fixed 라서 창 전체로 퍼진다.
   · 온보딩(.ob)은 #app 안에 있다 → #app 에 transform 을 주면 그 틀이 기준이 된다.
   · 시트·알림·메시는 body 에 붙는다 → 틀 위치를 직접 계산해서 맞춘다.
   그래서 틀의 크기·위치를 변수 하나로 정하고 넷이 같이 쓴다. */
@media (min-width:600px) and (min-height:600px){
  :root{
    --fw:414px;                                   /* 폰 가로 */
    --fh:min(896px, calc(100dvh - 56px));         /* 폰 세로 — 창이 낮으면 같이 줄어든다 */
    --fr:46px;                                    /* 모서리 */
    --ftop:calc((100dvh - var(--fh)) / 2);        /* 틀 윗변까지 거리 */
    --page:#EEF0F3;                               /* 틀 바깥 바닥 */
  }
  @media (prefers-color-scheme:dark){ :root:not([data-theme=light]){ --page:#080A0E } }
  :root[data-theme=dark]{ --page:#080A0E }

  html,body{background:var(--page)}
  body{min-height:100dvh;display:flex;align-items:center;justify-content:center}

  #app{
    width:var(--fw); max-width:none; height:var(--fh); margin:0; flex:none;
    border-radius:var(--fr); overflow:hidden;
    /* transform 이 있으면 안쪽 fixed 요소가 창이 아니라 이 틀을 기준으로 잡는다.
       온보딩 화면이 밖으로 새는 걸 이 한 줄이 막는다. */
    transform:translateZ(0);
    box-shadow:0 2px 6px rgba(15,19,25,.06), 0 24px 70px rgba(15,19,25,.16);
    outline:1px solid var(--line); outline-offset:-1px;
  }
  #app>.view{border-radius:inherit}

  /* 틀 바닥. #app 에 배경을 주면 그 위의 메시가 가려진다.
     그래서 바닥을 따로 한 겹 깔고, 메시는 그 위에 얹는다 (폰에서와 같은 순서). */
  body::before{content:'';position:fixed;z-index:0;
    top:var(--ftop);left:50%;transform:translateX(-50%);
    width:var(--fw);height:var(--fh);border-radius:var(--fr);background:var(--ground)}

  /* body 에 붙는 것들 — 틀과 같은 자리, 같은 크기로 맞춘다 */
  .mesh,.sheet-bg{
    inset:auto; top:var(--ftop); left:50%; transform:translateX(-50%);
    width:var(--fw); height:var(--fh); border-radius:var(--fr);
  }
  .sheet{
    left:50%; right:auto; transform:translateX(-50%);
    width:var(--fw); max-width:none; margin:0;
    bottom:var(--ftop); border-radius:22px 22px var(--fr) var(--fr);
  }
  .toast{bottom:calc(var(--ftop) + 96px); max-width:calc(var(--fw) - 40px)}

  /* 시트가 올라올 때 가로 위치가 흔들리지 않게 — 세로만 움직인다 */
  @keyframes sheetIn{from{transform:translateX(-50%) translateY(12%) scale(.97);
    opacity:0;filter:blur(6px)}
    to{transform:translateX(-50%)}}
  @keyframes sheetOut{from{transform:translateX(-50%)}
    to{transform:translateX(-50%) scale(1.03);opacity:0;filter:blur(12px)}}

  /* 온보딩은 창 높이가 아니라 틀 높이에 맞춰 줄어든다 */
  .ob-mid{height:clamp(150px, calc(var(--fh) - 508px), 356px)}
  .ob-mid .orbwrap{width:clamp(88px, calc(var(--fh) - 676px), 168px)!important;
    height:clamp(88px, calc(var(--fh) - 676px), 168px)!important}
}

/* 목록 아래 「더 있음」 — 내려오면 다음 묶음을 붙인다.
   글자를 쓰지 않는다. 「불러오는 중」은 곧 사라질 것에 이름을 붙이는 일이고,
   그러면 기다림이 더 길게 느껴진다. 점 세 개가 숨 쉬듯 흐려졌다 밝아진다. */
.more-l{display:flex;justify-content:center;align-items:center;height:46px}

/* ── 기다림 · 튀는 점 ────────────────────────────────────
   빙글 도는 원은 어느 앱에나 있다. 로티에서 골라 와도 마찬가지다.
   이 앱에는 이미 자기 것이 있다 — 시작 화면에서 「glımly」 글자 위를
   건너뛰는 그 점. 기다림에도 같은 몸짓을 쓴다. 파일 하나 안 늘린다.

   점이 바닥을 짚고 튀어오른다. 닿는 순간에만 눌린다.
   두 개가 반 박자 어긋나서, 하나가 뜰 때 하나가 내려온다. */
.bnc{display:flex;gap:9px;justify-content:center;align-items:flex-end;height:22px}
.bnc i{display:block;width:7px;height:7px;border-radius:50%;background:var(--blue);
  transform-origin:50% 100%;animation:bncY .58s cubic-bezier(.3,0,.7,1) infinite alternate}
.bnc i:nth-child(2){animation-delay:.29s;background:var(--ink-4);width:5px;height:5px}
@keyframes bncY{
  0%  {transform:translateY(0) scale(1.32,.68)}
  14% {transform:translateY(-2px) scale(1,1)}
  100%{transform:translateY(-13px) scale(.94,1.06)}}
@media (prefers-reduced-motion:reduce){
  .bnc i{animation:none;transform:none;opacity:.55}
  .bnc i:nth-child(2){opacity:.3}
}

/* 당겨서 새로고침 — 원이 도는 대신 점이 튄다.
   놓기 전에는 끈 만큼 점이 벌어지고, 놓으면 튀기 시작한다. */
.ptr-b{display:flex;gap:calc(3px + var(--p,0) * 6px);align-items:flex-end;
  justify-content:center;width:100%;height:100%}
.ptr-b i{display:block;width:6px;height:6px;border-radius:50%;background:var(--ink-4);
  transform-origin:50% 100%;
  transform:translateY(calc(var(--p,0) * -5px))}
.ptr.ready .ptr-b i{background:var(--blue)}
.ptr.ready .ptr-b i:nth-child(2){background:var(--ink-4)}
.ptr.spin .ptr-b i{transform:none;
  animation:bncY .58s cubic-bezier(.3,0,.7,1) infinite alternate}
.ptr.spin .ptr-b i:nth-child(1){background:var(--blue)}
.ptr.spin .ptr-b i:nth-child(2){animation-delay:.29s;background:var(--ink-4)}
@media (prefers-reduced-motion:reduce){
  .ptr.spin .ptr-b i{animation:none;background:var(--blue)}
}
