/* Dotdown. Near-black on off-white, one monospace family (Commit Mono),
   barely rounded corners, and a single red accent that marks today. */

/* Commit Mono is served from this folder, so there is no third-party request.
   The one variable file holds every weight from 200 to 700.
   Licence: fonts/OFL.txt (SIL Open Font License). */
@font-face {
  font-family: "Commit Mono";
  src: url("fonts/CommitMono-Variable.woff2") format("woff2");
  font-weight: 200 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #f5f5f2; /* also in the inline <style> of index.html and privacy.html */
  --ink: #1b1b1a;
  --muted: #62625e;
  --faint: #d5d5d0; /* elapsed days */
  --accent: #cf2e1c; /* today, and things that need attention */
  --warn: #e0aa00; /* the "getting close" tag: deeper here, to stand out on the light page */
  --radius: 2px;

  /* Keeps the layout still when the page scrollbar appears or disappears.
     --scrollbar-width is the viewport with the scrollbar (100vw) minus the
     viewport without it (100%): 0 when there is no scrollbar, or when it
     floats over the page as on phones. The 100% is worked out where the
     variable is used, so it is only right in body's padding and in
     position: fixed elements, where 100% means the viewport width.
     --gutter-right is the right-hand gutter with the scrollbar taken out of
     it: the scrollbar uses up gutter instead of pushing the content. */
  --gutter: 1.25rem; /* space between the content and the edge of the screen */
  --scrollbar-width: calc(100vw - 100%);
  --gutter-right: max(
    0px,
    calc(max(var(--gutter), env(safe-area-inset-right)) - var(--scrollbar-width))
  );

  /* Every digit in a monospace font has the same width, so the ticking
     numbers cannot jitter. The system fonts are only the fallback while
     Commit Mono loads, or if it fails to. */
  --mono: "Commit Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas,
    "Roboto Mono", "Liberation Mono", monospace;

  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141413; /* also in the inline <style> of index.html and privacy.html */
    --ink: #ecece8;
    --muted: #a2a29d;
    --faint: #3a3a37;
    --accent: #ff6a55;
    --warn: #f1c232;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Several elements below set `display`, which would otherwise beat [hidden]. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Scrollbar: grey thumb (quieter than the text), no visible track. */
  scrollbar-color: var(--muted) transparent;
  /* No pinch or double-tap zoom on touch screens; scrolling still works.
     (iOS ignores user-scalable=no in the viewport tag, but honours this.) */
  touch-action: pan-x pan-y;
  /* No coloured flash box when something is tapped (Android draws a blue
     one). Taps get the :active style further down instead; the keyboard
     focus outline is separate and stays. */
  -webkit-tap-highlight-color: transparent;
}

/* The same for browsers without scrollbar-color (older Safari). The
   @supports guard matters: where scrollbar-color works, these rules would
   only force the scrollbar to be permanently visible. */
@supports not (scrollbar-color: auto) {
  ::-webkit-scrollbar {
    width: 10px;
    height: 10px;
  }

  ::-webkit-scrollbar-track {
    background: transparent;
  }

  ::-webkit-scrollbar-thumb {
    border-radius: var(--radius);
    background: var(--muted);
  }
}

body {
  margin: 0;
  /* Same padding on the top, left and right. Safe-area insets are for
     notched phones (needs viewport-fit=cover). No padding at the bottom
     beyond the safe area: the corner links end the page, and their tap
     area is their spacing. */
  padding:
    /* A little extra on top keeps the first line clear of the phone's
       translucent status bar. */
    calc(max(var(--gutter), env(safe-area-inset-top)) + 0.5rem)
    var(--gutter-right) /* shrinks by the scrollbar's width, see :root */
    env(safe-area-inset-bottom)
    max(var(--gutter), env(safe-area-inset-left));
  background: var(--bg);
  color: var(--ink);
  font: 0.9375rem/1.6 var(--mono);
  /* Commit Mono's optional letter shapes: cv02 single-circle g, cv05 simpler
     @, cv06 straight-stemmed 6 and 9. Must come after `font`, which resets it. */
  font-feature-settings: "cv02", "cv05", "cv06";
  /* Wherever text runs over a line, break it so the last line is not a
     lone word. Inherited, so this covers the name, the dates, goals, the
     hint and the notice. Browsers without support just wrap as usual. */
  text-wrap: pretty;
  /* At least one screen tall, so on a short page the corner links (pushed
     down by margin-top: auto) sit at the bottom edge. svh: the screen with
     the browser's toolbars shown, so they are never hidden behind them. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

main {
  width: 100%; /* a flex item would otherwise shrink to its content */
  max-width: 38rem;
  margin: 0 auto;
}

