/* ============================================================
   Habits - monochrome dark, serif, minimal
   One hue only: a warm off-white on near-black. Emphasis comes
   from brightness and weight, never from colour.
   ============================================================ */

/* ---------- Fraunces (self-hosted, so it works offline) ---------- */
@font-face {
  font-family: 'Fraunces';
  src: url('fonts/fraunces-latin.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  src: url('fonts/fraunces-latin-ext.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ------------------------------------------------------------
   Two themes, one hue.

   Every surface is either the ink colour or the background, and
   every shade in between is the ink at some alpha. Swapping the
   theme swaps those two and nothing else, so the whole interface
   inverts without a single extra rule elsewhere in this file.

   The alphas are not mirrored exactly: dark ink on a pale ground
   reads stronger than pale ink on a dark one, so the light theme
   pulls the quiet tones down slightly to keep the same hush.
   ------------------------------------------------------------ */
:root {
  /* the only colour in the app, at six strengths */
  --ink:    #f2efe9;
  --bg:     #201f1f;

  --elev:      #2a2828;                  /* sheet */
  --elev-soft: rgba(42, 40, 40, .86);    /* floating pills */
  --scrim:     rgba(12, 11, 11, .72);

  --t-1:    rgba(242, 239, 233, 1);      /* headlines, completed things */
  --t-2:    rgba(242, 239, 233, .78);    /* habit names */
  --t-3:    rgba(242, 239, 233, .44);    /* secondary text */
  --t-4:    rgba(242, 239, 233, .24);    /* inactive marks */
  --t-5:    rgba(242, 239, 233, .11);    /* hairlines, empty tracks */
  --t-6:    rgba(242, 239, 233, .055);   /* faint fills */

  --serif: 'Fraunces', ui-serif, Georgia, 'Times New Roman', serif;

  /* Fraunces variable axes. SOFT rounds the terminals, WONK swaps in
     the curvier alternate letterforms - that is the "curvy" part. */
  --wonk-on:  'SOFT' 80, 'WONK' 1;
  --wonk-off: 'SOFT' 60, 'WONK' 0;

  --pad: 22px;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
}

:root[data-theme="light"] {
  --ink:    #201f1f;
  --bg:     #e9e9e9;

  --elev:      #fbf9f5;
  --elev-soft: rgba(251, 249, 245, .88);
  --scrim:     rgba(32, 31, 31, .34);

  --t-1:    rgba(32, 31, 31, 1);
  --t-2:    rgba(32, 31, 31, .80);
  --t-3:    rgba(32, 31, 31, .46);
  --t-4:    rgba(32, 31, 31, .26);
  --t-5:    rgba(32, 31, 31, .13);
  --t-6:    rgba(32, 31, 31, .045);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html { background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  transition: background-color .35s ease, color .35s ease;
  color: var(--t-2);
  font-family: var(--serif);
  font-variation-settings: 'opsz' 14, 'wght' 400, var(--wonk-off);
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
}

button, input { font: inherit; font-family: var(--serif); color: inherit; }
h1, h2, p, ul { margin: 0; }
ul { list-style: none; padding: 0; }
[hidden] { display: none !important; }

/* tiny uppercase label, used for day initials and hints */
.micro {
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  font-variation-settings: 'opsz' 9, 'wght' 500, var(--wonk-off);
  color: var(--t-4);
}

/* ---------- buttons ---------- */
.btn {
  appearance: none;
  border: 1px solid var(--t-5);
  background: transparent;
  color: var(--t-2);
  border-radius: 999px;
  padding: 13px 22px;
  cursor: pointer;
  font-variation-settings: 'opsz' 14, 'wght' 450, var(--wonk-off);
  transition: background .18s, border-color .18s, transform .08s;
}
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.btn-danger  { border-color: transparent; color: var(--t-3); }
.btn-danger:active { color: var(--t-1); }

/* ============================================================
   Password gate
   ============================================================ */
.gate {
  position: fixed; inset: 0;
  display: grid; place-items: center;
  padding: 28px; background: var(--bg); z-index: 50;
}
.gate-box { width: 100%; max-width: 260px; display: grid; gap: 14px; text-align: center; }
.gate-mark { color: var(--t-3); display: grid; place-items: center; margin-bottom: 18px; }
.gate input {
  width: 100%;
  background: transparent;
  border: 0; border-bottom: 1px solid var(--t-5);
  border-radius: 0;
  padding: 12px 4px;
  text-align: center;
  outline: none;
  color: var(--t-1);
  transition: border-color .2s;
}
.gate input::placeholder { color: var(--t-4); }
.gate input:focus { border-bottom-color: var(--t-3); }
.gate-error { color: var(--t-3); font-size: 13px; min-height: 20px; font-style: italic; }

/* ============================================================
   Frame
   ============================================================ */
.app {
  max-width: 520px; margin: 0 auto;
  padding: calc(var(--safe-t) + 40px) var(--pad) calc(var(--safe-b) + 120px);
}

.head { margin-bottom: 30px; }
.head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; }

.head h1 {
  font-size: 40px; line-height: 1.05;
  color: var(--t-1);
  font-variation-settings: 'opsz' 90, 'wght' 380, var(--wonk-on);
  letter-spacing: -.015em;
}
#dateLabel { margin-top: 6px; font-size: 15px; color: var(--t-3); font-style: italic; }
.progress-label { margin-top: 22px; font-size: 13px; color: var(--t-3); }

.head-right { display: flex; align-items: center; gap: 12px; margin-top: 6px; flex: none; }

.icon-btn {
  width: 32px; height: 32px; border-radius: 50%;
  border: 0; background: transparent; color: var(--t-4);
  display: grid; place-items: center; cursor: pointer;
  transition: color .2s, transform .12s;
}
.icon-btn:hover { color: var(--t-3); }
.icon-btn:active { transform: scale(.86); }

/* progress ring */
.ring { position: relative; width: 38px; height: 38px; flex: none; }
.ring svg { transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 1.5; stroke-linecap: round; }
.ring-bg { stroke: var(--t-5); }
.ring-fg {
  stroke: var(--t-1);
  stroke-dasharray: 119.4; stroke-dashoffset: 119.4;
  transition: stroke-dashoffset .4s cubic-bezier(.4,0,.2,1);
}

/* ============================================================
   Habit rows - no cards, just hairlines
   ============================================================ */
.list { display: block; }

.habit {
  padding: 20px 0;
  border-top: 1px solid var(--t-5);
  /* iOS pops up a selection callout if a finger rests on text. Nothing
     here is meant to be selected, so switch it off and taps stay taps. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.habit { padding-bottom: 12px; }   /* the strip supplies the rest */
.habit:last-child { border-bottom: 1px solid var(--t-5); }

.habit-main { display: flex; align-items: center; gap: 16px; }

.habit-tap {
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; padding: 0; text-align: left; cursor: pointer;
}
.habit-name {
  font-size: 19px; color: var(--t-2);
  font-variation-settings: 'opsz' 30, 'wght' 400, var(--wonk-on);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color .2s;
}
.habit.is-done .habit-name { color: var(--t-1); }

.habit-meta {
  display: flex; align-items: center; gap: 7px;
  flex-wrap: wrap;                 /* wrap between items... */
  margin-top: 2px; font-size: 12px; color: var(--t-4);
  font-variant-numeric: tabular-nums;
}
.habit-meta > span { white-space: nowrap; }   /* ...never inside one */
.streak-on { color: var(--t-3); }

/* binary mark */
.check {
  flex: none; width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid var(--t-4);
  background: transparent;
  display: grid; place-items: center;
  color: transparent; cursor: pointer;
  transition: background .2s, border-color .2s, color .2s, transform .1s;
}
.check:active { transform: scale(.88); }
.habit.is-done .check { background: var(--ink); border-color: var(--ink); color: var(--bg); }

/* count stepper */
.stepper { flex: none; display: flex; align-items: center; gap: 2px; }
.step {
  width: 30px; height: 30px; border-radius: 50%;
  border: 0; background: transparent; color: var(--t-3);
  display: grid; place-items: center; cursor: pointer;
  transition: color .2s, transform .1s;
}
.step:active { transform: scale(.85); }
.step:disabled { color: var(--t-5); cursor: default; }
.count-val {
  min-width: 44px; text-align: center;
  font-variant-numeric: tabular-nums;
  font-size: 16px; color: var(--t-3);
  font-variation-settings: 'opsz' 20, 'wght' 400, var(--wonk-off);
}
.habit.is-done .count-val { color: var(--t-1); }

/* ---------- 7 day strip ---------- */
/* The strip is a button. The dots are only 5px tall, so the padding is
   there purely to give a thumb something to hit. */
.strip {
  display: flex; align-items: center; gap: 9px;
  width: 100%;
  /* The dots are 5px tall. The padding is the tap target, and the row's own
     bottom padding is trimmed to match so the spacing looks unchanged. */
  margin-top: 4px;
  padding: 12px 0 12px 1px;
  border: 0; background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.dot { width: 5px; height: 5px; border-radius: 50%; background: var(--t-5); flex: none; }
.dot.on   { background: var(--t-1); }
.dot.part { background: linear-gradient(90deg, var(--t-2) 50%, var(--t-5) 50%); }
.dot.today { outline: 1px solid var(--t-5); outline-offset: 3px; }

/* ---------- expanded month ---------- */
.month { margin-top: 12px; }
.month-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.month-title {
  font-size: 15px; color: var(--t-3); font-style: italic;
  font-variation-settings: 'opsz' 20, 'wght' 400, var(--wonk-on);
}
.month-nav { display: flex; gap: 10px; }
.month-nav button {
  width: 26px; height: 26px; border-radius: 50%;
  border: 0; background: transparent; color: var(--t-3);
  display: grid; place-items: center; cursor: pointer;
  transition: color .2s;
}
.month-nav button:disabled { color: var(--t-5); cursor: default; }

.grid { display: grid; grid-template-columns: repeat(7, 1fr); row-gap: 7px; }
.grid-dow {
  font-size: 9px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--t-4); text-align: center; padding-bottom: 10px;
  font-variation-settings: 'opsz' 9, 'wght' 500, var(--wonk-off);
}
.day {
  width: 32px; height: 32px; margin: 0 auto;
  border-radius: 50%;
  border: 1px solid transparent;
  background: transparent;
  color: var(--t-3);
  font-size: 12px; font-variant-numeric: tabular-nums;
  font-variation-settings: 'opsz' 14, 'wght' 400, var(--wonk-off);
  display: grid; place-items: center; cursor: pointer;
  transition: background .18s, color .18s, transform .1s;
}
.day:active { transform: scale(.85); }
.day.blank { cursor: default; }
.day.on { background: var(--ink); color: var(--bg); }
.day.future, .day.pre { color: var(--t-5); cursor: default; }
.day.today { border-color: var(--t-4); }
.day.today.on { border-color: var(--ink); }
.month-hint { margin-top: 18px; font-size: 11px; color: var(--t-4); font-style: italic; }

/* ============================================================
   Empty state / add / status
   ============================================================ */
.empty { text-align: center; padding: 70px 0; display: grid; gap: 22px; justify-items: center; }
.empty p { color: var(--t-4); font-style: italic; }

.foot {
  position: fixed; left: 0; right: 0;
  bottom: calc(var(--safe-b) + 26px);
  display: grid; place-items: center; pointer-events: none;
}
.fab {
  pointer-events: auto;
  width: 50px; height: 50px; border-radius: 50%;
  border: 1px solid var(--t-5);
  background: var(--elev-soft);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  color: var(--t-2);
  display: grid; place-items: center; cursor: pointer;
  transition: transform .12s, background .2s, color .2s;
}
.fab:active { transform: scale(.9); }

.status {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--safe-b) + 92px);
  background: var(--elev-soft);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--t-5);
  border-radius: 999px;
  padding: 7px 16px;
  font-size: 12px; color: var(--t-3); font-style: italic;
  z-index: 30;
}
.status.err { color: var(--t-2); }

