/* Shared vocabulary for every Sable surface.
 * The design repeats a small set of shapes — an ink button, a field, a mono
 * caps label, a card, a pill — so they live here once and each surface only
 * adds what is genuinely its own. */

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

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--s-bg);
  color: var(--s-text);
  font-family: var(--s-sans);
  font-size: 13px;
  -webkit-font-smoothing: antialiased;
  transition: background .45s ease, color .45s ease;
}

::selection { background: var(--s-tint); color: var(--s-text); }

/* ---- focus ------------------------------------------------------------
 *
 * The ring is always there and always transparent, so focus is a change of
 * two animatable properties rather than an outline appearing out of nothing:
 * the colour fades up and the offset blooms outward. Leaving reverses both,
 * which is what makes blur feel like something instead of a hard cut.
 *
 * It still arrives as a 2px accent ring. This is a softer *arrival*, not a
 * softer indicator — keyboard users get what they got before. And it is
 * `:focus-visible`, so clicking a button with a mouse never paints a ring
 * nobody asked for.
 *
 * Zero specificity via :where(), so any control with its own focus treatment
 * still wins; reduced-motion drops the transition globally in tokens.css. */
:where(a, button, input, select, textarea, summary, [tabindex]) {
  outline: 2px solid transparent;
  outline-offset: 0;
  transition: outline-color .2s ease, outline-offset .22s cubic-bezier(.2, .8, .2, 1);
}
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline-color: var(--s-accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---- type ---------------------------------------------------------- */

.serif { font-family: var(--s-serif); letter-spacing: -0.02em; }
.mono { font-family: var(--s-mono); }

.label {
  font-family: var(--s-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--s-muted);
}
.label.accent { color: var(--s-accent); }

.muted { color: var(--s-muted); }
.faint { color: var(--s-faint); }
.warn { color: var(--s-warn); }
.ok { color: var(--s-ok); }

h1, h2, h3 { margin: 0; font-weight: 400; }

/* ---- the mark ------------------------------------------------------ */

.mark {
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
  background: var(--s-ink);
  border-radius: 11px;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
}
.mark span {
  font-family: var(--s-serif);
  color: var(--s-inkText);
  font-size: 23px;
  line-height: 1;
  padding-bottom: 3px;
}
/* The folded corner reads as paper, so it takes the colour behind the mark. */
.mark::after {
  content: '';
  position: absolute;
  top: 0; right: 0;
  width: 30%; height: 30%;
  background: var(--mark-fold, var(--s-bg));
  clip-path: polygon(100% 0, 0 0, 100% 100%);
}
/* The size it is on the first screen, where it is the only thing above the
 * title and can afford to sit off the page a little. */
.mark.lg {
  width: 60px;
  height: 60px;
  border-radius: 16px;
  box-shadow: 0 18px 36px -18px rgba(0, 0, 0, .5);
}
.mark.lg span { font-size: 31px; }
.mark.sm { width: 28px; height: 28px; border-radius: 8px; }
.mark.sm span { font-size: 15px; padding-bottom: 2px; }
.mark.xs { width: 24px; height: 24px; border-radius: 7px; }
.mark.xs span { font-size: 13px; padding-bottom: 1px; }

/* ---- buttons ------------------------------------------------------- */

.btn {
  appearance: none;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  font-family: var(--s-sans);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 16px;
  border-radius: var(--s-r-md);
  border: 1px solid transparent;
  background: transparent;
  color: var(--s-text);
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  transition: background .18s ease, border-color .18s ease, color .18s ease;
}
.btn:disabled { opacity: .45; cursor: not-allowed; }

.btn.ink { background: var(--s-ink); color: var(--s-inkText); border-color: var(--s-ink); }
.btn.ink:hover:not(:disabled) { background: var(--s-inkHover); border-color: var(--s-inkHover); }

.btn.quiet { background: var(--s-field); border-color: var(--s-line); color: var(--s-body); }
.btn.quiet:hover:not(:disabled) { border-color: var(--s-text); }

.btn.outline { border-color: var(--s-text); color: var(--s-text); }
.btn.outline:hover:not(:disabled) { background: var(--s-raised); }

.btn.bare { color: var(--s-muted); padding: 10px 12px; }
.btn.bare:hover:not(:disabled) { color: var(--s-text); }

.btn.danger { border-color: var(--s-warnLine); background: var(--s-warnBg); color: var(--s-warn); }
.btn.danger:hover:not(:disabled) { border-color: var(--s-warn); }

/* Cancelling is reversible, so it gets the outline. Deleting is not, so it
 * gets the only solid red fill in Sable — the weight of the button is the
 * warning, and it is worth nothing if it is spent on anything softer. */
.btn.warn { border-color: var(--s-warn); background: transparent; color: var(--s-warn); }
.btn.warn:hover:not(:disabled) { background: var(--s-warnBg); }

.btn.fill-danger { background: var(--s-warn); border-color: var(--s-warn); color: var(--s-surface); }
.btn.fill-danger:hover:not(:disabled) { filter: brightness(1.08); }

/* The Google button carries its own mark, so it stays neutral — a coloured
 * fill behind a coloured logo reads as an advert. */
.btn.google { background: var(--s-surface); border-color: var(--s-line); color: var(--s-text); }
.btn.google:hover:not(:disabled) { border-color: var(--s-text); }

/* Google's mark keeps its own colours in both themes — it is their logo, not
 * part of Sable's palette. */
.gmark { flex: 0 0 auto; display: block; }

.btn.sm { padding: 9px 14px; font-size: 12.5px; }
.btn.xs { padding: 6px 11px; font-size: 11.5px; gap: 6px; }
.btn.wide { width: 100%; }

.btn .glyph { font-family: var(--s-mono); font-size: 11px; opacity: .55; }
.btn .kbd { font-family: var(--s-mono); font-size: 10px; opacity: .5; margin-left: auto; }

/* ---- fields -------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }

.input, .select, .textarea {
  appearance: none;
  font: inherit;
  font-family: var(--s-sans);
  font-size: 13px;
  width: 100%;
  padding: 10px 12px;
  background: var(--s-field);
  border: 1px solid var(--s-line);
  border-radius: var(--s-r-md);
  color: var(--s-text);
  transition: border-color .18s ease, outline-color .2s ease, outline-offset .22s cubic-bezier(.2, .8, .2, 1);
}
.input::placeholder, .textarea::placeholder { color: var(--s-faint); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--s-faint); }
/* One focus ring. Fields used to trade the shared outline for a 1.5px border,
 * which made the controls a keyboard user spends the most time in the ones
 * with the quietest signal. The border still warms on focus — but it is the
 * accompaniment now, not the whole indication. */
.input:focus-visible, .select:focus-visible, .textarea:focus-visible {
  border-color: var(--s-accent);
}
.input:focus, .select:focus, .textarea:focus { border-color: var(--s-accent); }

/* ---- what a money field is doing --------------------------------------
 * Rest is a placeholder shaped like an answer. Focus corrects nothing.
 * On blur the field either agrees with the total, or says it could not read
 * what is in it — and never silently does neither. */

/* Understood: a brief accent flush as the reformatted number lands, so the
 * rewrite is visibly the field's doing and not a glitch. */
.input.understood { animation: sb-settle .5s ease; }

.input.bad,
.input.bad:focus,
.input.bad:focus-visible {
  border-color: var(--s-warn);
  border-width: 1.5px;
  padding: 9.5px 11.5px;
}
.input.bad { animation: sb-shake .3s ease; }

.field-note {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  margin-top: 5px;
  font-size: 10.5px;
  line-height: 1.45;
  color: var(--s-warn);
  text-wrap: pretty;
}
.field-note i { font-family: var(--s-mono); font-style: normal; font-size: 11px; line-height: 1.35; }

/* A total that is missing a line is not a total. */
.unresolved { color: var(--s-warn); }

/* Present to a screen reader, absent from the page. For figures that a chart
 * draws but does not spell out. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.input.mono, .select.mono { font-family: var(--s-mono); font-size: 12.5px; }
.input.num { font-family: var(--s-mono); font-size: 12px; text-align: right; }

.textarea { line-height: 1.55; resize: vertical; min-height: 52px; }

.select {
  cursor: pointer;
  padding-right: 30px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 15px) calc(50% + 1px), calc(100% - 11px) calc(50% + 1px);
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
  color: var(--s-text);
}
.select option { background: var(--s-surface); color: var(--s-text); }

/* Chrome renders date inputs with its own indicator; tint it to match. */
input[type='date'] { font-family: var(--s-mono); font-size: 12.5px; }
input[type='date']::-webkit-calendar-picker-indicator { opacity: .45; cursor: pointer; }
input[type='date']::-webkit-calendar-picker-indicator:hover { opacity: 1; }
:root[data-theme='dark'] input[type='date']::-webkit-calendar-picker-indicator { filter: invert(1); }

/* ---- toggle -------------------------------------------------------- */

.toggle { display: flex; align-items: flex-start; gap: 11px; cursor: pointer; }
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle .track {
  width: 34px; height: 20px;
  border-radius: 999px;
  background: var(--s-line);
  position: relative;
  flex: 0 0 auto;
  margin-top: 1px;
  transition: background .2s ease;
}
.toggle .track::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--s-surface);
  box-shadow: 0 1px 2px rgba(27, 26, 23, .25);
  transition: left .2s cubic-bezier(.2, .8, .2, 1);
}
.toggle input:checked + .track { background: var(--s-accent); }
.toggle input:checked + .track::after { left: 16px; }
.toggle input:focus-visible + .track { outline: 2px solid var(--s-accent); outline-offset: 2px; }
.toggle .copy { display: flex; flex-direction: column; gap: 2px; }
.toggle .copy b { font-size: 13px; font-weight: 500; }
.toggle .copy small { font-size: 11.5px; color: var(--s-muted); }


