/* Mobile-first, no build step, no CDN. Namche brand (ui.namche.ai) applied to
   the existing server-rendered structure: same selectors as before — only
   the tokens, type and component treatment changed. Fonts are vendored in
   ./fonts/ (see fonts/README.md); nothing here reaches an external origin. */

@font-face {
  font-family: "Geist Sans";
  src: url("/static/fonts/Geist-Variable-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Namche Shadow Sans";
  src: url("/static/fonts/NamcheShadowSans-Medium-latin.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Namche Shadow Sans";
  src: url("/static/fonts/NamcheShadowSans-Bold-latin.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Namche Shadow Mono";
  src: url("/static/fonts/NamcheShadowMono-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Namche Shadow Sans is headlines only, never Regular (Medium 500 default,
     Bold 700 for emphasis); Geist Sans carries every piece of running text;
     Namche Shadow Mono is labels/meta. Fallback cascade matches the token
     package so metrics stay layout-safe if a face fails to load. */
  --font-display: "Namche Shadow Sans", "Geist Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-sans: "Geist Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "Namche Shadow Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --weight-display: 500;
  --weight-display-bold: 700;
  --tracking-display: -0.01em;

  /* Shape — flat forms, one hairline weight, no shadow system. The brand's
     own value (0.5px) rounds to invisible on a standard-density display —
     most laptops, and the primary client is "her phone or laptop"
     (intent.md) — so 1px is the default and 0.5px is opt-in below, gated on
     device pixel density rather than viewport width. Every border still
     reads this one token, so both densities stay single-sourced. */
  --radius: 10px; /* controls: inputs, selects, notices */
  --radius-card: 12px; /* cards, panels */
  --radius-pill: 999px; /* buttons, badges */
  --hairline: 1px;

  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --dur-fast: 120ms;

  /* GAIA — the brand's neutral spine. Ink, page, and the warm hairline. */
  --ink: #262626; /* gaia-erebos */
  --ink-muted: rgba(38, 38, 38, 0.65); /* erebos at 65% — AA on the page only */
  --paper: #f1efe8; /* gaia-selene */
  --rule: #bab4ab; /* gaia-rhea — the warm-stone UI hairline */
  --link: var(--ink); /* editorial voice: ink at body weight, not a blue link */
  --link-hover: var(--ink-muted);
  --panel: #ffffff; /* white sheet on the warm page — surface-deck */
  --focus-ring: #122b63; /* Lapislazuli 800 */

  /* Feedback — five coverage states need five hues; the brand's semantic set
     covers four (success/warning/error/info) and the fifth (partial, a
     receipt with an unreceipted residual) is drawn from the Himalaya
     contrast spectrum, whose light field + dark ink is built for exactly
     this: a whole-coloured badge that stays legible on its own. */
  --alarm: #b0184a; /* color-error-base */
  --alarm-bg: #f6eaee; /* color-error-bg */
  --warn: #c77a12; /* color-warning-base */
  --warn-bg: #f6f1e9; /* color-warning-bg */
  --part: #371a65; /* contrast-himalaya-poppy-ink */
  --part-bg: #bfa6e8; /* contrast-himalaya-poppy */
  --ok: #12946e; /* color-success-base */
  --ok-bg: #eaf6f2; /* color-success-bg */
  --calm: #66666e; /* gaia-nyx */
  --calm-bg: #f0f2f5; /* gaia-olymp */
}

/* A sub-pixel hairline only draws a real line where the device has the
   pixels to draw it with — a HiDPI phone or an external retina display.
   `-webkit-` covers Safari, which did not recognise unprefixed
   `min-resolution` until relatively recently. */
@media (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 2) {
  :root {
    --hairline: 0.5px;
  }
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Night: the neutral spine flips (Erebos ground, Selene ink) and
       surfaces lift toward Selene in named steps instead of casting a
       shadow — the system has no elevation. Tones (the feedback hues, the
       Himalaya pair) are paint, not roles, and stay themselves at night. */
    --ink: #f1efe8; /* gaia-selene */
    --ink-muted: #c8c6c1; /* night-ink-muted */
    --paper: #262626; /* gaia-erebos */
    --rule: #474746; /* night-line */
    --link: var(--ink);
    --link-hover: var(--ink-muted);
    --panel: #303030; /* night-raised */
    --focus-ring: #789ae2; /* Lapislazuli 300 */

    --alarm: #d6858f; /* color-error-night */
    --alarm-bg: #3f292c; /* color-error-bg-night */
    --warn: #d59b5f; /* color-warning-night */
    --warn-bg: #403529; /* color-warning-bg-night */
    --part: #371a65; /* himalaya-poppy is identical day and night — brand tones don't flip */
    --part-bg: #bfa6e8;
    --ok: #66ae8f; /* color-success-night */
    --ok-bg: #2a3832; /* color-success-bg-night */
    --calm: #c8c6c1; /* night-ink-muted */
    --calm-bg: #424241; /* night-quiet */
  }
}

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  padding: 1.5rem 1.25rem 3rem;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
}

main {
  max-width: 38rem;
  margin: 0 auto;
}

h1 {
  margin: 0 0 1.5rem;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  letter-spacing: var(--tracking-display);
  font-size: 1.6rem;
  line-height: 1.25;
}

h2 {
  margin: 2rem 0 0.5rem;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  letter-spacing: var(--tracking-display);
  font-size: 1.15rem;
  line-height: 1.3;
}

p,
ul {
  margin: 0 0 1rem;
}

ul {
  padding-left: 1.25rem;
}

li {
  margin-bottom: 0.5rem;
}

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

/* Editorial link voice (tokens base.css): ink at the text's own weight, a
   quiet underline at 40% strength that comes to full strength on hover.
   Navigation chrome (.months, .button) resets this itself, below. */
a {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
  text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
  transition: color var(--dur-fast) var(--ease-standard), text-decoration-color var(--dur-fast) var(--ease-standard);
}

a:hover,
a:active {
  color: var(--link-hover);
  text-decoration-color: currentColor;
}

::selection {
  background: var(--part-bg);
  color: var(--part);
}

.lede {
  color: var(--ink-muted);
}

.meta {
  margin: 0 0 0.25rem;
  color: var(--ink-muted);
  font-size: 0.875rem;
}

footer {
  margin-top: 2.5rem;
  padding-top: 1rem;
  border-top: var(--hairline) solid var(--rule);
}

footer a {
  text-decoration: none;
}

@media (min-width: 40rem) {
  body {
    padding: 3rem 2rem;
  }

  h1 {
    font-size: 2rem;
  }
}

/* Sign-in. The only interactive page in the app so far: one link out to Google
   and one form back. */

.notice {
  margin: 0 0 1.5rem;
  padding: 0.75rem 1rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--ink-muted);
}