/* ============================================================
   Bottom sheet
   ============================================================ */
.sheet-wrap { position: fixed; inset: 0; z-index: 40; display: flex; align-items: flex-end; }
.sheet-scrim { position: absolute; inset: 0; background: var(--scrim); backdrop-filter: blur(4px); }

.sheet {
  position: relative;
  width: 100%; max-width: 520px; margin: 0 auto;
  background: var(--elev);
  border-top: 1px solid var(--t-5);
  border-radius: 26px 26px 0 0;
  padding: 12px var(--pad) calc(var(--safe-b) + 24px);
  display: grid; gap: 20px;
  animation: rise .26s cubic-bezier(.22,.8,.28,1);
  max-height: 92vh; overflow-y: auto;
}
@keyframes rise { from { transform: translateY(100%); } }
@media (prefers-reduced-motion: reduce) { .sheet { animation: none; } }

.sheet-grab { width: 32px; height: 3px; border-radius: 2px; background: var(--t-5); margin: 0 auto 8px; }
.sheet h2 {
  font-size: 24px; color: var(--t-1);
  font-variation-settings: 'opsz' 60, 'wght' 380, var(--wonk-on);
}

.field { display: grid; gap: 10px; }
.field > span {
  font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--t-4);
  font-variation-settings: 'opsz' 9, 'wght' 500, var(--wonk-off);
}
.field input {
  background: transparent;
  border: 0; border-bottom: 1px solid var(--t-5);
  border-radius: 0;
  padding: 8px 2px;
  font-size: 18px; color: var(--t-1);
  font-variation-settings: 'opsz' 24, 'wght' 400, var(--wonk-on);
  outline: none; width: 100%;
  transition: border-color .2s;
}
.field input::placeholder { color: var(--t-5); font-style: italic; }
.field input:focus { border-bottom-color: var(--t-3); }

