/* 원격 콘솔 — 조종 화면.
 *
 * 이 화면이 있는 이유는 둘뿐이다.
 *   (1) PC 들이 멀쩡한지 몇 초 안에 확인한다.
 *   (2) 뭔가 잘못 나가고 있을 때 **중지**를 누른다.
 * 규칙도 둘이다 — 읽는 것이 먼저 오고 누르는 것이 나중에 온다. 그리고 화면에서
 * 제일 크고 제일 누르기 쉬운 물건은 **되돌릴 수 있는 것**이다.
 *
 * ── 생김새: 어둠 속의 리모컨 ────────────────────────────────────────
 * 이건 웹페이지가 아니라 손에 드는 조작기다. 그래서 상태를 색이 아니라 **빛**
 * 으로 말한다 — 작동중인 PC 는 등이 실제로 켜지고, 멈춘 PC 는 등이 꺼져 있고,
 * 안 붙어 있는 PC 는 속이 빈 링만 남는다. 불이 하나도 없으면 아무것도 안 돌고
 * 있다는 뜻이고, 그건 화면을 읽지 않아도 안다.
 *
 * 검정은 중성 검정이 아니라 **따뜻한 숯빛**이다(갈색이 섞여 있다). 위에서
 * 등불이 하나 내려앉은 것처럼 바탕에 은은한 번짐을 깔았다.
 *
 * 색은 셋뿐이고 셋 다 뜻이 있다.
 *   불(주황)   — 켜짐. 작동중, 그리고 누르는 것.
 *   살(뼈색)   — 안 붙어 있음. 불이 아니라 윤곽으로만 있는 상태.
 *   경보(붉은) — 놓친 것, 그리고 브레이크. 주황과 색상이 확실히 갈린다.
 *
 * ── 안 하는 것 ────────────────────────────────────────────────────
 * **바깥에서 아무것도 안 가져온다.** 글꼴도 아이콘도 전부 이 안에 있다
 * (tests/test_web.py 의 test_바깥에서_가져오는_것이_없다). 취향이 아니다 —
 * 이 화면은 급할 때 중지를 누르는 물건이라, 글꼴 CDN 이 느린 날 단추가 늦게
 * 뜨면 그것으로 이 도구는 실패한다.
 *
 * **나타나는 애니메이션을 안 쓴다.** 목록은 5초마다 통째로 다시 그린다.
 * 카드가 뜰 때마다 떠오르거나 흐려졌다 맑아지면 화면이 5초마다 일렁이고,
 * 그러면 "뭔가 바뀌었다" 는 진짜 신호가 소음에 묻힌다. 움직임은 사람이 손을
 * 댄 자리에만 있다.
 *
 * **밝은 빛깔이 없다.** 이 화면의 뜻이 빛에 실려 있어서, 흰 바탕에서는 켜진
 * 등과 꺼진 등이 같아 보인다. 한 벌만 두고 그 한 벌을 제대로 만든다.
 */

/* ── 글꼴 ────────────────────────────────────────────────────────────
 * 프리텐다드를 **파일째 들고 있다.** 이름만 스택에 적어 두면 그 글꼴이 깔려
 * 있는 기계에서만 보이고, 폰과 대부분의 PC 에서는 맑은 고딕·애플 고딕으로
 * 떨어져 결국 "아무 화면" 처럼 보인다. 그게 이 화면이 심심해 보이던 이유다.
 *
 * 바깥에서 안 가져오는 규칙은 그대로다 — web/pretendard.woff2 는 이 중계가
 * /static 으로 직접 내주는 우리 파일이고, 라이선스(OFL)는 옆에 같이 뒀다.
 *
 * **Std 판(KS X 1001, 285KB)을 골랐다.** 전체판은 2.0MB 인데, 늦게 오는 동안
 * 대체 글꼴로 보이다가 글자가 통째로 갈아 끼워지는 것이 눈에 띈다. 285KB 는
 * 거의 즉시 온다. 대신 아주 드문 음절(똠·쀼 같은)은 이 판에 없어서 그 글자만
 * 대체 글꼴로 떨어진다 — 기기 별칭에 그런 글자를 쓰면 그때 눈에 보인다.
 *
 * swap: 글꼴을 기다리는 동안 글자를 숨기지 않는다. 이 화면에서 제일 급한 일이
 * '중지' 를 누르는 것인데, 그 단추가 글꼴 때문에 늦게 뜨면 안 된다.
 */
@font-face{
  font-family:"Pretendard Std Variable";
  src:url("/static/pretendard.woff2") format("woff2");
  font-weight:45 920;      /* 한 파일에 모든 굵기가 들어 있다 */
  font-style:normal;
  font-display:swap;
}

:root{
  color-scheme:dark;

  --숯:#0c0a09;        /* 바닥. 중성 검정이 아니라 갈색이 도는 숯빛 */
  --판:#171310;        /* 기기 카드 */
  --판밝:#1d1815;      /* 카드 위쪽(빛을 받는 쪽) */
  --우물:#0f0c0a;      /* 판에 파인 자리 */
  --우물2:#221c18;     /* hover */

  --살:#f5ede6;        /* 판 위 15.9:1 */
  --살2:#d6cabf;
  --재:#9a8c82;        /* 판 위 5.7:1 — 라벨·번호. 여기가 하한이다 */

  /* 테두리는 선이 아니라 어둠 속에서 모서리에 걸리는 빛이다. */
  --결:rgba(255,255,255,.07);
  --결진:rgba(255,255,255,.13);
  --윗빛:rgba(255,255,255,.055);

  --불:#ff5a1f;        /* 켜짐 · 누르는 것.  판 위 5.9:1 */
  --불면:#f0561c;      /* 채운 면 */
  --불글:#1b0e06;      /* 그 면 위의 글자. 흰 글자는 3.5:1 로 미달이다 */
  --불연:rgba(255,90,31,.13);

  --경보:#ff5470;      /* 놓친 것 · 브레이크.  판 위 5.9:1 */
  --경보면:#ff5470;
  --경보글:#1b0509;    /* 채웠을 때. 흰 글자보다 훨씬 또렷하다 */
  --경보연:rgba(255,84,112,.12);

  --초점:#7fb2ff;      /* 초점 링만 파랑. 뜻이 있는 색 셋과 안 겹친다 */

  /* 뒤에 늘어놓은 것은 글꼴 파일이 아직 안 왔을 때 잠깐 쓰는 것들이다.
   * 한글이 화면의 대부분이라, 한글 없는 글꼴을 앞에 두면 그 잠깐 동안 글자
   * 대부분이 또 다른 글꼴로 떨어져 두 번 갈아 끼워진다. */
  --글꼴:"Pretendard Std Variable",Pretendard,-apple-system,BlinkMacSystemFont,
        "Apple SD Gothic Neo","Segoe UI Variable Text","Segoe UI",
        "맑은 고딕","Malgun Gothic",system-ui,sans-serif;
  /* 계기 숫자도 같은 글꼴을 쓴다. 숫자만 고정폭으로 빼면 화면에 글꼴이 둘이
   * 되어 "개발자 화면" 처럼 보인다. 자리폭은 tabular-nums 로 잡는다. */
  --계기글꼴:var(--글꼴);

  /* 동심원. 카드 반지름에서 안쪽 여백만큼 뺀 것이 판의 반지름이다. 이 뺄셈을
   * 안 하면 모서리 두 개가 서로 다른 곡률로 어긋나 보인다. */
  /* 바깥 폭. PC 에서는 화면을 채운다 — 이 화면은 읽는 글이 아니라 계기판이라,
   * 가운데 1240px 에 몰아 두면 좌우가 통째로 죽은 자리가 된다. 아주 넓은
   * 모니터에서만 멈춘다(한 줄이 끝없이 늘어나면 눈이 끝까지 못 간다). */
  --안폭:min(100%,2200px);

  --카드R:24px;
  --여백:6px;
  --판R:18px;          /* 24 - 6 */
  --우물R:14px;
  --알약:999px;

  /* 곡선 하나만 쓴다. 무게가 있는 물건이 멎는 느낌이다. */
  --곡선:cubic-bezier(.32,.72,0,1);
}