/* ---- segmented ----------------------------------------------------- */

.seg {
  display: flex;
  padding: 3px;
  gap: 3px;
  background: var(--s-raised);
  border: 1px solid var(--s-line);
  border-radius: var(--s-r-lg);
}
.seg button {
  appearance: none;
  font: inherit;
  font-family: var(--s-sans);
  font-size: 12.5px;
  font-weight: 500;
  padding: 7px 15px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--s-muted);
  cursor: pointer;
  transition: background .2s ease, color .2s ease;
}
.seg button:hover { color: var(--s-text); }
.seg button[aria-selected='true'] { background: var(--s-ink); color: var(--s-inkText); }
/* Quieter selection: a raised chip rather than an ink block. */
.seg.subtle button[aria-selected='true'] {
  background: var(--s-surface);
  color: var(--s-text);
  box-shadow: 0 1px 2px rgba(27, 26, 23, .08);
}
.seg.grow button { flex: 1; }

/* ---- surfaces ------------------------------------------------------ */

.card {
  background: var(--s-surface);
  border: 1px solid var(--s-line);
  border-radius: var(--s-r-lg);
  padding: 20px;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: var(--s-body);
  background: var(--s-field);
  border: 1px solid var(--s-line);
  padding: 2px 8px 3px;
  border-radius: 999px;
  white-space: nowrap;
}
.pill .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--s-accent); }
.pill.draft .dot { background: var(--s-accent); }
.pill.sent .dot { background: var(--s-muted); }
.pill.paid .dot { background: var(--s-accent); opacity: .5; }
.pill.overdue { color: var(--s-warn); border-color: var(--s-warnLine); background: var(--s-warnBg); }
.pill.overdue .dot { background: var(--s-warn); }