.seg { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.seg-btn {
  border: 1px solid var(--t-5);
  background: transparent; color: var(--t-4);
  border-radius: 999px; padding: 12px 8px;
  font-size: 14px; cursor: pointer;
  transition: color .2s, border-color .2s, background .2s;
}
.seg-btn[aria-checked="true"] { color: var(--t-1); border-color: var(--t-3); background: var(--t-6); }

.sheet-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 6px; }

/* ---------- off days / rest ---------- */
.habit.is-off .habit-name { color: var(--t-4); }
.habit-meta .warn { color: var(--t-2); }
.habit-meta .sep { color: var(--t-5); }

.rest-row { padding: 16px 0 4px; border-top: 1px solid var(--t-5); }
.rest-toggle {
  border: 0; background: none; padding: 0; cursor: pointer;
  font-size: 12px; color: var(--t-4); font-style: italic;
  transition: color .2s;
}
.rest-toggle:hover { color: var(--t-3); }

.dot.off { background: none; box-shadow: inset 0 0 0 1px var(--t-5); }

/* a ring = a missed day the streak survived */
.day.skipped { box-shadow: inset 0 0 0 1px var(--t-4); color: var(--t-3); }
.day.off { color: var(--t-5); }
.day.off.on { color: var(--bg); }

/* ---------- day picker ---------- */
.days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; }
.day-btn {
  aspect-ratio: 1; max-height: 40px;
  border: 1px solid var(--t-5);
  background: transparent; color: var(--t-4);
  border-radius: 50%;
  font-size: 12px; cursor: pointer;
  display: grid; place-items: center;
  transition: color .18s, border-color .18s, background .18s, transform .1s;
}
.day-btn:active { transform: scale(.88); }
.day-btn[aria-checked="true"] {
  background: var(--ink); border-color: var(--ink); color: var(--bg);
}
.field-note { font-size: 11px; color: var(--t-4); font-style: italic; margin-top: 2px; }