/* Button — an ink pill with an uppercase mono label, the Namche default
   action (Erebos on Selene by day, Selene on Erebos at night — never the
   brand's red role colour, which stays reserved for data and accents). Every
   button reads as this vocabulary; `.primary` is the one that is filled. */
a.button,
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  min-height: 2.75rem;
  padding: 0.6rem 1.1rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard);
}

a.button:hover,
button:hover {
  background: var(--calm-bg);
  color: var(--ink);
  text-decoration: none;
}

a.button:focus-visible,
button:focus-visible {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--focus-ring) 40%, transparent);
}

/* ------------------------------------------------------------------ *
 * The month view (PLAN.md §7). Everything below extends the tokens
 * above rather than starting a second system: same variables, same
 * mobile-first order, no build step and no CDN.
 * ------------------------------------------------------------------ */

/* Month navigation -------------------------------------------------- */

.months {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 1rem;
  color: var(--ink-muted);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.months a {
  padding: 0.4rem 0.1rem;
  color: var(--ink-muted);
  text-decoration: none;
}

.months a:hover {
  color: var(--ink);
}

/* The summary: bar, headline, counts ------------------------------- */

.summary {
  margin-bottom: 1.5rem;
}

.bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.bar-track {
  flex: 1;
  height: 0.75rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--calm-bg);
  appearance: none;
}

.bar-track::-webkit-progress-bar {
  border-radius: var(--radius-pill);
  background: var(--calm-bg);
}

.bar-track::-webkit-progress-value {
  border-radius: var(--radius-pill);
  background: var(--ok);
}

.bar-track::-moz-progress-bar {
  border-radius: var(--radius-pill);
  background: var(--ok);
}

.bar-count {
  font-variant-numeric: tabular-nums;
  font-size: 0.95rem;
  color: var(--ink-muted);
}

/* The number the product is about. Deliberately the largest thing on the
   screen, and set in the display face at the brand's emphasis weight. */
.headline {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  margin: 1.25rem 0 1rem;
}