h1,
h2,
p,
ul,
dl,
dd,
fieldset {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* Small uppercase labels used for field names, units and section titles. */
.label,
.unit {
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* ---------- Intro and notice (create state) ---------- */

.intro h1 {
  padding-bottom: 0.75rem;
  border-bottom: 2px solid var(--ink);
  display: flex;
  align-items: center;
  gap: 0.625rem;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
}

/* The app icon, about as tall as the capital letters beside it. */
.intro h1 img {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 3px;
}

.intro p {
  margin-top: 1rem;
  color: var(--muted);
}

.notice {
  margin-top: 1.5rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--faint);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

/* ---------- Countdown ---------- */

/* Brand on the left, "New countdown" on the right, both small. */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: -0.75rem 0 1rem; /* the button's 44px tap area may overlap the padding above */
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted);
  font-size: 0.75rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.brand img {
  border-radius: 3px;
}

/* Right-aligned, so its text ends at the column edge. */
#new-top {
  text-align: right;
}

.name {
  padding-bottom: 0.75rem;
  border-bottom: 2px solid var(--ink);
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.ticker {
  margin-top: 2rem;
}

.num {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.days .num {
  display: block;
  margin-left: -0.04em; /* optical: lines the first digit up with the text */
  font-size: clamp(4.75rem, 27vw, 10rem);
  /* Only a touch tighter: at this size even a monospace font looks loose,
     but more than this and the digits start to crowd. */
  letter-spacing: -0.03em;
  line-height: 0.9;
}

/* Six or more digits (centuries away): shrink so the number still fits. */
.days .num.long {
  font-size: clamp(2.5rem, 12vw, 5.5rem);
}

/* The "days" label, and next to it the tag shown in the final stretch. */
.days-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.75rem;
  margin-top: 0.75rem;
}

/* Two warning stages (see stage() in app.js). "Getting close": a yellow tag,
   nothing else changes. "Final stretch": the tag turns red and so does the
   day number. The tag says it in words, so neither relies on colour alone. */
.ticker.urgent .days .num {
  color: var(--accent);
}

.soon {
  padding: 0.125rem 0.5rem;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--bg);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* Yellow needs dark text in both light and dark mode. Only the tag is
   yellow: as a text colour on the light background it would be unreadable. */
.soon.close {
  background: var(--warn);
  color: #1b1b1a;
}

.clock {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin-top: 1.25rem;
}

.clock > span {
  white-space: nowrap;
}

.clock .num {
  font-size: 1.5rem;
}

.passed {
  margin-top: 2rem;
  font-size: clamp(1.75rem, 8vw, 3rem);
  font-weight: 700;
  line-height: 1.1;
}

/* The span in words: "from <start>" above "until <target>". The labels share
   one column, so the two dates line up. */
.dates {
  margin-top: 1rem;
  color: var(--muted);
  font-size: 0.8125rem;
}

.dates div {
  display: flex;
  gap: 1ch;
}

.dates dt {
  flex: none;
  width: 5ch; /* "until" and "ended" are the longest labels */
}

/* ---------- Day grid (one square per day) ---------- */

.span {
  margin-top: 2.5rem;
}

.dots {
  --dot: 0.5rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, var(--dot));
  gap: calc(var(--dot) * 0.625);
  user-select: none;
  -webkit-user-select: none;
}

/* Short spans get bigger squares so the grid does not look lost. */
.dots.few {
  --dot: 0.875rem;
}

.dots i {
  width: var(--dot);
  height: var(--dot);
  border-radius: 1px;
  background: var(--ink); /* a day still to come */
}

.dots.few i {
  border-radius: var(--radius);
}

.dots .gone {
  background: var(--faint);
}

