Files
habit-tracker/app/static/css/style.css
T
shinalokandClaude Opus 5 0e8688c25b
CI/CD / test (push) Successful in 45s
CI/CD / deploy (push) Successful in 1m29s
make app name and purpose machine-readable on the landing page
Google OAuth branding review rejected the app twice with "no description of
the app purpose on the homepage" and "app name does not match the homepage",
even though both were present in Korean. Two likely causes, both addressed:

- The h1 wrapped an alt="" logo image before the text, so the app name could
  not be extracted from it. The image now sits outside the h1, leaving the
  heading as plain text.
- The page was Korean-only. The app name is now "해빗랩 (HabitLab)" (matching
  the console exactly), and the title, meta description and a new About
  section carry an English description of the app purpose and its use of
  Google account data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 18:29:42 +09:00

1317 lines
26 KiB
CSS

: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);
}
.app-footer a + a::before {
content: "·";
margin: 0 6px;
}
/* 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;
overflow: hidden; /* 안에서 뭐가 카드 폭보다 커지려 해도 밖으로 안 새어나가게 */
}
.markdown-editor + .EasyMDEContainer .CodeMirror-cursor {
border-left-color: var(--color-text);
}
.markdown-editor + .EasyMDEContainer .editor-statusbar {
color: var(--color-text-muted);
}
/* 원본 해상도가 큰 이미지를 붙여넣었을 때 에디터/미리보기 폭을 넘어가지 않게 캡핑.
.journal-entry-content img가 미리보기(.journal-preview)는 이미 커버하지만, 에디터 쪽
(CodeMirror가 마크다운 이미지를 인라인 위젯으로 그리는 경우)도 같은 규칙을 강제로 적용. */
.markdown-editor + .EasyMDEContainer .CodeMirror img {
max-width: 100% !important;
height: auto !important;
}
.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-content img {
max-width: 100%;
height: auto;
border-radius: var(--radius-control);
display: block;
margin: 4px 0;
}
.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;
}
/* 로고 + 앱 이름 h1 묶음. h1은 시각적으로 작은 브랜드 라벨이지만 문서 구조상 최상위 제목이다. */
.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 h1 {
margin: 0;
font-size: inherit;
font-weight: inherit;
color: inherit;
letter-spacing: inherit;
}
.landing-brand img {
width: 24px;
height: 24px;
border-radius: 6px;
}
.landing-hero-title {
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;
}
/* 기능 설명 / 계정 안내 — 구글 브랜딩 심사가 홈페이지에서 확인하는 "앱의 목적" 설명 영역. */
.landing-section h2 {
font-size: 17px;
font-weight: 700;
margin: 0 0 var(--space-2);
}
.landing-list {
margin: 0;
padding-left: 1.1em;
display: flex;
flex-direction: column;
gap: 10px;
font-size: 14.5px;
line-height: 1.65;
color: var(--color-text);
}
.landing-list strong {
color: var(--color-accent);
}
.landing-note {
margin: 0 0 var(--space-2);
font-size: 13.5px;
line-height: 1.7;
color: var(--color-text-muted);
}
.landing-note:last-child {
margin-bottom: 0;
}
.landing-note strong {
color: var(--color-text);
}