*{box-sizing:border-box}

/* **hidden 은 우리가 직접 지켜야 한다.** 브라우저 기본에도
 * [hidden]{display:none} 이 있지만, 우리가 쓴 규칙은 아무리 약해도 브라우저
 * 기본보다 세다 — .알림{display:flex} 한 줄이 그것을 덮어 토스트가 영영
 * 화면에 붙어 있게 된다(실제로 그랬다). app.js 는 .hidden 으로만 여닫는다. */
[hidden]{display:none !important}

html{
  background:var(--숯);
  /* 붙박이 두 층(머리띠 72 + 요약띠 약 41) 밑으로 초점이 들어가지 않게 한다.
   * 이게 없으면 Tab 으로 짚은 단추가 초점 링째로 띠 밑에 숨고, 무엇에 초점이
   * 가 있는지 못 본 채 Enter 를 치게 된다 — 거기 있는 것이 '작동' 일 수 있다. */
  scroll-padding-top:124px;
}

body{
  margin:0;
  /* **화면을 채운다.** 기기가 몇 대든 카드가 세로로도 끝까지 늘어나고 아래에
   * 검은 빈 자리가 안 남는다. 이건 취향이 아니라 이 화면의 쓰임이다 — 계기는
   * 클수록 멀리서 읽히고, 이 화면은 대개 책상 건너편에서 흘긋 본다.
   * svh 는 폰에서 주소창이 접혔다 펴져도 값이 안 뛰는 쪽이다. */
  min-height:100svh;
  display:flex;flex-direction:column;
  background:transparent;
  color:var(--살);
  font:16px/1.55 var(--글꼴);
  -webkit-text-size-adjust:100%;
  /* 폰에서 당겨 새로고침하다 화면이 통째로 튀는 것을 막는다. */
  overscroll-behavior-y:none;
}

/* 위에서 등불이 하나 내려앉은 것 같은 번짐. 화면 전체에 고정이라 스크롤해도
 * 안 따라 움직인다 — 배경이 움직이면 카드가 흔들려 보인다. */
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(115% 55% at 50% -8%, rgba(255,90,31,.17), transparent 62%),
    radial-gradient(70% 32% at 50% -2%, rgba(255,150,80,.10), transparent 58%);
}

/* 숫자는 어디서든 자리폭이 같아야 한다. 5초마다 다시 그리는 화면에서 47 → 9
 * 로 바뀔 때 뒤 글자가 밀리면 "뭔가 움직였다" 는 거짓 신호가 된다. */
.값,.번호,.잔 b,.칩 b,.코드값,.읽은때{
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
}

/* 눈으로는 안 보이되 화면읽개는 읽는 글. 아이콘만 있는 단추에 쓴다. */
.숨김글{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;
}

/* 아이콘은 전부 1.5 굵기의 가는 선이다. 두꺼우면 글자와 무게가 비슷해져
 * 화면이 시끄러워진다. */
svg{stroke-width:1.5;flex:0 0 auto}

/* 키보드로 짚은 것만 링을 보여 준다. 마우스로 누를 때마다 링이 뜨면 화면이
 * 소란스러워지고, 그러면 사람이 링 자체를 무시하게 된다. */
:where(button,input,a,[tabindex]):focus-visible{
  outline:2px solid var(--초점);
  outline-offset:3px;
}

/* ── 머리띠 ──────────────────────────────────────────────────────────
 * 화면 위에 딱 붙는 띠가 아니라, 바닥에서 떠 있는 알약이다. 조작기의 손잡이
 * 처럼 보이게 하려는 것이고, 붙박이 띠보다 폰에서 차지하는 무게도 가볍다.
 */