/* Today: the one coloured square, with a thin frame and a quiet pulse. */
.dots .today {
  background: var(--accent);
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: no-preference) {
  .dots .today {
    animation: pulse 1.8s ease-in-out infinite;
  }
}

/* Solid for the first half of each cycle, then one short, shallow dip.
   To tune: the duration above sets the pace, the opacity here the depth. */
@keyframes pulse {
  0%,
  50%,
  100% {
    opacity: 1;
  }
  75% {
    opacity: 0.6;
  }
}

.caption {
  margin-top: 1rem;
  color: var(--muted);
  font-size: 0.8125rem;
}

.caption strong {
  color: var(--ink);
  font-weight: 700;
}

/* "· half": shown around a quarter, a third, half and two thirds. */
#milestone {
  color: var(--ink);
}

/* ---------- Goals ---------- */

.goals {
  margin-top: 2.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--ink);
  counter-reset: goal;
}

.goals ul {
  margin-top: 0.5rem;
}

.goals li {
  position: relative;
  padding: 0.25rem 0 0.25rem 2.25rem;
  overflow-wrap: anywhere;
  counter-increment: goal;
}

/* Numbered 01, 02, ... */
.goals li::before {
  content: counter(goal, decimal-leading-zero);
  position: absolute;
  left: 0;
  color: var(--muted);
}

/* ---------- Buttons and links ---------- */

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}

/* Feedback while a button or link is pressed (touch or mouse). */
button:active:not(:disabled),
a:active {
  opacity: 0.6;
}

button:disabled {
  cursor: default;
  opacity: 0.5;
}

/* Text-style button. min-height/min-width keep the tap target at 44px. */
.link {
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  background: none;
  font-size: 0.75rem;
  letter-spacing: 0.09em;
  text-align: left; /* short labels ("Edit") stay flush with the column */
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-transform: uppercase;
  text-underline-offset: 0.3em;
}

/* Hover styles are limited to devices with a real pointer. On a touch
   screen a hover style would stick to whatever was tapped last. */
@media (hover: hover) {
  .link:hover {
    text-decoration-thickness: 2px;
  }
}

.primary {
  min-height: 2.75rem;
  padding: 0 1.25rem;
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--bg);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  transition: opacity 0.15s ease;
}

/* Hover fades the button a little; pressing it fades it further (see
   button:active above), the same feedback a tap gives on a phone. */
@media (hover: hover) {
  .primary:hover {
    opacity: 0.8;
  }

  /* Earlier hover style, kept in case it is wanted back: colours inverted.
  .primary:hover {
    background: var(--bg);
    color: var(--ink);
  }
  */
}

.actions {
  display: flex;
  gap: 1.5rem;
  margin-top: 2rem;
}

/* "More" sits at the right end of the row; its menu opens upward. */
.more {
  position: relative;
  margin-left: auto;
}

.more .link {
  text-align: right;
}

.menu {
  position: absolute;
  right: -4px;
  bottom: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--faint);
  border-radius: var(--radius);
  background: var(--bg);
  font-size: 0.75rem;
  white-space: nowrap;
}

.menu a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  color: var(--muted);
  text-underline-offset: 0.3em;
}

@media (hover: hover) {
  .menu a:hover {
    color: var(--ink);
  }
}

/* ---------- Form ---------- */

.editor {
  margin-top: 2rem;
}

/* While editing, the form sits under the countdown: separate it with a rule. */
#view:not([hidden]) ~ .editor {
  margin-top: 0.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--ink);
}

.field {
  margin-bottom: 1.5rem;
  border: 0;
}

.field label,
.field legend {
  display: block;
  margin-bottom: 0.375rem;
  padding: 0;
}

input {
  display: block;
  width: 100%;
  min-height: 2.75rem;
  /* Top and bottom padding that exactly fill the 44px with one line of text
     (line-height 1.6em, 1px borders). Safari centres the text of a text
     field but puts a date field's at the top, so leaving nothing to centre
     makes both sit at the same height. */
  padding: calc((2.75rem - 2px - 1.6em) / 2) 0.75rem;
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  /* Inherit the font, but never go below 16px or iOS zooms in on focus. */
  font: inherit;
  font-size: max(1rem, 16px);
  -webkit-appearance: none;
  appearance: none;
}