.headline-number {
  font-family: var(--font-display);
  font-size: 4rem;
  font-weight: var(--weight-display-bold);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.headline-label {
  font-size: 1rem;
  line-height: 1.3;
}

.headline-open .headline-number {
  color: var(--alarm);
}

.headline-clear .headline-number {
  color: var(--ok);
}

.counts {
  margin: 0 0 1rem;
  border-top: var(--hairline) solid var(--rule);
}

.count {
  display: grid;
  grid-template-columns: 8.5rem 3rem 1fr;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0;
  border-bottom: var(--hairline) solid var(--rule);
}

.count dt,
.count dd {
  margin: 0;
}

.count-value {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: right;
}

.count-blurb {
  color: var(--ink-muted);
  font-size: 0.85rem;
}

/* State badges ------------------------------------------------------ */

.pill {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border-radius: var(--radius-pill);
  font-family: var(--font-sans);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.pill-missing {
  background: var(--alarm-bg);
  color: var(--alarm);
}

.pill-ambiguous {
  background: var(--warn-bg);
  color: var(--warn);
}

.pill-partial {
  background: var(--part-bg);
  color: var(--part);
}

.pill-matched {
  background: var(--ok-bg);
  color: var(--ok);
}

.pill-exempt {
  background: var(--calm-bg);
  color: var(--calm);
}

/* The list ---------------------------------------------------------- */

.rows {
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
}

.row {
  margin: 0;
  padding: 0.75rem 0.75rem 0.75rem 0.6rem;
  border-bottom: var(--hairline) solid var(--rule);
  /* The left edge repeats the state, so scanning the list needs no reading. */
  border-left: 3px solid transparent;
}

.row-missing {
  border-left-color: var(--alarm);
}

.row-ambiguous {
  border-left-color: var(--warn);
}

.row-partial {
  border-left-color: var(--part);
}

.row-matched {
  border-left-color: var(--ok);
}

.row-exempt {
  border-left-color: var(--calm);
}

.row-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.row-day {
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
}

.row-party {
  flex: 1 1 8rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.row-amount {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.row-flag,
.row-note,
.row-residual {
  margin: 0.4rem 0 0;
  color: var(--ink-muted);
  font-size: 0.85rem;
}

.row-flag {
  color: var(--warn);
}

/* Money with no document behind it, named on the row it belongs to. */
.row-residual {
  color: var(--part);
}

/* Resolving --------------------------------------------------------- */

.resolve {
  margin-top: 0.6rem;
}

.resolve > summary {
  padding: 0.35rem 0;
  color: var(--link);
  font-size: 0.9rem;
  cursor: pointer;
  min-height: 2rem;
}

.hint {
  margin: 0.25rem 0 0.75rem;
  color: var(--ink-muted);
  font-size: 0.85rem;
}

.candidate {
  margin-bottom: 0.75rem;
  padding: 0.75rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-card);
  background: var(--panel);
}

.candidate-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 0.25rem;
}

.candidate-amount {
  font-variant-numeric: tabular-nums;
}

.candidate-date,
.candidate-meta {
  color: var(--ink-muted);
  font-size: 0.85rem;
}

/* The `explain` object, read out loud. It is why the tap is safe to make. */
.candidate-why {
  margin: 0 0 0.25rem;
  font-size: 0.9rem;
}

.candidate-meta {
  margin: 0 0 0.6rem;
}

.stale {
  color: var(--warn);
}

.actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

button.primary {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--paper);
  font-weight: 500;
}

button.primary:hover {
  background: color-mix(in oklab, var(--ink) 85%, transparent);
  color: var(--paper);
}

button[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

form.exempt label {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.85rem;
  color: var(--ink-muted);
}

form.exempt select,
form.exempt input[type="text"],
.flagged input[type="text"] {
  display: block;
  width: 100%;
  margin-bottom: 0.75rem;
  padding: 0.6rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  font-family: var(--font-sans);
  min-height: 2.75rem;
}

form.exempt select:focus-visible,
form.exempt input[type="text"]:focus-visible,
.flagged input[type="text"]:focus-visible {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--focus-ring) 40%, transparent);
}

/* Settled rows, collapsed ------------------------------------------- */

.settled > summary {
  padding: 0.75rem 0;
  color: var(--link);
  cursor: pointer;
  min-height: 2.75rem;
}

.allclear {
  padding: 1rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-card);
  background: var(--ok-bg);
  color: var(--ok);
}

/* Closing ----------------------------------------------------------- */

.close {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: var(--hairline) solid var(--rule);
}

.close-reason {
  margin-top: 0.6rem;
  color: var(--ink-muted);
  font-size: 0.9rem;
}