/* ---------- position ---------- */
.position { display: flex; align-items: center; gap: 14px; }
.position span {
  font-size: 14px; color: var(--t-3); font-variant-numeric: tabular-nums;
  min-width: 62px;
}
.pos-btn {
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--t-5); background: transparent; color: var(--t-3);
  display: grid; place-items: center; cursor: pointer;
  transition: color .18s, border-color .18s, transform .1s;
}
.pos-btn:active { transform: scale(.88); }
.pos-btn:disabled { color: var(--t-5); border-color: var(--t-6); cursor: default; }

/* ---------- the day is finished ---------- */
/* A full ring is easy to misread as "nearly there". A solid disc is not. */
.ring.is-full .ring-bg { fill: var(--ink); stroke: var(--ink); }
.ring.is-full .ring-fg { stroke: var(--ink); }

/* ---------- complete-days overview ---------- */
/* These cells are read-only, unlike the tappable ones in a habit's calendar. */
div.day { cursor: default; }
div.day:active { transform: none; }

.day.full      { background: var(--ink); color: var(--bg); }
.day.part-day  { box-shadow: inset 0 0 0 1px var(--t-4); color: var(--t-3); }
.day.empty-day { color: var(--t-5); }

.ov-summary {
  font-size: 13px; color: var(--t-3);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}
.ov-legend { font-size: 11px; color: var(--t-4); font-style: italic; margin-top: -12px; }

/* The hour something was finished. Same tone as an active streak - it is
   quiet because of its size and position, not because it is faded out. */
.habit-meta .at { color: var(--t-3); letter-spacing: .01em; }