.hair { height: 1px; background: var(--s-hair); }
.rule { height: 1px; background: var(--s-line); }

/* ---- accent swatches ----------------------------------------------- */

.swatches { display: flex; gap: 10px; }
.swatches button {
  width: 38px; height: 38px;
  border-radius: 10px;
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: box-shadow .2s ease;
}
.swatches button[aria-pressed='true'] {
  box-shadow: 0 0 0 2px var(--s-panel), 0 0 0 3.5px var(--s-text);
}
.swatches.sm button { width: 30px; height: 30px; border-radius: 8px; }

/* ---- skeletons ----------------------------------------------------- */

.sk {
  border-radius: 8px;
  background: linear-gradient(90deg, var(--s-raised) 25%, var(--s-surface) 50%, var(--s-raised) 75%);
  background-size: 220% 100%;
  animation: sb-shimmer 1.5s linear infinite;
}

/* ---- misc ---------------------------------------------------------- */

.row { display: flex; align-items: center; gap: 10px; }
.col { display: flex; flex-direction: column; }
.spacer { margin-left: auto; }
.grow { flex: 1; min-width: 0; }
.wrap { text-wrap: pretty; }
.ellipsis { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.link {
  color: var(--s-accent);
  cursor: pointer;
  text-decoration: none;
  border: 0;
  background: none;
  font: inherit;
  padding: 0;
}
.link:hover { color: var(--s-text); }

.avatar {
  width: 32px; height: 32px;
  border-radius: 8px;
  background: var(--s-tint);
  color: var(--s-accent);
  display: grid;
  place-items: center;
  font-size: 11.5px;
  font-weight: 600;
  flex: 0 0 auto;
}
:root[data-theme='dark'] .avatar { color: var(--s-accent); }

.empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  padding: 40px 36px;
  text-align: center;
}

/* Toast — one line, bottom of whichever surface raised it. */
.toast {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 90;
  background: var(--s-ink);
  color: var(--s-inkText);
  font-size: 12.5px;
  padding: 10px 16px;
  border-radius: var(--s-r-md);
  box-shadow: var(--s-shadowCard);
  animation: sb-rise .25s ease both;
  pointer-events: none;
  max-width: calc(100% - 32px);
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
