: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); } .app-footer { text-align: center; padding: var(--space-4) 0 var(--space-2); font-size: 13px; } .app-footer a { 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="date"], input[type="password"], select, textarea { 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); } textarea { resize: vertical; min-height: 90px; line-height: 1.5; } select { cursor: pointer; } input[type="file"] { width: 100%; font-family: inherit; font-size: 14px; color: var(--color-text-muted); } input[type="color"] { width: 56px; height: 40px; padding: 2px; border: 1px solid var(--color-border); border-radius: var(--radius-control); background: var(--color-bg); cursor: pointer; } 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; } /* 저널 기분 선택 pill */ .mood-picker { display: flex; gap: 6px; flex-wrap: wrap; } .mood-pill { border-radius: 999px; border: 1px solid var(--color-border); background: transparent; color: var(--color-text-muted); font-size: 14px; padding: 8px 12px; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; } .mood-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); } /* 저널링 */ .journal-day-dots { display: flex; gap: 2px; } .journal-day-dot { width: 5px; height: 5px; border-radius: 50%; } .journal-prompt-card, .on-this-day-card { margin-top: var(--space-2); padding: var(--space-2); border-radius: var(--radius-control); background: var(--color-success-tint); font-size: 14px; } .journal-entry-item { padding: 10px 0; border-bottom: 1px solid var(--color-border); } .journal-entry-item:last-child { border-bottom: none; } .journal-entry-title { font-weight: 600; margin-top: 6px; } .journal-entry-content { margin-top: 4px; line-height: 1.6; } .journal-preview { margin-top: 6px; padding: 10px 12px; border: 1px dashed var(--color-border); border-radius: var(--radius-control); background: var(--color-bg); min-height: 24px; font-size: 14px; } /* 마크다운 에디터 툴바 (EasyMDE는 toolbar:false로 끄고 여기서 자체 버튼으로 대체 — EasyMDE 기본 툴바는 Font Awesome CDN을 전제로 해서 이 앱의 "CDN 금지" 원칙과 안 맞는다) */ .markdown-toolbar { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; } .md-tool-btn { min-width: 30px; height: 30px; padding: 0 6px; border: 1px solid var(--color-border); border-radius: 6px; background: var(--color-surface); color: var(--color-text); font-size: 14px; cursor: pointer; } .md-tool-btn:active { background: var(--color-bg); } /* EasyMDE(CodeMirror) 컨테이너를 이 앱의 입력 필드 톤에 맞춘다 */ .markdown-editor + .EasyMDEContainer .CodeMirror { border: 1px solid var(--color-border); border-radius: var(--radius-control); background: var(--color-bg); color: var(--color-text); font-family: inherit; font-size: 15px; padding: 6px 8px; } .markdown-editor + .EasyMDEContainer .CodeMirror-cursor { border-left-color: var(--color-text); } .markdown-editor + .EasyMDEContainer .editor-statusbar { color: var(--color-text-muted); } .journal-entry-content > *:first-child { margin-top: 0; } .journal-entry-content > *:last-child { margin-bottom: 0; } .journal-entry-content p, .journal-entry-content ul, .journal-entry-content ol, .journal-entry-content blockquote, .journal-entry-content pre { margin: 0 0 8px; } .journal-entry-content h1, .journal-entry-content h2, .journal-entry-content h3, .journal-entry-content h4 { margin: 12px 0 6px; line-height: 1.3; } .journal-entry-content h1 { font-size: 19px; } .journal-entry-content h2 { font-size: 17px; } .journal-entry-content h3, .journal-entry-content h4 { font-size: 15px; } .journal-entry-content ul, .journal-entry-content ol { padding-left: 20px; } .journal-entry-content blockquote { margin-left: 0; padding-left: 10px; border-left: 3px solid var(--color-accent); color: var(--color-text-muted); } .journal-entry-content code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 4px; padding: 1px 5px; } .journal-entry-content pre { background: var(--color-bg); border: 1px solid var(--color-border); border-radius: var(--radius-control); padding: 10px; overflow-x: auto; } .journal-entry-content pre code { border: none; padding: 0; } .journal-entry-content a { color: var(--color-accent); } .journal-entry-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } .tag-chip { font-size: 12px; color: var(--color-text-muted); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 999px; padding: 2px 8px; } .mood-icon { font-size: 18px; } .attachment-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: 8px; margin-top: 8px; } .attachment-thumb { position: relative; aspect-ratio: 1; border-radius: var(--radius-control); overflow: hidden; border: 1px solid var(--color-border); } .attachment-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; } .attachment-video-link { display: flex; align-items: center; justify-content: center; height: 100%; font-size: 12px; text-align: center; color: var(--color-text-muted); text-decoration: none; padding: 4px; } .attachment-delete-btn { position: absolute; top: 2px; right: 2px; width: 20px; height: 20px; border-radius: 50%; border: none; background: rgba(0, 0, 0, 0.6); color: #fff; font-size: 14px; line-height: 1; cursor: pointer; } /* 랜딩 페이지 (/) */ .landing { max-width: 480px; margin: 0 auto; padding: var(--space-4) var(--space-2) var(--space-4); display: flex; flex-direction: column; gap: var(--space-4); } .landing-hero { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; } .landing-brand { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 700; color: var(--color-accent); letter-spacing: -0.01em; } .landing-brand img { width: 24px; height: 24px; border-radius: 6px; } .landing-hero h1 { font-size: 32px; font-weight: 700; letter-spacing: -0.02em; text-wrap: balance; margin: 0; } .landing-tagline { font-size: 16px; color: var(--color-text-muted); margin: 0; } /* 요일 스트릭 시연: 실제 습관 체크 인터랙션을 그대로 축소해 보여준다 */ .landing-streak { display: flex; gap: 8px; } .landing-day { width: 34px; height: 34px; border-radius: 999px; border: 1px solid var(--color-border); display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--color-text-muted); background: var(--color-surface); } .landing-day.done { background: var(--color-accent); border-color: var(--color-accent); color: #fff; opacity: 0; animation: landing-day-in 0.35s ease-out forwards; } .landing-day.done svg { width: 16px; height: 16px; } .landing-day:nth-of-type(1).done { animation-delay: 0.1s; } .landing-day:nth-of-type(2).done { animation-delay: 0.25s; } .landing-day:nth-of-type(3).done { animation-delay: 0.4s; } .landing-day:nth-of-type(4).done { animation-delay: 0.55s; } .landing-day:nth-of-type(5).done { animation-delay: 0.7s; } @keyframes landing-day-in { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: scale(1); } } @media (prefers-reduced-motion: reduce) { .landing-day.done { opacity: 1; animation: none; } } .landing-copy { font-size: 15.5px; line-height: 1.75; color: var(--color-text); display: flex; flex-direction: column; gap: var(--space-2); } .landing-copy strong { color: var(--color-accent); } .landing-features { display: grid; gap: var(--space-2); } .landing-feature { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-card); } .landing-feature svg { flex-shrink: 0; width: 20px; height: 20px; color: var(--color-accent); } .landing-feature p { margin: 0; font-size: 14px; color: var(--color-text); } .landing-feature p strong { display: block; font-size: 14.5px; margin-bottom: 2px; }