input::placeholder {
  color: var(--muted);
  opacity: 0.7;
}

input:focus-visible {
  outline-offset: 0;
}

/* iOS centres the value of a date input by default. */
input::-webkit-date-and-time-value {
  text-align: left;
}

/* The parts of a date field come with a little padding of their own in
   Safari and Chrome, which pushes the date right of the other fields' text. */
input::-webkit-datetime-edit,
input::-webkit-datetime-edit-fields-wrapper,
input::-webkit-datetime-edit-day-field,
input::-webkit-datetime-edit-month-field,
input::-webkit-datetime-edit-year-field {
  margin: 0;
  padding: 0;
}

#f-goals li {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-bottom: 0.5rem;
}

#f-goals input {
  flex: 1;
  min-width: 0;
}

/* Grip for dragging a goal to a new place. Its 44px tap area reaches into
   the page gutter (the negative margin), so the three lines sit flush with
   the left edge of the column and the text field keeps its width.
   touch-action: none lets a finger drag it without scrolling the page. */
.grip {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-left: -0.9375rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

/* The three lines: one drawn, two more as its shadows. */
.grip::before {
  content: "";
  width: 0.875rem;
  height: 2px;
  background: currentColor;
  box-shadow: 0 -5px currentColor, 0 5px currentColor;
}

/* The row being dragged. */
.dragging .grip {
  color: var(--accent);
  cursor: grabbing;
}

#f-goals .dragging input {
  border-color: var(--accent);
}

.remove {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font-size: 1.375rem;
  line-height: 1;
}

@media (hover: hover) {
  .remove:hover {
    color: var(--accent);
  }
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.5rem;
  margin-bottom: 24px;
}

/* ---------- Hint (after an edit) ---------- */
/* Floats over the page and reserves no room, so showing or dismissing it
   never changes the page's layout or height. On a short screen it can sit
   over the last lines of the page until it is dismissed. */

.hint {
  position: fixed;
  /* vw, not %: centred on the whole viewport like the page content, so it
     does not move when a scrollbar appears. */
  left: 50vw;
  bottom: calc(3.5rem + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: min(100vw - 2 * var(--gutter), 36rem);
  padding: 0.25rem 0.25rem 0.25rem 1rem;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--bg);
  font-size: 0.8125rem;
  line-height: 1.4;
}

.hint span {
  flex: 1;
  padding: 0.5rem 0;
}

.hint .link {
  flex: none;
}

/* Phones: the text gets the full width, the buttons sit on a row below. */
@media (max-width: 30rem) {
  .hint {
    flex-wrap: wrap;
    row-gap: 0;
  }

  .hint span {
    flex-basis: 100%;
    padding: 0.625rem 0.75rem 0 0;
  }

  #hint-close {
    margin-left: auto;
  }
}

#hint-close {
  font-size: 1.375rem;
  text-align: center;
  text-decoration: none;
}

/* ---------- Corner slot and ad slot ---------- */

/* The last thing on the page, at the right. On a short page it sits at the
   bottom of the screen; on a long one it comes after the content, so it never
   covers anything. */
#corner {
  display: flex;
  align-self: flex-end;
  margin-top: auto;
  padding-top: 2rem; /* the least space between the content and the links */
  font-size: 0.75rem;
}

#corner a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 0.625rem;
  color: var(--muted);
  text-underline-offset: 0.3em;
}

/* No padding after the last link, so its text ends exactly at the gutter. */
#corner a:last-child {
  padding-right: 0;
}

@media (hover: hover) {
  #corner a:hover {
    color: var(--ink);
  }
}

/* ---------- Privacy page ---------- */

.page section {
  margin-top: 2rem;
}

.page section p {
  margin-top: 0.5rem;
}

.page a {
  color: inherit;
  text-underline-offset: 0.3em;
}

.page code {
  font: inherit;
}

.page .updated {
  margin: 2.5rem 0 var(--gutter); /* no corner links here to end the page */
  color: var(--muted);
  font-size: 0.8125rem;
}

.ad {
  width: 100%;
  max-width: 38rem;
  margin: 3rem auto 0;
}
