:root { --color-bg: #f5f4ef; --color-surface: #ffffff; --color-text: #2b2a27; --color-text-muted: #6b6a66; --color-accent: #d97757; --color-accent-hover: #c15f3c; --color-accent-rgb: 217, 119, 87; --color-border: #e8e6df; --color-success: #4f7a5a; --color-success-tint: rgba(79, 122, 90, 0.08); --color-danger: #b3543f; --color-gold: #a8791a; --color-gold-tint: rgba(168, 121, 26, 0.12); --radius-card: 14px; --radius-control: 10px; --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.04); --space-1: 8px; --space-2: 16px; --space-3: 24px; --space-4: 32px; --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Pretendard", "Malgun Gothic", sans-serif; } @media (prefers-color-scheme: dark) { :root { --color-bg: #1f1e1b; --color-surface: #2a2926; --color-text: #edebe4; --color-text-muted: #a8a69f; --color-accent: #e08962; --color-accent-hover: #eb9c78; --color-accent-rgb: 224, 137, 98; --color-border: #3a3833; --color-success: #6fa47c; --color-success-tint: rgba(111, 164, 124, 0.14); --color-danger: #d97c68; --color-gold: #d9b84f; --color-gold-tint: rgba(217, 184, 79, 0.16); --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.2); } } * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; } [x-cloak] { display: none !important; } html, body { margin: 0; padding: 0; overscroll-behavior-y: none; } body { background: var(--color-bg); color: var(--color-text); font-family: var(--font-sans); font-size: 15px; line-height: 1.55; -webkit-font-smoothing: antialiased; } a { color: inherit; } .app-shell { max-width: 640px; margin: 0 auto; padding: var(--space-3) var(--space-2) var(--space-4); } @media (min-width: 900px) { .app-shell { max-width: 760px; padding-top: var(--space-4); } .app-shell.wide { max-width: 960px; } } h1, h2, h3 { font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; margin: 0 0 var(--space-2); } h1 { font-size: 22px; } h2 { font-size: 17px; } p { margin: 0 0 var(--space-2); color: var(--color-text-muted); } /* iOS 홈 화면 추가 안내 배너 */ .ios-install-banner { display: none; align-items: center; justify-content: space-between; gap: var(--space-2); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-control); box-shadow: var(--shadow-card); padding: 10px 12px; margin-bottom: var(--space-2); font-size: 13px; color: var(--color-text); } .ios-install-banner button { flex-shrink: 0; background: none; border: none; color: var(--color-text-muted); font-size: 18px; line-height: 1; cursor: pointer; padding: 0 2px; } /* 상단 네비게이션 */ .top-nav { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; row-gap: var(--space-1); margin-bottom: var(--space-3); } .top-nav .brand { font-weight: 600; font-size: 17px; white-space: nowrap; } .top-nav .nav-links { display: flex; gap: var(--space-1); } .top-nav .nav-links a { text-decoration: none; color: var(--color-text-muted); font-size: 14px; white-space: nowrap; padding: 6px 10px; border-radius: var(--radius-control); } .top-nav .nav-links a.active { color: var(--color-text); background: var(--color-surface); box-shadow: var(--shadow-card); } .top-nav .nav-user { display: flex; align-items: center; flex-shrink: 0; gap: var(--space-1); font-size: 13px; color: var(--color-text-muted); } .top-nav .nav-user span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 96px; } .btn-link { background: none; border: none; padding: 0; font: inherit; font-size: 13px; color: var(--color-text-muted); text-decoration: underline; white-space: nowrap; flex-shrink: 0; cursor: pointer; } /* 하단 탭바 (모바일 전용) — 기본은 숨김, 좁은 화면에서만 노출 */ .bottom-tab-bar { display: none; } /* 좁은 화면: 상단은 브랜드+유저정보만 남기고, 이동 네비게이션은 하단 탭바로 옮긴다 */ @media (max-width: 480px) { .top-nav .nav-links { display: none; } .app-shell { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px) + var(--space-2)); } .bottom-tab-bar { display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; background: var(--color-surface); border-top: 1px solid var(--color-border); padding-bottom: env(safe-area-inset-bottom, 0px); } .bottom-tab-bar .tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 8px 4px 6px; text-decoration: none; color: var(--color-text-muted); font-size: 11px; touch-action: manipulation; } .bottom-tab-bar .tab-item svg { width: 22px; height: 22px; } .bottom-tab-bar .tab-item.active { color: var(--color-accent); } } /* 카드 */ .card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-card); box-shadow: var(--shadow-card); padding: var(--space-3); margin-bottom: var(--space-2); } /* 버튼 */ .btn { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; gap: 6px; border: none; border-radius: var(--radius-control); padding: 10px 16px; font-size: 14px; font-weight: 500; white-space: nowrap; cursor: pointer; font-family: inherit; transition: background-color 0.15s ease, opacity 0.15s ease; touch-action: manipulation; } .btn-primary { background: var(--color-accent); color: #fff; } .btn-primary:hover { background: var(--color-accent-hover); } .btn-secondary { background: transparent; color: var(--color-text); border: 1px solid var(--color-border); } .btn-secondary:hover { background: var(--color-bg); } .btn-danger-ghost { background: transparent; color: var(--color-danger); border: 1px solid var(--color-border); } .btn-block { width: 100%; } /* 입력 */ input[type="text"], input[type="time"], input[type="password"] { width: 100%; font-family: inherit; font-size: 15px; padding: 10px 12px; border: 1px solid var(--color-border); border-radius: var(--radius-control); background: var(--color-bg); color: var(--color-text); } label { display: block; font-size: 13px; color: var(--color-text-muted); margin-bottom: 6px; } .field { margin-bottom: var(--space-2); } .form-error-text { color: var(--color-danger); font-size: 13px; margin: -8px 0 var(--space-2); min-height: 1em; } /* 탭 — 좁은 화면에서 4개가 다 안 들어가면 줄바꿈 대신 가로 스크롤. 양 끝에 스크롤 가능 방향으로만 그림자가 지도록 하는 순수 CSS 트릭: 앞쪽 두 레이어(배경색→투명 그라데이션, background-attachment: local)는 콘텐츠와 같이 스크롤되면서 탭 텍스트를 가려 페이드아웃시키고, 뒤쪽 두 레이어(radial-gradient 그림자, attachment: scroll)는 스크롤 컨테이너 기준으로 고정되어 있다 — 콘텐츠 레이어가 그 위를 덮을 수 있을 때만(=그 방향으로 더 스크롤할 내용이 있을 때만) 그림자가 드러나 보인다. 끝까지 스크롤하면 콘텐츠 레이어가 그림자를 완전히 덮어 자연스럽게 사라진다. */ .tabs { display: flex; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; gap: 6px; margin-bottom: var(--space-2); border-bottom: 1px solid var(--color-border); background: linear-gradient(to right, var(--color-bg) 50%, transparent) left, linear-gradient(to left, var(--color-bg) 50%, transparent) right, radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, 0.2), transparent) left, radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.2), transparent) right; background-repeat: no-repeat; background-color: var(--color-bg); background-size: 20px 100%, 20px 100%, 10px 100%, 10px 100%; background-attachment: local, local, scroll, scroll; } .tabs a { text-decoration: none; color: var(--color-text-muted); font-size: 14px; padding: 10px 4px; margin-right: var(--space-2); border-bottom: 2px solid transparent; white-space: nowrap; flex-shrink: 0; touch-action: manipulation; } .tabs a.active { color: var(--color-text); border-bottom-color: var(--color-accent); font-weight: 600; } /* 요일 선택 pill */ .weekday-picker { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; } .weekday-pill { width: 36px; height: 36px; border-radius: 999px; border: 1px solid var(--color-border); background: var(--color-bg); color: var(--color-text); font-size: 13px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; } .weekday-pill.selected { background: var(--color-accent); border-color: var(--color-accent); color: #fff; } .everyday-btn { border-radius: 999px; border: 1px solid var(--color-border); background: transparent; color: var(--color-text-muted); font-size: 13px; padding: 8px 14px; cursor: pointer; margin-left: 4px; } .everyday-btn.selected { border-color: var(--color-accent); color: var(--color-accent); } /* 목표 기간 난이도 선택 */ .difficulty-picker { display: flex; gap: 6px; flex-wrap: wrap; } .difficulty-pill { border-radius: 999px; border: 1px solid var(--color-border); background: transparent; color: var(--color-text-muted); font-size: 13px; padding: 8px 14px; cursor: pointer; } .difficulty-pill.selected { background: var(--color-accent); border-color: var(--color-accent); color: #fff; } .difficulty-hint { font-size: 12px; color: var(--color-text-muted); margin-top: 6px; } .goal-progress-badge { font-size: 12px; color: var(--color-text-muted); } /* 습관 리스트 아이템 */ .habit-item { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px var(--space-2); padding: 12px 4px; border-bottom: 1px solid var(--color-border); touch-action: manipulation; } .habit-item:last-child { border-bottom: none; } .habit-item.today-checked { background: var(--color-success-tint); border-radius: var(--radius-control); margin: 0 -4px; padding-left: 8px; padding-right: 8px; } .habit-item-main { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1 1 auto; } .habit-item-name { font-size: 15px; overflow-wrap: break-word; word-break: break-word; } .habit-item-condition { font-size: 13px; color: var(--color-text-muted); margin-top: 2px; } .habit-item-meta { font-size: 12px; color: var(--color-text-muted); } .habit-item-stats { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; } .drag-handle { flex-shrink: 0; cursor: grab; color: var(--color-text-muted); font-size: 18px; line-height: 1; padding: 4px 2px; touch-action: none; user-select: none; } .sortable-ghost { opacity: 0.4; } .sortable-chosen .habit-item { background: var(--color-bg); border-radius: var(--radius-control); } .habit-item-actions { display: flex; gap: 6px; flex-shrink: 0; } .check-indicator { width: 26px; height: 26px; padding: 0; margin: 0; border-radius: 50%; border: 2px solid var(--color-border); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; background: transparent; font-family: inherit; font-size: 13px; line-height: 1; transition: background-color 0.15s ease, border-color 0.15s ease; } .check-indicator.checked { background: var(--color-success); border-color: var(--color-success); color: #fff; } .empty-state { text-align: center; color: var(--color-text-muted); padding: var(--space-4) var(--space-2); font-size: 14px; } .badge { display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 999px; background: var(--color-bg); color: var(--color-text-muted); border: 1px solid var(--color-border); } .badge-milestone { background: var(--color-gold-tint); color: var(--color-gold); border-color: var(--color-gold); font-weight: 600; } .celebration-banner { display: flex; align-items: center; gap: 8px; padding: 12px 16px; margin-bottom: var(--space-2); border-radius: var(--radius-card); background: var(--color-gold-tint); border: 1px solid var(--color-gold); color: var(--color-text); font-size: 14px; animation: celebration-pop 0.4s ease-out; } @keyframes celebration-pop { from { opacity: 0; transform: scale(0.95) translateY(-4px); } to { opacity: 1; transform: scale(1) translateY(0); } } /* 레벨 배지 & XP 진행바 */ .level-badge { background: var(--color-gold-tint); color: var(--color-gold); border-color: var(--color-gold); font-weight: 600; } .xp-bar-wrap { display: flex; align-items: center; gap: 6px; margin-top: 4px; } .xp-bar { flex: 1 1 auto; height: 5px; border-radius: 999px; background: var(--color-bg); border: 1px solid var(--color-border); overflow: hidden; } .xp-bar-fill { height: 100%; border-radius: 999px; background: var(--color-accent); } .xp-bar-label { flex-shrink: 0; font-size: 11px; color: var(--color-text-muted); } .account-level-card { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); } .account-level-card .level-badge { font-size: 13px; padding: 4px 12px; } .account-level-card .xp-bar-wrap { flex: 1 1 auto; max-width: 220px; margin-top: 0; } .nav-level-pill { display: inline-block; font-size: 11px; font-weight: 600; padding: 1px 7px; border-radius: 999px; background: var(--color-gold-tint); color: var(--color-gold); border: 1px solid var(--color-gold); flex-shrink: 0; } /* 월별 캘린더 */ .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; margin-bottom: 4px; } .calendar-weekday { text-align: center; font-size: 12px; color: var(--color-text-muted); padding: 4px 0; } .calendar-cell { aspect-ratio: 1; border-radius: 8px; border: 1px solid var(--color-border); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; } .calendar-cell.muted { opacity: 0.35; } .calendar-date { font-size: 12px; font-weight: 500; } .calendar-ratio { font-size: 10px; color: var(--color-text-muted); } .calendar-cell.clickable { cursor: pointer; } .day-detail-card { margin-top: var(--space-2); } .day-detail-list { display: flex; flex-direction: column; gap: 8px; } .day-detail-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--color-border); } .day-detail-item:last-child { border-bottom: none; } .day-detail-status-checked { color: var(--color-success); border-color: var(--color-success); } .day-detail-status-missed { color: var(--color-danger); border-color: var(--color-danger); } /* 주별 매트릭스 */ .week-matrix { width: 100%; border-collapse: collapse; font-size: 13px; white-space: nowrap; } .week-matrix th, .week-matrix td { padding: 10px 8px; text-align: center; border-bottom: 1px solid var(--color-border); } .week-matrix th:first-child, .week-matrix td:first-child { text-align: left; } .week-matrix th { color: var(--color-text-muted); font-weight: 500; font-size: 12px; } .wm-check { color: var(--color-success); font-weight: 700; } .wm-dash { color: var(--color-border); }