header{
  position:sticky;top:0;z-index:30;
  /* **배경이 있어야 한다.** 없으면 위쪽 여백 10px 이 그냥 구멍이라, 스크롤하는
   * 카드가 알약 위로 또렷하게 지나간다. 불투명하게 덮는 대신 흐리게 덮어
   * 바탕의 번짐은 남긴다. */
  background:rgba(12,10,9,.72);
  backdrop-filter:blur(14px) saturate(1.25);
  padding:10px 12px 8px;
  padding-left:max(12px,env(safe-area-inset-left));
  padding-right:max(12px,env(safe-area-inset-right));
}
header .안쪽{
  max-width:var(--안폭);margin:0 auto;
  padding:7px 8px 7px 15px;
  display:flex;align-items:center;gap:8px;
  background:rgba(29,24,21,.72);
  border:1px solid var(--결);
  border-radius:var(--알약);
  box-shadow:0 1px 0 var(--윗빛) inset, 0 10px 30px -12px rgba(0,0,0,.8);
}
header h1{
  margin:0;flex:1;min-width:0;
  font-size:15.5px;font-weight:650;letter-spacing:-.015em;
  display:flex;align-items:center;gap:10px;
}
/* 표식은 켜져 있는 등이다 — 이 화면이 지금 살아 있다는 첫 신호다. */
.표식{
  width:28px;height:28px;border-radius:10px;
  background:linear-gradient(165deg,#ff7a3d,var(--불면));
  color:var(--불글);
  display:grid;place-items:center;
  box-shadow:0 0 18px -2px rgba(255,90,31,.55),
             0 1px 0 rgba(255,255,255,.3) inset;
}
.표식 svg{width:16px;height:16px;stroke-width:1.9}

.머리단추{
  min-height:38px;padding:0 14px;
  display:inline-flex;align-items:center;gap:7px;
  border:1px solid var(--결);border-radius:var(--알약);
  background:rgba(255,255,255,.04);color:var(--살2);
  font:600 13.5px/1 var(--글꼴);cursor:pointer;
  transition:background .35s var(--곡선),color .35s var(--곡선),
             transform .35s var(--곡선),border-color .35s var(--곡선);
}
.머리단추{position:relative}
.머리단추::after{content:"";position:absolute;inset:-3px;border-radius:var(--알약)}
.머리단추:hover{background:rgba(255,255,255,.09);color:var(--살);
                border-color:var(--결진)}
.머리단추:active{transform:scale(.96)}
.머리단추 svg{width:15px;height:15px}
/* 폰에서는 아이콘만 남긴다. 이름은 화면읽개가 aria-label 로 읽는다. */
@media (max-width:559px){
  .머리단추 .글자{display:none}
  .머리단추{width:38px;padding:0;justify-content:center}
}

/* ── 요약띠 ──────────────────────────────────────────────────────────
 * 머리띠 밑에 붙어 스크롤을 따라온다. 카드가 화면 밖으로 나가도 경보는 안
 * 사라진다 — 그것이 이 띠의 존재 이유다. 경보가 없으면 경보 칩을 아예 안
 * 만든다. 늘 있는 자리는 결국 안 보게 된다.
 */
/* top 은 머리띠의 **전체 높이**여야 한다 — 10(여백) + 54(알약) + 8(여백) = 72.
 * 알약 바닥(64)에 맞추면 요약칩 위 8px 이 알약 밑으로 들어가 잘린다. */
.요약{
  position:sticky;top:72px;z-index:20;
  padding:8px 12px;
  padding-left:max(12px,env(safe-area-inset-left));
  padding-right:max(12px,env(safe-area-inset-right));
  /* 페이드 꼬리를 안 쓴다. 투명해진 꼬리도 상자는 상자여서, 아무것도 안 그려진
   * 자리가 그 아래 단추의 탭을 가로챈다(실제로 중지가 안 눌렸다). */
  background:rgba(12,10,9,.72);
  backdrop-filter:blur(14px) saturate(1.25);
  border-bottom:1px solid var(--결);
}
/* **줄바꿈을 안 한다.** 칩이 두 줄이 되면 띠 높이가 변하고, 띠가 흐름 안에
 * 있으므로 아래 카드가 통째로 밀린다 — 누르려던 단추가 손가락 밑에서 움직인다.
 * 한 줄에 고정하고 넘치면 옆으로 민다. 경보 칩을 맨 앞에 그리므로(app.js)
 * 밀려 나가는 것은 늘 덜 급한 쪽이다. */
.요약 .안쪽{
  max-width:var(--안폭);margin:0 auto;
  display:flex;align-items:center;gap:6px;
  flex-wrap:nowrap;overflow-x:auto;
  scrollbar-width:none;-ms-overflow-style:none;
}
.요약 .안쪽::-webkit-scrollbar{display:none}
.칩{
  display:inline-flex;align-items:center;gap:6px;
  padding:5px 11px;border-radius:var(--알약);
  border:1px solid var(--결);background:rgba(255,255,255,.035);
  font-size:12.5px;font-weight:600;color:var(--살2);white-space:nowrap;
}
.칩 b{font-weight:700;color:var(--살)}
.칩 svg{width:13px;height:13px}
.칩.주의{border-color:var(--결진);color:var(--살)}
.칩.주의 b{color:var(--살)}
.칩.경보{
  border-color:var(--경보);background:var(--경보연);color:var(--경보);
  box-shadow:0 0 16px -6px var(--경보);
}
.칩.경보 b{color:var(--경보)}
.읽은때{margin-left:auto;padding-left:4px;font-size:11.5px;color:var(--재);
        white-space:nowrap;font-variant-numeric:tabular-nums}

/* ── 여러 대를 한 번에 ──────────────────────────────────────────────────
 * 요약띠와 같은 결로 만든다. 다만 **붙여 두지(sticky) 않는다.** 되돌릴 수 없는
 * 단추가 화면에 늘 떠 있으면, 목록을 훑으려고 미는 손가락 밑에 '작동' 이
 * 들어온다. 맨 위까지 올라가야 눌리는 편이 맞다. */
.일괄{
  padding:10px 12px;
  padding-left:max(12px,env(safe-area-inset-left));
  padding-right:max(12px,env(safe-area-inset-right));
  border-bottom:1px solid var(--결);
  background:rgba(255,255,255,.02);
}
/* 폰에서는 두 줄이다: 위에 시각, 아래에 단추 셋. 한 줄에 다 넣으면 단추가
 * 서로를 짓눌러 '중지' 가 화면 밖으로 나간다 — 급할 때 눌러야 하는 것이
 * 그것이다. 넓은 화면에서는 한 줄로 편다(아래 @media). */
.일괄 .안쪽{
  max-width:var(--안폭);margin:0 auto;
  display:grid;grid-template-columns:auto minmax(0,1fr);
  align-items:center;gap:8px;
}
.일괄이름{
  font-size:12.5px;font-weight:700;color:var(--재);
  letter-spacing:.04em;white-space:nowrap;
}
.일괄 input[type=datetime-local]{
  width:100%;min-width:0;
  padding:8px 10px;border-radius:var(--알약);
  border:1px solid var(--결);background:rgba(255,255,255,.04);
  color:var(--살);font:inherit;font-size:13px;
  color-scheme:dark;
}
/* 셋이 폭을 똑같이 나눈다. 급할 때 때리는 '중지' 가 늘 같은 자리에 같은
 * 크기로 있어야 한다. */
.일괄단추들{grid-column:1/-1;display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px}
.일괄단추들 .단추{padding:9px 6px;font-size:13px;min-width:0;width:100%}

@media (min-width:560px){
  .일괄 .안쪽{grid-template-columns:auto minmax(0,230px) 1fr}
  .일괄단추들{grid-column:auto;justify-self:end;
             grid-template-columns:repeat(3,minmax(84px,auto))}
}

/* ── 예약판 ─────────────────────────────────────────────────────────────
 * 기록판과 같은 판을 쓰고, 안에 시각 칸 한 줄만 놓는다. */
.예약줄{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.예약칸{
  flex:1 1 170px;min-width:0;
  padding:9px 11px;border-radius:10px;
  border:1px solid var(--결진);background:rgba(255,255,255,.05);
  color:var(--살);font:inherit;font-size:14px;
  color-scheme:dark;
}
.예약말{margin:11px 1px 0;font-size:12.5px;line-height:1.6;color:var(--재)}

/* ── 본문 ────────────────────────────────────────────────────────────── */
main{
  width:100%;max-width:var(--안폭);margin:0 auto;
  /* 남는 세로를 전부 받는다. 이게 없으면 기기가 세 대일 때 화면 아래 절반이
   * 통째로 빈다. 0 으로 안 줄어드는(flex-shrink:0) 것이 중요하다 — 토스트가
   * 떠서 자리를 더 먹어도 카드가 손가락 밑에서 줄어들지 않는다. */
  flex:1 0 auto;
  display:flex;flex-direction:column;
  padding:4px 16px calc(16px + env(safe-area-inset-bottom));
  padding-left:max(16px,env(safe-area-inset-left));
  padding-right:max(16px,env(safe-area-inset-right));
}
#목록{
  flex:1;
  display:grid;gap:16px;
  grid-template-columns:repeat(auto-fit,minmax(340px,1fr));
  /* **줄은 내용만큼만 높다.** 남는 세로를 줄이 나눠 갖게 해 봤더니(1fr)
   * 카드가 760px 까지 늘어나면서 안이 통째로 헐거워졌다 — 계기 우물이 속이
   * 빈 검은 상자가 되고, 단추 사이가 손가락 두 개만큼 벌어진다.
   * 화면을 채우는 것은 **가로**로 한다. 세로로 남는 자리는 그냥 바탕이다. */
  grid-auto-rows:min-content;
  align-items:stretch;   /* 카드 높이를 맞춰 브레이크가 같은 줄에 선다 */
}
/* 320px 짜리 좁은 폰에서 340px 최소폭은 가로 스크롤을 만든다. 끈다. */
@media (max-width:379px){#목록{grid-template-columns:1fr}}

/* ── 기기 카드 ───────────────────────────────────────────────────────
 * 껍데기 안에 판이 앉고, 판 안에 우물이 파인다. 세 겹의 반지름이 동심원으로
 * 맞아 떨어지는 것이 이 화면의 생김새를 결정한다.
 * 브레이크는 판 위가 아니라 **껍데기 바닥**에 붙는다 — 계기에 달린 것이
 * 아니라 기계에 달린 물건이라는 뜻이고, 되돌릴 수 없는 단추들과 다른 층이다.
 */
.기기{
  /* grid 칸 안에서 이 값이 없으면 내용의 min-content 가 칸 폭을 밀어내
   * 좁은 폰에서 가로 스크롤이 생긴다. */
  min-width:0;
  /* **카드가 자기 폭을 스스로 안다.** 화면 폭이 아니라 카드 폭에 맞춰 글자와
   * 단추가 커지므로(아래 @container), 두 열이든 다섯 열이든 카드 안의 비율이
   * 그대로다. 화면 폭으로 재면 기기 대수에 따라 비율이 어긋난다. */
  container:card / inline-size;
  display:flex;flex-direction:column;
  padding:var(--여백);
  background:rgba(255,255,255,.035);
  border:1px solid var(--결);
  border-radius:var(--카드R);
  box-shadow:0 18px 40px -24px rgba(0,0,0,.9);
}
/* 도는 기기는 껍데기까지 은은하게 달아오른다. 카드를 읽지 않아도 어느 것이
 * 일하고 있는지 멀리서 보인다. */
.기기.작동중{
  border-color:rgba(255,90,31,.28);
  box-shadow:0 0 40px -18px rgba(255,90,31,.55),
             0 18px 40px -24px rgba(0,0,0,.9);
}
/* 놓친 것이 있으면 그쪽이 이긴다. 돌고 있어도 볼 것이 있다는 뜻이다. */
.기기.경보{
  border-color:rgba(255,84,112,.45);
  box-shadow:0 0 40px -16px rgba(255,84,112,.5),
             0 18px 40px -24px rgba(0,0,0,.9);
}

.판{
  /* 기록판이 이 판 위에 정확히 겹쳐 앉는다(.기록판 참고). */
  position:relative;
  flex:1;min-width:0;
  display:flex;flex-direction:column;
  padding:16px 17px 17px;
  /* 위쪽이 밝고 아래쪽이 어둡다 — 위에서 빛이 내려오는 화면이라 그 방향을
   * 판에도 그대로 둔다. */
  background:linear-gradient(180deg,var(--판밝),var(--판));
  border-radius:var(--판R);
  box-shadow:0 1px 0 var(--윗빛) inset;
}
/* 안 붙어 있는 기기는 판의 불이 꺼진다. 색을 더하는 대신 빼서 말한다. */
.기기.끊김 .판{background:var(--우물);box-shadow:none}

/* 머리: 이름 + 연필 + 번호.
 * flex 가 아니라 grid 인 이유가 있다. app.js 가 이름 span 을 input 으로
 * 통째로 갈아 끼우는데(머리.replaceChild), flex 로 두면 입력칸이 폭을 다
 * 먹어 번호가 세 줄로 쪼개진다. 자리를 격자로 못 박으면 무엇이 들어와도
 * 배치가 그대로다. */
.머리{
  display:grid;
  grid-template-columns:minmax(0,1fr) auto;
  align-items:center;column-gap:8px;
}
.이름{
  grid-column:1;grid-row:1;
  min-width:0;
  /* **block 이어야 한다.** flex 로 두면 text-overflow:ellipsis 가 아예 안
   * 그려져서, 긴 별칭이 "…" 없이 글자 중간에서 뚝 잘린다(실제로 그랬다).
   * 세로 가운데 맞춤은 flex 대신 line-height 로 한다. */
  display:block;
  height:34px;line-height:34px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:19px;font-weight:650;letter-spacing:-.022em;
}
input.이름칸{
  grid-column:1;grid-row:1;
  min-width:0;width:100%;height:34px;
  margin:0;padding:0 10px;
  font:650 19px/1 var(--글꼴);letter-spacing:-.022em;
  color:var(--살);background:var(--우물);
  border:1px solid var(--불);border-radius:11px;
  box-shadow:0 0 0 3px var(--불연);
  outline:none;
}
.연필{
  grid-column:2;grid-row:1;
  width:34px;height:34px;
  display:inline-grid;place-items:center;
  background:transparent;border:1px solid transparent;border-radius:11px;
  color:var(--재);cursor:pointer;
  transition:background .35s var(--곡선),color .35s var(--곡선);
}
.연필{position:relative}
/* 보이는 크기는 34px 그대로, 누르는 넓이만 44px 로 넓힌다. */
.연필::after{content:"";position:absolute;inset:-5px;border-radius:14px}
.연필:hover{background:rgba(255,255,255,.06);color:var(--살2)}
.연필 svg{width:15px;height:15px}
.연필:disabled{opacity:.35;cursor:default}
.번호{
  grid-column:1 / -1;grid-row:2;
  margin-top:2px;
  font:400 12.5px/1.4 var(--계기글꼴);
  /* **font 단축 뒤에 다시 걸어야 한다.** 단축 속성은 font-variant 를 normal 로
   * 되돌리므로, 위쪽에 모아 둔 tabular-nums 규칙이 여기서 통째로 지워진다. */
  font-variant-numeric:tabular-nums;
  letter-spacing:.16em;color:var(--재);
}

/* 상태 줄.
 * '붙어 있나' 와 '돌고 있나' 는 다른 층이다. 등은 붙어 있는지를, 말은 무엇을
 * 하고 있는지를 말한다. 그리고 **색만으로 가르지 않는다** — 켜진 등은 채워져
 * 빛나고, 꺼진 등은 채워지되 어둡고, 안 붙은 등은 속이 비어 있다. 색이 안
 * 보여도 모양이 남는다. */
.상태{
  display:flex;align-items:center;gap:9px;
  margin-top:15px;
  font-size:14.5px;font-weight:600;letter-spacing:-.01em;
}
.등{
  width:9px;height:9px;border-radius:50%;
  background:#4a403a;                       /* 꺼진 등 */
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.6);
}
.기기.작동중 .등{
  background:var(--불);
  box-shadow:0 0 0 4px var(--불연), 0 0 14px 2px rgba(255,90,31,.65);
}
.기기.끊김 .등{
  background:transparent;
  box-shadow:inset 0 0 0 2px var(--재);     /* 속이 빈 링 */
}
.기기.작동중 .상태말{color:var(--불)}
.기기.멈춤 .상태말{color:var(--재)}
.기기.끊김 .상태말{color:var(--살2)}
/* 붙어는 있는데 아직 상태를 한 번도 안 올린 기기. 등을 켜지도 끄지도 않는다 —
 * 반쯤 채운 회색 원이다. '모른다' 를 '멈춤' 이나 '작동중' 으로 그리면 안 된다. */
.기기.모름 .등{background:var(--재);opacity:.5}
.기기.모름 .상태말{color:var(--재)}
.본때{margin-left:auto;font:400 11.5px/1 var(--글꼴);color:var(--재);
      white-space:nowrap;font-variant-numeric:tabular-nums}

/* 계기.
 * **세 값은 독립이 아니라 포함관계다** — 놓친것 ⊆ 지금할것 ⊆ 기다림
 * (app/scheduler.py 의 due_now / missed). 그래서 똑같은 칸 셋으로 나란히
 * 세우지 않는다. 그렇게 두면 12·1·3 을 보고 사람이 16건이라고 읽는다.
 * 큰 수 하나를 세우고 나머지를 '그중' 으로 매단다. */
.우물{
  /* 카드가 세로로 늘어나면 남는 자리를 계기가 받는다. 가운데를 비워 두고
   * 단추만 바닥으로 밀려나는 대신, 이 화면에서 제일 자주 읽는 숫자가 커진다.
   * **다만 끝이 있다.** 여기까지 안 막으면 남는 자리를 우물이 전부 삼켜,
   * 숫자 하나가 텅 빈 검은 상자 한가운데 뜬다. */
  /* 한 줄의 카드들은 키가 같다(align-items:stretch). 그 차이를 여기서
   * 받아 브레이크가 같은 줄에 서게 한다. 끝을 막아 두는 것은, 한 카드가
   * 유난히 길 때 나머지 카드의 우물이 텅 빈 상자가 되는 것을 막으려는 것이다. */
  flex:1;max-height:250px;
  display:flex;flex-direction:column;justify-content:center;
  margin-top:14px;padding:13px 15px;
  background:var(--우물);border-radius:var(--우물R);
  box-shadow:inset 0 1px 2px rgba(0,0,0,.5);
}
.큰{display:flex;align-items:baseline;gap:9px}
.큰 .라벨{font-size:11.5px;font-weight:650;color:var(--재)}
.큰 .값{
  font:650 32px/1 var(--계기글꼴);letter-spacing:-.035em;color:var(--살);
  font-variant-numeric:tabular-nums;   /* font 단축이 지운 것을 되건다 */
}
.기기.작동중 .큰 .값{color:var(--불)}
.큰 .단위{font-size:12px;color:var(--재)}
.잔{
  display:flex;flex-wrap:wrap;align-items:center;gap:6px 13px;
  margin-top:9px;font-size:12.5px;color:var(--재);
}
.잔 b{font-weight:650;color:var(--살2)}
/* 놓친 것은 못 보고 지나가면 그날 예약이 통째로 안 나간다. 0 일 때도 자리를
 * 만들어 두면 늘 있는 자리가 되어 결국 안 보게 되므로, 0 이 아닐 때만
 * 만든다. 그때는 다른 잔값과 아예 다른 물건이 된다. */
.놓침{
  display:inline-flex;align-items:center;gap:5px;
  padding:3px 10px;margin:-3px 0;border-radius:var(--알약);
  background:var(--경보연);color:var(--경보);font-weight:650;
  border:1px solid var(--경보);
}
.놓침 b{color:var(--경보)}
.놓침 svg{width:12px;height:12px}

/* 기록 보기.
 * **계기 안에 있다.** 읽기만 하는 물건이라 되돌릴 수 없는 단추들이 있는 판
 * 위나, 브레이크가 있는 트레이에는 안 둔다 — 기록을 보려고 뻗은 손가락이
 * 빗나가 '지금검사' 를 때리면 글이 나간다.
 * 조용한 생김새인 것도 뜻이 있다. 이 화면에서 불이 들어와 있는 것은 실제로
 * 무언가를 하는 단추뿐이어야 한다. */
.기록단추{
  align-self:flex-start;position:relative;
  margin-top:13px;min-height:34px;padding:0 12px 0 10px;
  display:inline-flex;align-items:center;gap:7px;
  border:1px solid var(--결);border-radius:var(--알약);
  background:transparent;color:var(--재);
  font:600 12.5px/1 var(--글꼴);cursor:pointer;
  transition:background .35s var(--곡선),color .35s var(--곡선),
             border-color .35s var(--곡선);
}
.기록단추:hover{background:rgba(255,255,255,.05);color:var(--살2);
                border-color:var(--결진)}
.기록단추:disabled{opacity:.4;cursor:default;background:transparent}
.기록단추 svg{width:14px;height:14px}
/* 보이는 크기는 34px 그대로, **누르는 넓이만** 44px 로 넓힌다(연필과 같은
 * 수법이다). 폰에서 34px 짜리는 손가락으로 두 번에 한 번 빗나간다. */
.기록단추::after{content:"";position:absolute;inset:-5px;border-radius:var(--알약)}
/* 도는 동안 붙는 점. .단추.도는중 과 같은 물건이지만 그쪽은 .단추 에만
 * 걸려 있다. */
.기록단추.도는중::after{
  content:"";width:11px;height:11px;
  border:1.5px solid currentColor;border-top-color:transparent;border-radius:50%;
  animation:돌기 .8s linear infinite;
}

/* ── 명령 ────────────────────────────────────────────────────────────
 * 자리와 크기가 안전 규칙이다.
 *   작동·이어서 진행 — **되돌릴 수 없다.** 남의 게시판에 글이 실제로 나간다.
 *                     판 위에, 확인창 뒤에 둔다.
 *   중지          — 언제 눌러도 안전한 비상 브레이크. 껍데기 바닥에 홀로,
 *                   더 크게, 확인창 없이 둔다. 폭은 위 단추와 맞춘다.
 * 급할 때 카드 아래쪽을 후려치는 손가락이 무엇을 때리든 그것은 브레이크여야
 * 한다. 그래서 둘을 아예 다른 층(판 / 껍데기)에 올려 놓았다.
 */
.단추들{display:flex;gap:9px;margin-top:auto;padding-top:16px}

button{font-family:inherit}

.단추{
  flex:1;min-width:0;min-height:46px;padding:0 14px;
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  border:1px solid var(--결);border-radius:var(--알약);
  background:rgba(255,255,255,.045);color:var(--살2);
  font:600 14.5px/1 var(--글꼴);letter-spacing:-.01em;cursor:pointer;
  transition:background .35s var(--곡선),color .35s var(--곡선),
             transform .35s var(--곡선),border-color .35s var(--곡선),
             box-shadow .35s var(--곡선);
}
.단추:hover{background:rgba(255,255,255,.09);color:var(--살);
            border-color:var(--결진)}
/* 눌리는 물건처럼 살짝 내려앉는다. transform 만 쓴다 — 레이아웃을 안 건드려
 * 60fps 가 안전하다. */
.단추:active:not(:disabled){transform:scale(.975)}
.단추 svg{width:15px;height:15px}

/* 켜는 단추. 화면에서 유일하게 불이 들어와 있는 물건이다. */
.단추.주{
  background:linear-gradient(180deg,#ff7233,var(--불면));
  border-color:transparent;color:var(--불글);font-weight:700;
  box-shadow:0 0 24px -8px rgba(255,90,31,.75),
             0 1px 0 rgba(255,255,255,.28) inset;
}
.단추.주:hover{
  background:linear-gradient(180deg,#ff8145,#ff5f24);
  box-shadow:0 0 30px -6px rgba(255,90,31,.85),
             0 1px 0 rgba(255,255,255,.34) inset;
}

/* **판의 단추와 좌우 끝을 맞춘다.** 브레이크가 트레이에 있어서 예전에는
 * 껍데기 끝까지 늘어났는데, 그러면 바로 위의 '작동' 과 폭이 30px 쯤 어긋나
 * 두 단추가 서로 다른 자를 쓴 것처럼 보인다. 층이 다르다는 것은 폭이 아니라
 * **자리(트레이)와 색과 높이**가 말한다 — 그건 그대로다. */
.브레이크{padding:10px 17px 5px}
.단추.멈추기{
  width:100%;flex:none;min-height:50px;
  font-size:15.5px;font-weight:650;
  background:var(--우물);
  border:1px solid var(--경보);
  color:var(--경보);
}
.단추.멈추기:hover{
  background:var(--경보면);color:var(--경보글);border-color:var(--경보면);
  box-shadow:0 0 26px -8px var(--경보);
}

/* 못 누르는 단추를 opacity 로만 흐리면 야외·밝은 화면에서 눌러도 되는 것과
 * 구별이 안 간다. 면을 평평하게 만들고 글자색까지 같이 죽인다. */
.단추:disabled,
.단추.주:disabled,
.단추.멈추기:disabled{
  background:rgba(255,255,255,.03);border-color:var(--결);
  color:var(--재);box-shadow:none;cursor:default;
}

/* 명령이 도는 동안. 글자를 스피너로 바꾸지 않는다 — 글자가 사라지면 사람이
 * 자기가 무엇을 눌렀는지 잃어버린다. 옆에 점을 붙인다. */
.단추.도는중::after{
  content:"";width:13px;height:13px;
  border:1.5px solid currentColor;border-top-color:transparent;border-radius:50%;
  animation:돌기 .8s linear infinite;
}
@keyframes 돌기{to{transform:rotate(360deg)}}

/* ── 카드가 커질 때 ──────────────────────────────────────────────────
 * 화면이 아니라 **카드**를 재서 키운다(container-type:inline-size).
 * PC 에서 카드가 600px 폭이 되면 32px 짜리 숫자는 작은 글씨가 되어 버린다 —
 * 계기판인데 계기가 안 보이는 셈이다. 여기서 커지는 것은 셋뿐이다:
 * 읽는 것(이름·숫자)과 누르는 것(단추), 그리고 그 둘 사이의 숨.
 * 나머지(테두리·자간·색)는 그대로 둔다. 전부 같이 커지면 그냥 확대다.
 *
 * 이 규칙들이 기본 규칙보다 **뒤에** 있어야 한다. 특이도가 같아서, 앞에 두면
 * 하나도 안 먹는다.
 */
@container card (min-width:400px){
  .판{padding:19px 21px 20px}
  .이름{height:38px;line-height:38px;font-size:21px}
  input.이름칸{height:38px;font-size:21px}
  .연필{width:38px;height:38px}
  .상태{margin-top:16px;font-size:15.5px}
  .우물{margin-top:15px;padding:15px 17px}
  /* **계기가 자기 높이를 안다.** 카드가 세로로 늘어나면 우물이 그 자리를 다
   * 받는데, 그 안의 숫자가 32px 로 남아 있으면 큰 화면일수록 계기가 작아
   * 보인다 — 텅 빈 검은 상자 한가운데 작은 숫자가 뜬다(실제로 그랬다).
   * cqh 는 이 우물의 높이다. 그래서 우물이 커진 만큼만 숫자가 커진다.
   *
   * **좁은 카드에서는 안 켠다.** size 담기는 안쪽 내용을 높이 계산에서
   * 빼므로, 잔줄이 두 줄로 접히는 좁은 카드에서 켜면 둘째 줄이 우물 밖으로
   * 삐져나온다. min-height 는 담기로 0 이 된 안쪽 대신 세우는 바닥이다. */
  .우물{container:well / size;min-height:152px}
  .큰 .값{font-size:clamp(40px,33cqh,124px)}
  .큰 .라벨{font-size:clamp(11.5px,3.4cqh,18px)}
  .큰 .단위{font-size:clamp(12px,3.4cqh,19px)}
  .잔{margin-top:clamp(9px,2.6cqh,20px);font-size:clamp(13px,3.5cqh,19px)}
  .놓침{padding:5px 12px}
  .놓침 svg{width:14px;height:14px}
  .단추들{gap:10px;padding-top:17px}
  .단추{min-height:50px;font-size:15px}
  .브레이크{padding:11px 21px 5px}
  .단추.멈추기{min-height:54px;font-size:16.5px}
}
@container card (min-width:540px){
  .판{padding:23px 25px 23px}
  .이름{height:42px;line-height:42px;font-size:24px}
  input.이름칸{height:42px;font-size:24px}
  .번호{font-size:13.5px}
  .상태{margin-top:19px;font-size:16.5px}
  .등{width:10px;height:10px}
  .우물{margin-top:17px;padding:19px 21px}
  .큰{gap:11px}
  .놓침{padding:6px 14px}
  .단추들{padding-top:19px}
  .단추{min-height:54px;font-size:16px}
  .브레이크{padding:12px 25px 6px}
  .단추.멈추기{min-height:58px;font-size:18px}
}

/* ── 빈 화면 / 처음 읽는 중 ─────────────────────────────────────────── */
.귀띔{color:var(--재);font-size:13.5px}
.빈칸{
  grid-column:1 / -1;
  /* 줄이 화면을 채우도록 늘어나므로, 안쪽 글은 가운데로 모은다. 안 그러면
   * 빈 화면에서 안내문 하나가 저 위에 붙어 있게 된다. */
  display:grid;align-content:center;justify-items:center;
  padding:52px 26px;text-align:center;
  background:rgba(255,255,255,.025);
  border:1px dashed var(--결진);border-radius:var(--카드R);
}
.빈칸 svg{width:30px;height:30px;color:var(--재);margin-bottom:14px}
.빈칸 p{margin:0 auto;max-width:34ch;color:var(--재);font-size:13.5px;line-height:1.65}

/* 처음 읽는 동안 자리를 미리 잡아 둔다. "읽는 중…" 한 줄만 두면 목록이 뜨는
 * 순간 화면이 통째로 뛴다. */
.뼈대{
  display:flex;flex-direction:column;
  padding:var(--여백);
  background:rgba(255,255,255,.035);border:1px solid var(--결);
  border-radius:var(--카드R);
}
.뼈대 i{
  flex:1;padding:16px 17px 17px;min-height:224px;
  background:linear-gradient(180deg,var(--판밝),var(--판));border-radius:var(--판R);
}
.뼈대 span{
  display:block;height:11px;border-radius:6px;background:rgba(255,255,255,.05);
  margin-bottom:12px;animation:숨쉬기 1.8s var(--곡선) infinite;
}
.뼈대 span:nth-child(1){width:46%;height:20px}
.뼈대 span:nth-child(2){width:34%}
.뼈대 span:nth-child(3){width:100%;height:66px;margin-top:16px}
.뼈대 span:nth-child(4){width:100%;height:46px;margin-top:16px}
@keyframes 숨쉬기{0%,100%{opacity:1}50%{opacity:.45}}

/* ── 알림(토스트) ───────────────────────────────────────────────────── */
.알림{
  position:fixed;z-index:50;
  left:12px;right:12px;
  /* **바닥이 아니라 위에 뜬다.** 카드가 화면 세로를 채우게 되면서 화면 바닥은
   * 늘 어느 카드의 브레이크 자리가 되었다. 언제 눌러도 안전한 유일한 단추를,
   * 결과를 알려 주는 쪽지가 15초 동안 덮으면 안 된다. 위로 올리면 덮는 것이
   * 없어서, 아래에 자리를 내주던 규칙(body.알림뜸)도 같이 없앴다. */
  top:calc(84px + env(safe-area-inset-top));
  display:flex;align-items:flex-start;gap:11px;
  padding:14px 16px;
  background:rgba(29,24,21,.92);color:var(--살);
  border:1px solid var(--결진);border-radius:18px;
  backdrop-filter:blur(16px);
  box-shadow:0 1px 0 var(--윗빛) inset, 0 20px 50px -18px rgba(0,0,0,.95);
  font-size:14.5px;line-height:1.5;
  animation:떠오르기 .42s var(--곡선);
  /* **손가락을 안 받는다.** 안에 누를 것이 하나도 없는데 상자는 상자여서,
   * 15초짜리 쪽지가 떠 있는 동안 그 아래로 지나가는 '중지' 의 탭을 통째로
   * 가로챈다. 페이드 꼬리를 안 쓰는 것과 똑같은 까닭이다(요약띠 참고) —
   * 이 화면에서 브레이크를 막는 물건은 하나도 있으면 안 된다. */
  pointer-events:none;
}
.알림 svg{width:17px;height:17px;margin-top:2px;color:var(--불)}
.알림 .글{flex:1;min-width:0;white-space:pre-line}
/* 요약띠가 떠 있으면 그 밑으로 내려간다. 경보 칩을 쪽지가 덮으면 안 된다 —
 * 놓친 것이 있다는 신호가 명령 결과에 가려지는 것이 제일 나쁜 순서다.
 * :has 를 모르는 브라우저에서는 84px 자리에 그대로 뜬다(덮되, 곧 사라진다). */
body:has(#요약:not([hidden])) .알림{
  top:calc(124px + env(safe-area-inset-top));
}
@keyframes 떠오르기{from{opacity:0;transform:translateY(-10px)}}
/* PC 에서 전폭 토스트를 그대로 늘리면 한 줄이 너무 길어 눈이 끝까지 못 간다. */
@media (min-width:720px){
  .알림{left:auto;right:24px;max-width:440px}
}

/* ── 등록 코드 창 ────────────────────────────────────────────────────
 * window.alert 을 안 쓰는 이유는 생김새가 아니다. **한 번 닫으면 코드를 다시
 * 볼 수 없다** — PC 앞으로 걸어가는 사이에 잘못 닫으면 코드를 새로 받아야
 * 한다. 여기서는 닫기 전까지 떠 있고 남은 시간을 세어 준다.
 */
/* **닫힌 창은 우리가 직접 숨긴다.** 브라우저 기본에도 dialog:not([open])
 * {display:none} 이 있지만, showModal 이 없는 브라우저는 <dialog> 자체를
 * 모르는 브라우저라 그 기본도 없다 — 그러면 창 속살(.창 카드째)이 목록 밑에
 * 늘 그려진다. hidden 을 !important 로 지키는 것과 같은 자리다. */
dialog:not([open]){display:none}
dialog{padding:0;border:none;background:transparent;max-width:100%;max-height:100%}
dialog::backdrop{background:rgba(4,3,2,.78);backdrop-filter:blur(4px)}
.창{
  width:min(340px,calc(100vw - 32px));
  padding:var(--여백);
  background:rgba(255,255,255,.05);
  border:1px solid var(--결진);border-radius:var(--카드R);
  box-shadow:0 30px 70px -20px rgba(0,0,0,.95);
}
.창 .속{
  padding:26px 22px 20px;text-align:center;
  background:linear-gradient(180deg,var(--판밝),var(--판));
  border-radius:var(--판R);
  box-shadow:0 1px 0 var(--윗빛) inset;
}
.창 h2{margin:0 0 4px;font-size:16px;font-weight:650;letter-spacing:-.015em}
.창 .귀띔{margin:0}
.코드값{
  margin:20px 0 8px;
  font:700 42px/1 var(--계기글꼴);letter-spacing:.15em;
  font-variant-numeric:tabular-nums;   /* font 단축이 지운 것을 되건다 */
  /* 자간이 오른쪽에도 붙어 가운데가 왼쪽으로 밀린다. 그만큼 되민다. */
  text-indent:.15em;
  color:var(--불);
  text-shadow:0 0 26px rgba(255,90,31,.45);
}
.남은때{font-size:12.5px;color:var(--재);min-height:19px;
        font-variant-numeric:tabular-nums}
.남은때.급함{color:var(--경보);font-weight:650}
.창 .단추{width:100%;flex:none;margin-top:20px;min-height:46px}

/* ── 기록판 ────────────────────────────────────────────────────────
 * **팝업이 아니다.** 카드의 판 위로 펼쳐져 덮이고, 비상 브레이크가 있는
 * 트레이는 안 덮는다 — 기록을 보는 중에도 '중지' 는 늘 눈에 보이고 늘
 * 눌린다. 화면 전체를 덮는 모달이면 그 한 가지가 깨진다.
 *
 * 판과 같은 자리·같은 반지름이라, 뜨는 것이 아니라 **그 판이 뒤집힌 것**
 * 처럼 보인다. 카드 높이는 하나도 안 변하므로 다른 카드가 밀리지 않는다.
 */
.기록판{
  position:absolute;inset:0;z-index:2;
  display:flex;flex-direction:column;
  padding:14px 16px 13px;
  /* 불투명해야 한다. 밑의 계기와 단추가 비쳐 보이면 글자가 겹쳐 읽힌다. */
  background:linear-gradient(180deg,#1b1613,var(--판));
  border-radius:var(--판R);
  box-shadow:0 1px 0 var(--윗빛) inset, 0 20px 40px -22px rgba(0,0,0,.95);
  animation:펼치기 .26s var(--곡선);
}
/* 위에서 아래로 펼쳐진다 — 누른 단추가 판 안에 있으므로 그 자리에서
 * 내려오는 것처럼 보인다. */
@keyframes 펼치기{from{opacity:0;transform:translateY(-10px)}}

.기록머리{
  display:flex;align-items:center;gap:9px;
  padding-bottom:9px;border-bottom:1px solid var(--결);
}
.기록제목{font-size:13px;font-weight:650;color:var(--살2);white-space:nowrap}
.기록누구{
  flex:1;min-width:0;font-size:12.5px;color:var(--재);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.기록닫기{
  position:relative;flex:0 0 auto;width:28px;height:28px;
  display:inline-grid;place-items:center;
  background:transparent;border:1px solid transparent;border-radius:9px;
  color:var(--재);cursor:pointer;
}
/* 보이는 크기는 28px 그대로, 누르는 넓이만 44px 로 넓힌다. */
.기록닫기::after{content:"";position:absolute;inset:-8px;border-radius:14px}
.기록닫기:hover{background:rgba(255,255,255,.07);color:var(--살)}
.기록닫기 svg{width:15px;height:15px}

/* min-height:0 이 없으면 flex 칸이 내용만큼 커져 스크롤이 안 생기고, 판이
 * 카드 밖으로 흘러넘친다. */
.기록몸{
  flex:1;min-height:0;
  margin-top:9px;padding-right:2px;
  overflow-y:auto;overscroll-behavior:contain;
}
.로그줄{
  display:flex;gap:12px;align-items:baseline;
  padding:3px 1px;font-size:13px;line-height:1.5;
}
/* 시각은 자리폭이 같아야 한다. 안 그러면 줄마다 말이 다른 자리에서 시작해
 * 목록이 지그재그로 보인다. */
.로그때{
  flex:0 0 auto;width:6.2em;
  color:var(--재);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;
}
.로그말{flex:1;min-width:0;color:var(--살2)}
/* 시각이 없는 줄(꼬리말·안내). 시각 자리를 비우고 통째로 쓴다. */
.로그줄.홑{display:block;color:var(--재);padding:9px 1px}

/* ── 로그인 ────────────────────────────────────────────────────────── */
.로그인{
  min-height:100svh;
  display:grid;place-items:center;
  padding:24px 16px calc(24px + env(safe-area-inset-bottom));
}
.로그인칸{
  width:min(360px,100%);
  padding:var(--여백);
  background:rgba(255,255,255,.04);
  border:1px solid var(--결);border-radius:var(--카드R);
  box-shadow:0 24px 60px -28px rgba(0,0,0,.95);
}
.로그인칸 .속{
  padding:30px 24px 24px;
  background:linear-gradient(180deg,var(--판밝),var(--판));
  border-radius:var(--판R);
  box-shadow:0 1px 0 var(--윗빛) inset;
}
.로그인칸 .표식{width:42px;height:42px;border-radius:14px;margin:0 auto 18px}
.로그인칸 .표식 svg{width:23px;height:23px}
.로그인칸 h1{
  margin:0 0 5px;font-size:19px;font-weight:650;text-align:center;
  letter-spacing:-.022em;
}
.로그인칸 .귀띔{text-align:center;margin:0 0 24px}
.줄{margin-bottom:13px}
.줄 label{
  display:block;margin-bottom:7px;
  font-size:12.5px;font-weight:650;color:var(--재);
}
input[type=text],input[type=password]{
  width:100%;min-height:48px;padding:0 14px;
  border:1px solid var(--결);border-radius:14px;
  background:var(--우물);color:var(--살);
  box-shadow:inset 0 1px 2px rgba(0,0,0,.5);
  /* 16px 아래로 내려가면 iOS 사파리가 입력칸을 누를 때 화면을 확대한다. */
  font:400 16px/1 var(--글꼴);
  transition:border-color .35s var(--곡선),box-shadow .35s var(--곡선);
}
input[type=text]:focus,input[type=password]:focus{
  border-color:var(--불);outline:none;
  box-shadow:inset 0 1px 2px rgba(0,0,0,.5), 0 0 0 3px var(--불연);
}
.로그인칸 .단추{width:100%;flex:none;margin-top:8px;min-height:50px;font-size:15.5px}
/* 실패 문구. 자리를 미리 잡아 두지 않으면 뜰 때 단추가 밀린다. */
.말{margin:15px 0 0;min-height:19px;font-size:13px;color:var(--경보);
    text-align:center;line-height:1.45}

/* ── 움직임을 줄여 달라고 한 사람에게 ─────────────────────────────── */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  /* 도는 점은 멈추면 뜻이 사라진다. 이것만 남기되 아주 느리게 돌린다. */
  .단추.도는중::after{
    animation:돌기 2.6s linear infinite !important;
    animation-duration:2.6s !important;
    animation-iteration-count:infinite !important;
  }
}