.closed {
  padding: 1rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-card);
  background: var(--panel);
}

.closed-title {
  margin-top: 0;
  font-size: 1.05rem;
}

.snapshot {
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.snapshot li {
  display: flex;
  justify-content: space-between;
  max-width: 14rem;
  margin-bottom: 0.25rem;
}

.snapshot-count,
.live-count {
  font-variant-numeric: tabular-nums;
}

/* A flagged month has to *look* untrustworthy ----------------------- */

.flagged {
  margin-bottom: 1.5rem;
  padding: 1rem;
  border: 2px solid var(--alarm);
  border-radius: var(--radius-card);
  background: var(--alarm-bg);
  color: var(--ink);
}

.flagged-title {
  margin-top: 0;
  font-size: 1.1rem;
  color: var(--alarm);
}

.flagged-reason {
  font-weight: 600;
}

.divergence {
  width: 100%;
  margin: 1rem 0;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.divergence caption {
  margin-bottom: 0.4rem;
  color: var(--ink-muted);
  font-size: 0.85rem;
  text-align: left;
}

.divergence th,
.divergence td {
  padding: 0.35rem 0.5rem;
  border-bottom: var(--hairline) solid var(--rule);
  text-align: left;
  font-weight: 500;
}

.divergence td {
  text-align: right;
  font-weight: 400;
}

/* The divergence *is* the warning: the rows that moved are the ones that
   say the close no longer describes this month. */
.divergence .diverged {
  font-weight: 700;
}

.divergence .diverged .live-count {
  color: var(--alarm);
}

.notice-warn {
  border-color: var(--alarm);
  color: var(--alarm);
}

.notice-ok {
  border-color: var(--ok);
  background: var(--ok-bg);
  color: var(--ok);
}

.environment-banner {
  margin: 0 0 1rem;
  padding: 0.4rem 0.7rem;
  border: var(--hairline) solid var(--warn);
  border-radius: var(--radius);
  color: var(--warn);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Capture: the upload form ------------------------------------------ *
 * Directly under the headline number, because on a phone the receipt is
 * in the reader's hand and everything below is about receipts already in.
 */

.capture {
  margin-bottom: 1.5rem;
  padding: 1rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-card);
  background: var(--panel);
}

.capture h2 {
  margin-top: 0;
}

.upload-label {
  display: block;
  margin-bottom: 0.4rem;
  font-size: 0.9rem;
  color: var(--ink-muted);
}

/* A file input is the one control that has to be comfortable to hit with a
   thumb: it is the first thing a signed-in reader does. */
.upload input[type="file"] {
  display: block;
  width: 100%;
  margin-bottom: 0.5rem;
  padding: 0.6rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  font-family: var(--font-sans);
  min-height: 2.75rem;
}

.upload input[type="file"]:focus-visible {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--focus-ring) 40%, transparent);
}

/* Where an upload went ---------------------------------------------- */

.receipts {
  margin-top: 2rem;
}

.receipt-list {
  margin: 0 0 0.5rem;
  padding: 0;
  list-style: none;
}

.receipt {
  margin: 0;
  padding: 0.75rem 0.75rem 0.75rem 0.6rem;
  border-bottom: var(--hairline) solid var(--rule);
  border-left: 3px solid transparent;
}

/* The one this page load is reporting on. */
.receipt-fresh {
  border-left-color: var(--ok);
  background: var(--ok-bg);
}

.receipt-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
}

.receipt-what {
  flex: 1 1 8rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.receipt-amount {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.receipt-date,
.receipt-meta {
  color: var(--ink-muted);
  font-size: 0.85rem;
}

.receipt-meta {
  margin: 0.2rem 0 0;
}

/* The intake address, and whether it works ---------------------------- */

.intake {
  margin-top: 2rem;
  padding: 1rem;
  border: var(--hairline) solid var(--rule);
  border-radius: var(--radius-card);
  background: var(--panel);
}

.intake h2 {
  margin-top: 0;
}

.intake-address {
  margin: 0 0 0.5rem;
  overflow-wrap: anywhere;
}

/* Not styled as an error — nothing is broken — but it must not read as an
   aside either: acting on it loses a receipt. */
.intake-inactive {
  border-color: var(--warn);
}

.intake-warning {
  margin: 0;
  color: var(--warn);
  font-size: 0.9rem;
}

.whoami {
  margin-top: 2.5rem;
}

@media (min-width: 40rem) {
  .headline-number {
    font-size: 5rem;
  }
}
