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

/* Kawach Visual DNA
 * =================
 *
 * The foundation for the redesign. This file is NOT loaded by the app: it is
 * loaded only by /lab/, so the system can be judged in isolation before any
 * of the six screens is touched. `css/tokens.css` and `css/style.css` are
 * untouched and production still runs on them.
 *
 * Everything here has a measured value. Where a value looks arbitrary there
 * is a comment saying what decided it - usually contrast, a fingertip, or
 * the fact that a phone has to draw it sixty times a second.
 *
 * The one rule the whole system rests on: DEPTH INSTEAD OF BORDERS. A thing
 * is separated from the thing behind it by being made of slightly different
 * material and catching slightly different light, not by having a line drawn
 * around it. Lines are for when material cannot do the job.
 */

:root {
  /* ====================================================================
     01 · COLOUR
     A near-black navy ground, three accents that sit on one spectrum, and
     four colours that mean something about money. Nothing decorative.
     ==================================================================== */

  /* Ground. Not #000: pure black kills the sense of a lit room, and on OLED
     it makes every edge a hard cut. This is a very dark blue that still has
     somewhere to fall to. */
  --k-bg: oklch(12% 0.016 268);
  --k-bg-elev: oklch(15.5% 0.018 268);

  /* Surfaces, four steps up. Each is a real perceptual step (about 3.5% L),
     which is the smallest difference that still reads as "in front of". */
  --k-surface: oklch(19% 0.019 268);
  --k-surface-elev: oklch(22.5% 0.021 268);
  --k-surface-hero: oklch(26% 0.024 268);
  --k-surface-press: oklch(24% 0.022 268);

  /* Ink. Three levels and no more: a fourth is always someone hiding
     something they should have deleted. */
  --k-text: oklch(97% 0.004 260); /* 14.3:1 at worst */
  --k-text-2: oklch(73% 0.014 262); /*  6.5:1 at worst */
  --k-text-3: oklch(65% 0.016 262); /*  4.8:1 at worst, and that is the floor */

  /* Lines. Expressed as white at an opacity so they work over any surface
     level without being restated. */
  --k-hairline: oklch(100% 0 0 / 0.06);
  --k-border-subtle: oklch(100% 0 0 / 0.10);
  --k-border: oklch(100% 0 0 / 0.14);
  --k-border-emphasis: oklch(100% 0 0 / 0.22);

  /* The spectrum. Cyan, violet and magenta are one continuous sweep of hue
     (206 -> 292 -> 330), which is why a gradient between any two of them
     never muddies. Cyan leads; magenta is the far end and is used sparingly,
     mostly inside a drawing. */
  --k-cyan: oklch(82% 0.13 206);
  --k-cyan-deep: oklch(58% 0.14 216);
  --k-violet: oklch(66% 0.17 292);
  --k-magenta: oklch(72% 0.19 330);
  --k-accent: var(--k-cyan); /* the one thing you can press */
  --k-accent-2: var(--k-violet); /* the second voice in a comparison */
  --k-accent-ink: oklch(17% 0.04 220); /* text on a filled accent */

  /* Money. These four never decorate anything. */
  --k-positive: oklch(80% 0.16 158);
  --k-negative: oklch(70% 0.18 22);
  --k-warning: oklch(83% 0.15 78);
  --k-info: var(--k-cyan);

  /* ====================================================================
     02 · GLASS
     Four levels. Each differs measurably in all five of fill, blur,
     highlight, shadow and line, so they can be told apart at a glance and
     nobody has to guess which one to reach for.
     ==================================================================== */

  /* L1 · quiet panel: supporting information, a list, a row group. */
  --k-glass-1: color-mix(in srgb, var(--k-surface) 58%, transparent);
  --k-blur-1: 10px;

  /* L2 · data card: a figure with something to say. The default. */
  --k-glass-2: color-mix(in srgb, var(--k-surface-elev) 64%, transparent);
  --k-blur-2: 16px;

  /* L3 · focused: what you have opened, chosen, or are being pointed at. */
  --k-glass-3: color-mix(in srgb, var(--k-surface-elev) 74%, transparent);
  --k-blur-3: 22px;

  /* L4 · hero: one per screen. The answer. */
  --k-glass-4: color-mix(in srgb, var(--k-surface-hero) 70%, transparent);
  --k-blur-4: 30px;

  /* A sheet sits over everything and must not let the page read through it. */
  --k-glass-sheet: color-mix(in srgb, var(--k-bg-elev) 92%, transparent);
  --k-blur-sheet: 40px;

  /* The light along the top edge of a pane. This one gradient is what makes
     a rectangle read as a physical surface rather than a swatch. */
  --k-sheen: linear-gradient(
    180deg,
    oklch(100% 0 0 / 0.07) 0%,
    oklch(100% 0 0 / 0.018) 34%,
    transparent 64%
  );
  --k-sheen-hero: linear-gradient(
    180deg,
    oklch(100% 0 0 / 0.10) 0%,
    oklch(100% 0 0 / 0.025) 30%,
    transparent 60%
  );
  --k-inner-top: inset 0 1px 0 0 oklch(100% 0 0 / 0.09);
  --k-inner-top-hero: inset 0 1px 0 0 oklch(100% 0 0 / 0.14);

  /* ====================================================================
     03 · SHADOW  ·  three depths, no more
     ==================================================================== */
  --k-shadow-soft: 0 1px 2px oklch(0% 0 0 / 0.3), 0 4px 14px oklch(0% 0 0 / 0.22);
  --k-shadow-elev: 0 2px 6px oklch(0% 0 0 / 0.36), 0 12px 32px oklch(0% 0 0 / 0.3);
  --k-shadow-hero: 0 3px 10px oklch(0% 0 0 / 0.4), 0 24px 60px oklch(0% 0 0 / 0.42);

  /* ====================================================================
     04 · GLOW
     Light is the loudest thing in the system, so it is rationed: a screen
     gets at most three glowing objects. Numbers are drop-shadow radii.
     ==================================================================== */
  --k-glow-cyan: 0 0 26px color-mix(in srgb, var(--k-cyan) 30%, transparent);
  --k-glow-violet: 0 0 26px color-mix(in srgb, var(--k-violet) 28%, transparent);
  --k-glow-magenta: 0 0 26px color-mix(in srgb, var(--k-magenta) 28%, transparent);
  --k-glow-positive: 0 0 22px color-mix(in srgb, var(--k-positive) 26%, transparent);
  --k-glow-negative: 0 0 22px color-mix(in srgb, var(--k-negative) 26%, transparent);
  --k-glow-warning: 0 0 22px color-mix(in srgb, var(--k-warning) 24%, transparent);
  /* Light thrown by a figure itself, not by a box behind it. */
  --k-glow-text: 0 0 34px color-mix(in srgb, var(--k-cyan) 18%, transparent);

  /* ====================================================================
     05 · TYPOGRAPHY
     One family. Figures are tracked tighter as they grow, because a large
     number set at normal tracking reads as a scoreboard.
     ==================================================================== */
  --k-font: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --k-hero: clamp(3.1rem, 13.5vw, 4.25rem); /* the one answer on a screen */
  --k-display: 2.25rem; /* a figure a card is about */
  --k-title: 1.5rem; /* the screen's name */
  --k-heading: 1.125rem; /* a heading inside a screen */
  --k-value: 1.25rem; /* an ordinary money figure */
  --k-value-sm: 1rem; /* a figure in a row */
  --k-body: 0.9375rem; /* sentences, names */
  --k-label: 0.8125rem; /* the name of a thing */
  --k-caption: 0.6875rem; /* the line under it */

  /* Weight says what a thing is, not how loud it is. Four, and no others. */
  --k-w-fig: 640;
  --k-w-strong: 700;
  --k-w-label: 500;
  --k-w-body: 400;

  --k-track-hero: -0.045em;
  --k-track-display: -0.03em;
  --k-track-title: -0.02em;
  --k-track-caption: 0.04em; /* small caps-ish labels open up slightly */

  --k-lh-tight: 0.95;
  --k-lh-snug: 1.25;
  --k-lh-body: 1.5;

  /* ====================================================================
     06 · SPACING  ·  a 4-point scale, named by size
     ==================================================================== */
  --k-1: 4px;
  --k-2: 8px;
  --k-3: 12px;
  --k-4: 16px;
  --k-5: 20px;
  --k-6: 24px;
  --k-8: 32px;
  --k-10: 40px;
  --k-12: 48px;
  --k-16: 64px;

  /* ====================================================================
     07 · RADIUS  ·  nothing is ever rounder than its parent
     ==================================================================== */
  --k-r-xs: 8px; /* a tag, a swatch */
  --k-r-sm: 12px; /* an icon tile, a small control */
  --k-r-md: 16px; /* an input, a raised strip */
  --k-r-lg: 22px; /* a data card */
  --k-r-xl: 28px; /* a hero, a sheet */
  --k-r-2xl: 36px; /* a full-bleed feature panel */
  --k-r-pill: 999px;

  /* ====================================================================
     08 · CONTROLS  ·  three heights, one tap rule
     ==================================================================== */
  --k-ctl-lg: 52px; /* a full-width primary action */
  --k-ctl-md: 44px; /* a row, a select, a segmented control */
  --k-ctl-sm: 34px; /* a chip, inside a 44px tap area */
  --k-tap: 44px; /* the floor, whatever the glyph looks like */
  --k-icon-lg: 1.5rem;
  --k-icon-md: 1.25rem;
  --k-icon-sm: 1rem;

  /* ====================================================================
     09 · MOTION
     Short, and always about cause and effect. Nothing loops, nothing
     bounces, nothing moves that is not answering something.
     ==================================================================== */
  --k-t-instant: 0ms;
  --k-t-fast: 140ms; /* a press */
  --k-t-normal: 240ms; /* a state change */
  --k-t-slow: 420ms; /* something arriving */
  /* The expressive ceiling. 900ms was the old value and nothing ever used
     it; 600ms is the top of the band a person still reads as one motion
     rather than as waiting. A chart that needs longer is staggered out of
     several of these, never stretched into one slow one. */
  --k-t-draw: 600ms;
  --k-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --k-ease-in: cubic-bezier(0.7, 0, 0.84, 0);
  --k-ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  /* The one spring, for a sheet arriving. Overshoot is tiny on purpose. */
  --k-spring: cubic-bezier(0.16, 1, 0.3, 1); /* no overshoot: a sheet is UI, not a thing thrown */

  /* ====================================================================
     10 · ATMOSPHERE
     Strengths are capped by measurement, not taste: above roughly a tenth
     of a wash at any one pixel, --k-text-3 stops clearing 4.5:1 against its
     own background. That ceiling is the reason these numbers are small.
     ==================================================================== */
  --k-atm-cyan: 10%;
  --k-atm-violet: 9%;
  --k-atm-magenta: 6%;
  --k-atm-warm: 4%;
  --k-atm-warm-hue: oklch(74% 0.12 52);
}

/* Light is a different material, not an inversion. Glass on paper is nearly
   opaque, the sheen becomes a shadow from above, and glow all but vanishes,
   because a lit edge on white reads as a smudge. Hierarchy in daylight is
   carried by weight and space, the way paper has always done it. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --k-bg: oklch(97% 0.004 258);
    --k-bg-elev: oklch(100% 0 0);
    --k-surface: oklch(100% 0 0);
    --k-surface-elev: oklch(98.5% 0.003 258);
    --k-surface-hero: oklch(100% 0 0);
    --k-surface-press: oklch(95.5% 0.005 258);

    --k-text: oklch(19% 0.014 264);
    --k-text-2: oklch(47% 0.016 262);
    --k-text-3: oklch(52% 0.016 262);

    --k-hairline: oklch(19% 0.014 264 / 0.07);
    --k-border-subtle: oklch(19% 0.014 264 / 0.11);
    --k-border: oklch(19% 0.014 264 / 0.15);
    --k-border-emphasis: oklch(19% 0.014 264 / 0.26);

    --k-cyan: oklch(54% 0.14 232);
    --k-cyan-deep: oklch(44% 0.13 228);
    --k-violet: oklch(50% 0.17 292);
    --k-magenta: oklch(54% 0.19 330);
    --k-accent-ink: oklch(100% 0 0);

    --k-positive: oklch(52% 0.13 158);
    --k-negative: oklch(55% 0.19 26);
    --k-warning: oklch(54% 0.13 70);

    --k-glass-1: color-mix(in srgb, var(--k-surface) 86%, transparent);
    --k-glass-2: color-mix(in srgb, var(--k-surface) 92%, transparent);
    --k-glass-3: color-mix(in srgb, var(--k-surface) 96%, transparent);
    --k-glass-4: color-mix(in srgb, var(--k-surface) 96%, transparent);
    --k-glass-sheet: color-mix(in srgb, var(--k-surface) 98%, transparent);

    --k-sheen: linear-gradient(180deg, oklch(100% 0 0 / 0.9) 0%, oklch(100% 0 0 / 0.3) 40%, transparent 72%);
    --k-sheen-hero: var(--k-sheen);
    --k-inner-top: inset 0 1px 0 0 oklch(100% 0 0 / 0.8);
    --k-inner-top-hero: var(--k-inner-top);

    --k-shadow-soft: 0 1px 2px oklch(19% 0.014 264 / 0.05), 0 3px 12px oklch(19% 0.014 264 / 0.06);
    --k-shadow-elev: 0 2px 6px oklch(19% 0.014 264 / 0.07), 0 10px 28px oklch(19% 0.014 264 / 0.09);
    --k-shadow-hero: 0 3px 10px oklch(19% 0.014 264 / 0.08), 0 20px 48px oklch(19% 0.014 264 / 0.12);

    --k-glow-cyan: 0 0 18px color-mix(in srgb, var(--k-cyan) 12%, transparent);
    --k-glow-violet: 0 0 18px color-mix(in srgb, var(--k-violet) 11%, transparent);
    --k-glow-magenta: 0 0 18px color-mix(in srgb, var(--k-magenta) 11%, transparent);
    --k-glow-positive: 0 0 16px color-mix(in srgb, var(--k-positive) 10%, transparent);
    --k-glow-negative: 0 0 16px color-mix(in srgb, var(--k-negative) 10%, transparent);
    --k-glow-warning: 0 0 16px color-mix(in srgb, var(--k-warning) 10%, transparent);
    --k-glow-text: none;

    --k-atm-cyan: 7%;
    --k-atm-violet: 6%;
    --k-atm-magenta: 4%;
    --k-atm-warm: 3%;
  }
}
/* generated from the block above by tools/theme; do not edit by hand */
:root[data-theme="light"] {
    --k-bg: oklch(97% 0.004 258);
    --k-bg-elev: oklch(100% 0 0);
    --k-surface: oklch(100% 0 0);
    --k-surface-elev: oklch(98.5% 0.003 258);
    --k-surface-hero: oklch(100% 0 0);
    --k-surface-press: oklch(95.5% 0.005 258);

    --k-text: oklch(19% 0.014 264);
    --k-text-2: oklch(47% 0.016 262);
    --k-text-3: oklch(52% 0.016 262);

    --k-hairline: oklch(19% 0.014 264 / 0.07);
    --k-border-subtle: oklch(19% 0.014 264 / 0.11);
    --k-border: oklch(19% 0.014 264 / 0.15);
    --k-border-emphasis: oklch(19% 0.014 264 / 0.26);

    --k-cyan: oklch(54% 0.14 232);
    --k-cyan-deep: oklch(44% 0.13 228);
    --k-violet: oklch(50% 0.17 292);
    --k-magenta: oklch(54% 0.19 330);
    --k-accent-ink: oklch(100% 0 0);

    --k-positive: oklch(52% 0.13 158);
    --k-negative: oklch(55% 0.19 26);
    --k-warning: oklch(54% 0.13 70);

    --k-glass-1: color-mix(in srgb, var(--k-surface) 86%, transparent);
    --k-glass-2: color-mix(in srgb, var(--k-surface) 92%, transparent);
    --k-glass-3: color-mix(in srgb, var(--k-surface) 96%, transparent);
    --k-glass-4: color-mix(in srgb, var(--k-surface) 96%, transparent);
    --k-glass-sheet: color-mix(in srgb, var(--k-surface) 98%, transparent);

    --k-sheen: linear-gradient(180deg, oklch(100% 0 0 / 0.9) 0%, oklch(100% 0 0 / 0.3) 40%, transparent 72%);
    --k-sheen-hero: var(--k-sheen);
    --k-inner-top: inset 0 1px 0 0 oklch(100% 0 0 / 0.8);
    --k-inner-top-hero: var(--k-inner-top);

    --k-shadow-soft: 0 1px 2px oklch(19% 0.014 264 / 0.05), 0 3px 12px oklch(19% 0.014 264 / 0.06);
    --k-shadow-elev: 0 2px 6px oklch(19% 0.014 264 / 0.07), 0 10px 28px oklch(19% 0.014 264 / 0.09);
    --k-shadow-hero: 0 3px 10px oklch(19% 0.014 264 / 0.08), 0 20px 48px oklch(19% 0.014 264 / 0.12);

    --k-glow-cyan: 0 0 18px color-mix(in srgb, var(--k-cyan) 12%, transparent);
    --k-glow-violet: 0 0 18px color-mix(in srgb, var(--k-violet) 11%, transparent);
    --k-glow-magenta: 0 0 18px color-mix(in srgb, var(--k-magenta) 11%, transparent);
    --k-glow-positive: 0 0 16px color-mix(in srgb, var(--k-positive) 10%, transparent);
    --k-glow-negative: 0 0 16px color-mix(in srgb, var(--k-negative) 10%, transparent);
    --k-glow-warning: 0 0 16px color-mix(in srgb, var(--k-warning) 10%, transparent);
    --k-glow-text: none;

    --k-atm-cyan: 7%;
    --k-atm-violet: 6%;
    --k-atm-magenta: 4%;
    --k-atm-warm: 3%;
  }

/* ======================================================================
   COMPONENT GRAMMAR
   Every rule below is an application of the tokens above. No component
   invents a value of its own.
   ====================================================================== */

.k {
  font-family: var(--k-font);
  color: var(--k-text);
  background: var(--k-bg);
  font-size: var(--k-body);
  line-height: var(--k-lh-body);
  -webkit-font-smoothing: antialiased;
}

/* --- Atmosphere ------------------------------------------------------
   Two fixed layers behind everything: the near field at the top, where the
   light comes from, and the far field, which keeps the room lit all the way
   down instead of stopping below the fold. Both are enormous and weak. */

/* --- The one reset -------------------------------------------------
   The system sized everything as if padding were inside the box, but never
   said so: it was borrowing the reset in style.css. That held while the DNA
   was only ever loaded next to it, and broke the moment the lab loaded this
   file on its own - a full-width input came out 34px wider than its field.
   A design system that only works when another stylesheet is present is not
   a design system, so it says so here. Scoped to .k, which is on every
   migrated container and on the lab, so it changes nothing anywhere else.
   --------------------------------------------------------------------- */
.k,
.k *,
.k *::before,
.k *::after { box-sizing: border-box; }

/* --- Glass panel: the base every surface derives from ---------------- */
.k-pane {
  position: relative;
  background-color: var(--k-glass-2);
  background-image: var(--k-sheen);
  -webkit-backdrop-filter: blur(var(--k-blur-2));
  backdrop-filter: blur(var(--k-blur-2));
  border: 1px solid var(--k-hairline);
  border-radius: var(--k-r-lg);
  box-shadow: var(--k-inner-top), var(--k-shadow-soft);
  padding: var(--k-5);
}

.k-pane--quiet {
  background-color: var(--k-glass-1);
  -webkit-backdrop-filter: blur(var(--k-blur-1));
  backdrop-filter: blur(var(--k-blur-1));
  box-shadow: var(--k-inner-top);
}

/* --- Hero: one per screen, and it holds four things ------------------ */
.k-hero {
  position: relative;
  overflow: hidden;
  background-color: var(--k-glass-4);
  background-image: var(--k-sheen-hero);
  -webkit-backdrop-filter: blur(var(--k-blur-4));
  backdrop-filter: blur(var(--k-blur-4));
  border: 1px solid var(--k-border-subtle);
  border-radius: var(--k-r-xl);
  box-shadow: var(--k-inner-top-hero), var(--k-shadow-hero);
  padding: var(--k-6);
}

/* The pool of light behind the figure. One per hero, never per card. */
.k-hero::before {
  content: "";
  position: absolute;
  inset: -50% 12% auto -28%;
  height: 62%;
  background: radial-gradient(58% 100% at 46% 0%, color-mix(in srgb, var(--k-cyan) 15%, transparent), transparent 70%);
  pointer-events: none;
}
.k-hero > * { position: relative; }

.k-label {
  font-size: var(--k-label);
  font-weight: var(--k-w-label);
  color: var(--k-text-2);
}

/* --- Metric: a label above a figure, stacked, never side by side ----- */

/* --- Buttons: one geometry, three voices ---------------------------- */
.k-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--k-2);
  min-height: var(--k-ctl-md);
  padding: 0 var(--k-5);
  border-radius: var(--k-r-pill);
  border: 1px solid transparent;
  font-family: inherit;
  font-size: var(--k-body);
  font-weight: var(--k-w-fig);
  cursor: pointer;
  transition: background var(--k-t-fast) var(--k-ease), transform var(--k-t-fast) var(--k-ease),
    box-shadow var(--k-t-fast) var(--k-ease);
}
.k-btn:active { transform: translateY(1px); }

.k-btn--primary {
  min-height: var(--k-ctl-lg);
  background: var(--k-accent);
  color: var(--k-accent-ink);
  font-weight: var(--k-w-strong);
  box-shadow: inset 0 1px 0 0 oklch(100% 0 0 / 0.28), var(--k-glow-cyan);
}
.k-btn--primary:active { box-shadow: inset 0 1px 0 0 oklch(100% 0 0 / 0.2); }

.k-btn--secondary {
  background-color: var(--k-glass-2);
  background-image: var(--k-sheen);
  border-color: var(--k-border-subtle);
  color: var(--k-text);
}
.k-btn--secondary:active { background-color: var(--k-surface-press); }

.k-btn--ghost { background: none; color: var(--k-text-2); }
.k-btn--ghost:active { background: var(--k-surface-press); }

/* --- Chip and pill: small, and their target is not ------------------- */

/* A glyph may be small. Its target may not. This strip is invisible, adds
   nothing to the layout, and is the size of a fingertip. */
.k-seg__btn::before,
.k-toggle::before {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: var(--k-tap);
  transform: translateY(-50%);
}

/* --- Segmented control: one track, one lit cell --------------------- */
.k-seg {
  display: inline-flex;
  padding: var(--k-1);
  gap: var(--k-1);
  border-radius: var(--k-r-pill);
  background: var(--k-glass-1);
  border: 1px solid var(--k-hairline);
}
.k-seg__btn {
  position: relative;
  min-height: var(--k-ctl-sm);
  padding: 0 var(--k-4);
  border: 0;
  border-radius: var(--k-r-pill);
  background: none;
  color: var(--k-text-2);
  font: inherit;
  font-size: var(--k-label);
  font-weight: var(--k-w-label);
  cursor: pointer;
  transition: background var(--k-t-fast) var(--k-ease), color var(--k-t-fast) var(--k-ease);
}
.k-seg__btn[aria-selected="true"] {
  background: color-mix(in srgb, var(--k-accent) 15%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--k-accent) 38%, transparent);
  color: var(--k-text);
  font-weight: var(--k-w-fig);
}

/* --- Input and select: the same pane as everything else ------------- */
.k-field { display: flex; flex-direction: column; gap: var(--k-2); }
.k-input,
.k-select {
  width: 100%;
  min-height: var(--k-ctl-md);
  padding: 0 var(--k-4);
  border-radius: var(--k-r-md);
  border: 1px solid var(--k-border-subtle);
  background-color: var(--k-glass-1);
  background-image: var(--k-sheen);
  color: var(--k-text);
  font-family: inherit;
  /* 16px exactly: below that iOS zooms the page when the field takes focus. */
  font-size: 16px;
  transition: border-color var(--k-t-fast) var(--k-ease), box-shadow var(--k-t-fast) var(--k-ease);
}
.k-input::placeholder { color: var(--k-text-3); }
.k-input:focus-visible,
.k-select:focus-visible {
  outline: 2px solid var(--k-accent);
  outline-offset: 1px;
  border-color: color-mix(in srgb, var(--k-accent) 60%, transparent);
  box-shadow: var(--k-glow-cyan);
}
/* The browser's own arrow is the one control that never matches, so the
   element keeps all its behaviour and only its skin changes. */
.k-select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: calc(var(--k-5) + 0.7em);
  background-image: var(--k-sheen),
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: 0 0, right calc(var(--k-4) + 0.3em) center, right var(--k-4) center;
  background-size: auto, 0.32em 0.32em, 0.32em 0.32em;
  background-repeat: no-repeat;
  color: var(--k-text-2);
}

/* --- Toggle --------------------------------------------------------- */
.k-toggle {
  position: relative;
  width: 52px;
  height: 30px;
  flex: none;
  border: 0;
  border-radius: var(--k-r-pill);
  background: var(--k-surface-elev);
  cursor: pointer;
  transition: background var(--k-t-normal) var(--k-ease);
}
.k-toggle::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--k-text-2);
  transition: transform var(--k-t-normal) var(--k-ease), background var(--k-t-normal) var(--k-ease);
}
.k-toggle[aria-checked="true"] { background: color-mix(in srgb, var(--k-accent) 40%, transparent); box-shadow: var(--k-glow-cyan); }
.k-toggle[aria-checked="true"]::after { transform: translateX(22px); background: var(--k-accent); }

/* --- Icon tile: a category's colour lives here, not in a filled block */
.k-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: var(--k-r-sm);
  background: color-mix(in srgb, var(--k-tint, var(--k-accent)) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--k-tint, var(--k-accent)) 26%, transparent);
  color: var(--k-tint, var(--k-accent));
  font-size: var(--k-icon-md);
}

/* --- Rows: content on a surface, not a box per item ----------------- */
.k-rows { display: flex; flex-direction: column; }
.k-row {
  display: flex;
  align-items: center;
  gap: var(--k-3);
  min-height: 58px;
  padding: var(--k-3) 0;
  text-align: left;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  width: 100%;
  cursor: pointer;
}
.k-row + .k-row { border-top: 1px solid var(--k-hairline); }
.k-row:active { background: var(--k-surface-press); }
.k-row__body { flex: 1; min-width: 0; }
/* A row is a title with its detail under it, so both are blocks. They were
   inline while only Add used them, which worked by accident: Add gives a
   row a title and nothing else. */
.k-row__title { display: block; font-size: var(--k-body); font-weight: var(--k-w-fig); }
.k-row__meta { display: block; font-size: var(--k-label); color: var(--k-text-3); margin-top: 2px; }
.k-row__value { font-size: var(--k-value-sm); font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; }
.k-row__value--pos { color: var(--k-positive); }

/* --- Disclosure: one turning arrow in the whole product ------------- */
.k-disclose > summary {
  display: flex;
  align-items: center;
  gap: var(--k-2);
  min-height: var(--k-tap);
  list-style: none;
  cursor: pointer;
  font-size: var(--k-body);
}
.k-disclose > summary::-webkit-details-marker { display: none; }
.k-disclose > summary::after {
  content: "";
  flex: none;
  width: 0.42em;
  height: 0.42em;
  margin-left: auto;
  border-right: 1.75px solid var(--k-text-2);
  border-bottom: 1.75px solid var(--k-text-2);
  transform: rotate(45deg) translate(-0.1em, -0.1em);
  transition: transform var(--k-t-normal) var(--k-ease), border-color var(--k-t-normal) var(--k-ease);
}
.k-disclose[open] > summary::after {
  border-color: var(--k-accent);
  transform: rotate(-135deg) translate(-0.1em, -0.1em);
}

/* --- Insight: the app noticing something ---------------------------- */
.k-insight {
  display: flex;
  gap: var(--k-3);
  align-items: flex-start;
  padding: var(--k-4);
  border-radius: var(--k-r-lg);
  background-color: var(--k-glass-2);
  background-image: var(--k-sheen);
  border: 1px solid var(--k-hairline);
  box-shadow: var(--k-inner-top), var(--k-shadow-soft);
}

.k-insight__title { font-size: var(--k-body); font-weight: var(--k-w-strong); }
.k-insight__body { font-size: var(--k-label); color: var(--k-text-2); line-height: var(--k-lh-body); }

/* --- Charts ---------------------------------------------------------
   One family of strokes, set here so no drawing can invent its own. Red is
   not a chart colour: it is kept for money that has actually gone. */

/* The thing a line is measured against is never lit. That is its job. */

/* A meter is a chart with one value. */
.k-meter { height: 10px; border-radius: var(--k-r-pill); background: color-mix(in srgb, var(--k-surface-elev) 60%, transparent); overflow: hidden; }
.k-meter__fill {
  height: 100%;
  border-radius: var(--k-r-pill);
  background: linear-gradient(90deg, var(--k-cyan), var(--k-violet));
  box-shadow: 0 0 12px color-mix(in srgb, var(--k-cyan) 40%, transparent);
  transition: width var(--k-t-slow) var(--k-ease);
}

/* --- Bottom navigation: part of the shell, not another card --------- */

/* --- Sheet ---------------------------------------------------------- */
.k-scrim { position: fixed; inset: 0; background: oklch(0% 0 0 / 0.55); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.k-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--k-5) var(--k-5) calc(var(--k-6) + env(safe-area-inset-bottom));
  border-radius: var(--k-r-xl) var(--k-r-xl) 0 0;
  background-color: var(--k-glass-sheet);
  background-image: var(--k-sheen-hero);
  -webkit-backdrop-filter: blur(var(--k-blur-sheet));
  backdrop-filter: blur(var(--k-blur-sheet));
  border-top: 1px solid var(--k-border-subtle);
  box-shadow: var(--k-shadow-hero);
  animation: k-sheet-in var(--k-t-slow) var(--k-spring);
}
.k-sheet__grip { width: 40px; height: 4px; border-radius: var(--k-r-pill); background: var(--k-border-emphasis); margin: 0 auto var(--k-4); }

/* --- Empty and loading ---------------------------------------------- */

/* --- Focus: one ring, everywhere ------------------------------------ */
.k :focus-visible,
.k-btn:focus-visible,
.k-row:focus-visible,
.k-seg__btn:focus-visible {
  outline: 2px solid var(--k-accent);
  outline-offset: 2px;
  border-radius: var(--k-r-sm);
}

/* --- Motion --------------------------------------------------------- */
@keyframes k-sheet-in { from { transform: translateY(100%); } to { transform: translateY(0); } }

@keyframes k-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* Said once, for the whole system: when the phone asks for less movement,
   nothing moves. The state still changes; it stops sliding into it. */
@media (prefers-reduced-motion: reduce) {
  .k *,
  .k *::before,
  .k *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ======================================================================
   MIGRATION · screens still carrying the old class names
   ======================================================================

   A screen joins the new system by taking the `k` class. Everything below
   maps the markup that screen already emits onto the grammar above, so a
   screen can move over without its JavaScript being rewritten and without
   the other screens seeing any of it.

   This section should SHRINK to nothing. Each screen that migrates takes
   its rules with it; when the last one has moved, the markup emits the
   `k-` classes directly and this block is deleted. It is scaffolding, and
   it is labelled as scaffolding so nobody mistakes it for the system.

   Phase 9A: Summary only. `#dashboard` is rendered by Summary and by
   nothing else, so `.k` on it cannot leak into another screen.
   ====================================================================== */

/* The room. style.css already paints an atmosphere for the whole app; on a
   migrated screen the DNA's is used instead, so there are never two. */
/* The shell follows whichever screens are on the system. It used to name
   three of them by a marker each - #dashboard, #hist-hero, #add-form -
   which meant every migration had to remember to add itself here, and
   Accounts, Plan and Coach were left with the old header and nav after
   their screens had moved. Every migrated view puts k on the container,
   so that is the thing to ask about. */
body:has(#view-container.k) {
  background: var(--k-bg);
  color: var(--k-text);
  font-family: var(--k-font);
}

body:has(#view-container.k)::before,
body:has(#view-container.k)::after {
  content: "";
  position: fixed;
  pointer-events: none;
  z-index: 0;
}

body:has(#view-container.k)::before {
  inset: -12% -20% auto -20%;
  height: 56vh;
  background:
    radial-gradient(62% 70% at 14% 0%, color-mix(in srgb, var(--k-cyan) var(--k-atm-cyan), transparent), transparent 72%),
    radial-gradient(54% 66% at 92% 3%, color-mix(in srgb, var(--k-violet) var(--k-atm-violet), transparent), transparent 74%);
}

body:has(#view-container.k)::after {
  inset: 0;
  background:
    radial-gradient(84% 46% at -16% 34%, color-mix(in srgb, var(--k-cyan) var(--k-atm-magenta), transparent), transparent 74%),
    radial-gradient(74% 44% at 118% 58%, color-mix(in srgb, var(--k-magenta) var(--k-atm-magenta), transparent), transparent 72%),
    radial-gradient(80% 40% at 110% 100%, color-mix(in srgb, var(--k-atm-warm-hue) var(--k-atm-warm), transparent), transparent 70%);
}

/* --- the hero ------------------------------------------------------- */
.k .hero {
  position: relative;
  overflow: hidden;
  background-color: var(--k-glass-4);
  background-image: var(--k-sheen-hero);
  -webkit-backdrop-filter: blur(var(--k-blur-4));
  backdrop-filter: blur(var(--k-blur-4));
  border: 1px solid var(--k-border-subtle);
  border-radius: var(--k-r-xl);
  padding: var(--k-6);
  margin: var(--k-1) 0 var(--k-5);
  box-shadow: var(--k-inner-top-hero), var(--k-shadow-hero);
}

.k .hero::before {
  inset: -50% 12% auto -28%;
  height: 62%;
  background: radial-gradient(58% 100% at 46% 0%, color-mix(in srgb, var(--k-cyan) 15%, transparent), transparent 70%);
}

.k .hero-label {
  font-size: var(--k-label);
  font-weight: var(--k-w-label);
  color: var(--k-text-2);
}

.k .hero-amount {
  font-size: var(--k-hero);
  font-weight: var(--k-w-strong);
  letter-spacing: var(--k-track-hero);
  line-height: var(--k-lh-tight);
  margin: var(--k-2) 0 var(--k-1);
  text-shadow: var(--k-glow-text);
  /* A figure is one word. It may shrink, it may never break. */
  white-space: nowrap;
}

/* On a narrow phone a seven-figure balance at the full hero size does not
   fit the line, and nowrap alone would push it off the screen. The token
   stays as it is; the hero simply sets a smaller size for itself here. */
@media (max-width: 360px) {
  .k .hero-amount { font-size: clamp(2.4rem, 12vw, 3.1rem); }
}

.k .hero.level-over .hero-amount,
.k .hero-amount.negative {
  color: var(--k-negative);
  text-shadow: 0 0 34px color-mix(in srgb, var(--k-negative) 20%, transparent);
}

/* The sentence under the figure is a sentence, never a tinted strip. */
.k .hero-status {
  margin: var(--k-4) 0 0;
  padding: 0;
  background: none;
  font-size: var(--k-label);
  font-weight: var(--k-w-label);
  color: var(--k-text-2);
}

.k .hero-status.level-warning { color: var(--k-warning); }
.k .hero-status.level-critical,
.k .hero-status.level-over { color: var(--k-negative); }

/* Supporting figures under the hero: label over value, label quiet. */
.k .hero-under { gap: var(--k-8); margin: var(--k-4) var(--k-4) 0; }

.k .stat-k {
  font-size: var(--k-caption);
  font-weight: var(--k-w-label);
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-text-3);
}

.k .stat-v {
  font-size: var(--k-value);
  font-weight: var(--k-w-fig);
  letter-spacing: var(--k-track-title);
}

/* --- panes ---------------------------------------------------------- */
.k .totals-card,
.k .breakdown-list,
.k .cat-list,
.k .empty-state {
  position: relative;
  background-color: var(--k-glass-2);
  background-image: var(--k-sheen);
  border: 1px solid var(--k-hairline);
  border-radius: var(--k-r-lg);
  box-shadow: var(--k-inner-top), var(--k-shadow-soft);
}

/* A pane inside a pane is always wrong here.
 *
 * The panes are translucent glass, so putting one inside another stacks the
 * tint: the inner box comes out darker and heavier than the card holding it,
 * with its own edge and its own 22px corners. That is what the bank
 * breakdown looked like - a second card drawn inside the first, indented,
 * with a seam down its right side.
 *
 * The inner one keeps its rows and its spacing, and loses everything that
 * made it look like a pane. Written as a rule rather than fixed at the one
 * call site, because a pane inside a pane is never right in this design and
 * there are sixty-odd places that could do it. */
.k .totals-card .totals-card,
.k .breakdown-list .totals-card,
.k .empty-state .totals-card {
  background: none;
  background-image: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.k .bank-card { padding: var(--k-5); border-radius: var(--k-r-lg); }
.k .bank-amount { font-size: var(--k-display); font-weight: var(--k-w-fig); letter-spacing: var(--k-track-display); }
.k .bank-amount.small { font-size: var(--k-value); }

/* A warning keeps a visible edge. That is the one thing an edge is for. */
.k .warn-card,
.k .due-soon {
  border-color: color-mix(in srgb, var(--k-warning) 30%, transparent);
}

/* --- rows and disclosures ------------------------------------------- */
.k .disclose > summary,
.k .section-fold > summary {
  min-height: var(--k-tap);
  font-size: var(--k-body);
}

.k .disclose,
.k .section-fold { border-color: var(--k-hairline); }
.k .disclose > summary::after,
.k .section-fold > summary::after { border-color: var(--k-text-2); }
.k .disclose[open] > summary::after,
.k .section-fold[open] > summary::after { border-color: var(--k-accent); }

.k .breakdown-row + .breakdown-row,
.k .commitment-row + .commitment-row,
.k .todo-row + .todo-row { border-top-color: var(--k-hairline); }

/* --- controls ------------------------------------------------------- */
.k .btn-primary {
  min-height: var(--k-ctl-lg);
  border-radius: var(--k-r-pill);
  background: var(--k-accent);
  color: var(--k-accent-ink);
  font-weight: var(--k-w-strong);
  box-shadow: inset 0 1px 0 0 oklch(100% 0 0 / 0.28), var(--k-glow-cyan);
}

.k .btn-secondary,
.k .btn-tiny {
  background-color: var(--k-glass-2);
  background-image: var(--k-sheen);
  border-color: var(--k-border-subtle);
  color: var(--k-text);
  border-radius: var(--k-r-pill);
}

.k .chip,
.k .seg-btn,
.k .plan-chip {
  border-radius: var(--k-r-pill);
  font-size: var(--k-label);
  font-weight: var(--k-w-label);
}

/* Chosen is a tint and a ring. A filled control means "this is the action",
   and a screen has one of those. */
.k .chip.active,
.k .chip.selected,
.k .seg-btn.active {
  background: color-mix(in srgb, var(--k-accent) 14%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--k-accent) 42%, transparent), var(--k-glow-cyan);
  color: var(--k-text);
  font-weight: var(--k-w-fig);
}

/* --- money ---------------------------------------------------------- */
.k .in { color: var(--k-positive); }
.k .out { color: var(--k-negative); }
.k .muted { color: var(--k-text-2); }
.k .muted-note { color: var(--k-text-3); font-size: var(--k-label); }

/* --- charts --------------------------------------------------------- */
.k .chart-line {
  stroke: var(--k-accent);
  stroke-width: 2.5;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--k-accent) 55%, transparent));
}

.k .chart-pace { stroke: var(--k-text-3); stroke-width: 2; opacity: 0.7; }
.k .chart-note { font-size: var(--k-label); color: var(--k-text-2); margin-top: var(--k-3); }
.k .chart-dot { fill: var(--k-accent); filter: drop-shadow(0 0 7px color-mix(in srgb, var(--k-accent) 70%, transparent)); }
.k .chart-dot-halo { fill: color-mix(in srgb, var(--k-accent) 20%, transparent); }
.k .chart-projection { stroke: var(--k-text-2); stroke-width: 2; opacity: 0.7; }
.k .chart-dot--projection { fill: var(--k-text-2); opacity: 0.9; }
.k .chart-ring-track {
  fill: none;
  stroke: color-mix(in srgb, var(--k-surface-elev) 72%, transparent);
  stroke-width: 11;
  vector-effect: non-scaling-stroke;
}
.k .chart-ring-fill {
  fill: none;
  stroke: var(--k-accent);
  stroke-width: 11;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--k-accent) 42%, transparent));
  vector-effect: non-scaling-stroke;
}
.k .goal-ring,
.k .alloc-ring { display: block; width: 100%; max-width: 120px; height: auto; overflow: visible; }
.k .chart-block { width: 100%; min-width: 0; }
.k .chart-block > svg { max-width: 100%; }
.k .bar-in { fill: color-mix(in srgb, var(--k-positive) 70%, transparent); }
.k .bar-out { fill: color-mix(in srgb, var(--k-negative) 66%, transparent); }
.k .bar-track { fill: color-mix(in srgb, var(--k-surface-elev) 48%, transparent); }

.k .hero-meter { background: color-mix(in srgb, var(--k-surface-elev) 55%, transparent); }
.k .hero-meter-fill {
  background: linear-gradient(90deg, var(--k-cyan), var(--k-violet));
  box-shadow: 0 0 12px color-mix(in srgb, var(--k-cyan) 40%, transparent);
}

/* --- headings, and the air between sections ------------------------- */
.k .section-head h3 {
  font-size: var(--k-caption);
  font-weight: var(--k-w-fig);
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-text-3);
}

.k .section-head { margin: var(--k-8) 0 var(--k-3); }

/* --- the shell ------------------------------------------------------ */
body:has(#view-container.k) .app-header {
  background: linear-gradient(180deg, var(--k-bg) 0%, var(--k-bg) 62%, transparent 100%);
}

body:has(#view-container.k) .app-header h1 {
  font-size: var(--k-title);
  font-weight: var(--k-w-strong);
  letter-spacing: var(--k-track-title);
}

body:has(#view-container.k) .bottom-nav {
  /* Opaque, for the same reason as the base rule in css/style.css: at 80%
     anything scrolling underneath stayed readable through the labels. */
  background: var(--k-bg-elev);
  border-top-color: var(--k-hairline);
}

/* Where you are is said with light, not with a bright pill behind it. */
body:has(#view-container.k) .nav-btn { color: var(--k-text-3); }
body:has(#view-container.k) .nav-btn.active { background: none; color: var(--k-text); }
body:has(#view-container.k) .nav-btn.active .nav-icon {
  color: var(--k-accent-text);
  filter: drop-shadow(0 0 9px color-mix(in srgb, var(--k-accent) 55%, transparent));
}

/* ---------------------------------------------------------------------
   MIGRATION · History  (phase 9B)
   Scoped by `.k` on History's own container, exactly as Summary is.
   --------------------------------------------------------------------- */

/* --- the month stepper, above the hero ------------------------------ */
.k .hist-month { margin: var(--k-1) 0 var(--k-3); }
.k .hist-month-name {
  font-size: var(--k-heading);
  font-weight: var(--k-w-strong);
  letter-spacing: var(--k-track-title);
  color: var(--k-text);
}

/* --- the hero ------------------------------------------------------- */
/* The month leads and the figure answers it, so the two labels are not
   competing: the period is ordinary ink, the description is quieter. */
.k #hist-period { color: var(--k-text-2); font-weight: var(--k-w-fig); }

.k .hero-under #hist-stats,
.k #hist-stats { gap: var(--k-8); }

/* The sentence under the figure sits between it and the drawing, so it
   needs room on both sides rather than being wedged against either. */
.k #txn-count { margin: var(--k-3) 0 var(--k-1); }

/* --- the six-month chart -------------------------------------------- */
/* It lives inside the hero, so it runs to the hero's own edges instead of
   sitting in a box of its own with a second background behind it. */
.k #hist-hero .chart-block {
  margin: var(--k-4) 0 0;
  background: none;
  border: 0;
  padding: 0;
}

/* Green is money in and coral is money out, at well under full strength,
   with only a breath of light on them. Fluorescent bars are what made this
   screen read as a different application. */
.k #hist-hero .bar-in {
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--k-positive) 26%, transparent));
}
.k #hist-hero .bar-out {
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--k-negative) 24%, transparent));
}

/* The month you are looking at is the one that matters; the five behind it
   are there for comparison and step back. The last two bars in the drawing
   are always the newest month, whichever months happen to have data. */
.k #hist-hero .bar-in,
.k #hist-hero .bar-out { opacity: 0.6; }
.k #hist-hero .bar-in:nth-last-of-type(2),
.k #hist-hero .bar-out:nth-last-of-type(1) { opacity: 1; }

.k #hist-hero .bar-track { fill: color-mix(in srgb, var(--k-surface-elev) 34%, transparent); }
.k #hist-hero .chart-tick { fill: var(--k-text-3); }

/* The legend is a sentence, so it is set like one. */
.k .in-out-legend {
  /* The gap was here without the flex that makes a gap mean anything, so the
     three parts ran together as "inoutSept keeps...". */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--k-2) var(--k-4);
  font-size: var(--k-label);
  color: var(--k-text-2);
}
.k .in-out-legend > span { display: inline-flex; align-items: center; gap: 6px; }
.k .key { display: inline-block; width: 9px; height: 9px; border-radius: 2px; flex: none; }
.k .key { border-radius: 2px; }
.k .key-in { background: var(--k-positive); }
.k .key-out { background: var(--k-negative); }

/* --- search and filters, one family --------------------------------- */
.k .hist-top { gap: var(--k-2); margin-bottom: var(--k-3); }

.k .hist-search {
  min-height: var(--k-ctl-md);
  border-radius: var(--k-r-md);
  border: 1px solid var(--k-border-subtle);
  background-color: var(--k-glass-1);
  background-image: var(--k-sheen);
  color: var(--k-text);
}
.k .hist-search::placeholder { color: var(--k-text-3); }
.k .hist-search:focus-visible {
  outline: 2px solid var(--k-accent);
  outline-offset: 1px;
  border-color: color-mix(in srgb, var(--k-accent) 60%, transparent);
  box-shadow: var(--k-glow-cyan);
}

.k .hist-select-btn {
  min-height: var(--k-ctl-md);
  border-radius: var(--k-r-pill);
  font-size: var(--k-label);
  font-weight: var(--k-w-fig);
}

.k .hist-chips { gap: var(--k-2); }

/* A select keeps every bit of its native behaviour and only changes its
   skin. The browser draws its own arrow, which is the one control in the
   app that never matches, so it is replaced with the app's own. */
.k select.hist-chip {
  -webkit-appearance: none;
  appearance: none;
  min-height: var(--k-ctl-md);
  padding: 0 calc(var(--k-5) + 0.7em) 0 var(--k-4);
  border-radius: var(--k-r-pill);
  border: 1px solid var(--k-border-subtle);
  background-color: var(--k-glass-1);
  background-image: var(--k-sheen),
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: 0 0, right calc(var(--k-4) + 0.3em) center, right var(--k-4) center;
  background-size: auto, 0.32em 0.32em, 0.32em 0.32em;
  background-repeat: no-repeat;
  color: var(--k-text-2);
  font-size: var(--k-label);
  font-weight: var(--k-w-label);
}
.k select.hist-chip:focus-visible {
  outline: 2px solid var(--k-accent);
  outline-offset: 1px;
  border-color: color-mix(in srgb, var(--k-accent) 60%, transparent);
  box-shadow: var(--k-glow-cyan);
}

/* The count of things needing a category is a warning, so it reads as one. */
.k .hist-needs {
  min-height: var(--k-ctl-sm);
  border-radius: var(--k-r-pill);
  background: color-mix(in srgb, var(--k-warning) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--k-warning) 32%, transparent);
  color: var(--k-warning);
  font-size: var(--k-label);
  font-weight: var(--k-w-label);
}

/* In daylight the warning colour on its own 12% wash lands at 4.05:1. The
   lightness comes down and the hue and chroma stay, so it still reads as the
   same amber - the same correction the delta pill needs, for the same
   reason. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .k .hist-needs {
    color: color-mix(in oklch, var(--k-warning) 68%, oklch(0% 0 0));
    color: oklch(from var(--k-warning) 38% c h);
  }
}
/* generated from the block above by tools/theme; do not edit by hand */
:root[data-theme="light"] .k .hist-needs {
    color: color-mix(in oklch, var(--k-warning) 68%, oklch(0% 0 0));
    color: oklch(from var(--k-warning) 38% c h);
  }

/* --- the day list --------------------------------------------------- */
/* A day is a heading and its rows. It was a bordered card, and a month is
   twenty of them, so the screen read as a column of boxes with the actual
   payments inside them. Nothing here is blurred: a scrolling list of
   backdrop-filtered rows costs real frames on a mid-range phone. */
.k .hist-day-card {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0 var(--k-1);
}

.k .hist-day-head {
  padding: var(--k-6) var(--k-1) var(--k-2);
  font-size: var(--k-caption);
  font-weight: var(--k-w-fig);
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-text-3);
}

/* The only line on the whole list, and it is the one doing work. */
.k .hist-row + .hist-row { border-top: 1px solid var(--k-hairline); }
.k .hist-row { padding: var(--k-3) 0; }
.k .hist-row:active { background: var(--k-surface-press); }

.k .hist-row.selected {
  background: color-mix(in srgb, var(--k-accent) 10%, transparent);
  border-radius: var(--k-r-sm);
}

/* Merchant strong, where it came from quiet, amount strong and coloured. */
.k .hist-name { font-size: var(--k-body); font-weight: var(--k-w-fig); color: var(--k-text); }
.k .hist-sub { font-size: var(--k-label); color: var(--k-text-3); }
.k .txn-amount {
  font-size: var(--k-value-sm);
  font-weight: var(--k-w-fig);
  font-variant-numeric: tabular-nums;
}
.k .txn-amount.in { color: var(--k-positive); }
.k .txn-amount.out { color: var(--k-negative); }

/* A category's colour belongs on its icon, not in a filled tile behind it. */
.k .hist-cat {
  width: 38px;
  height: 38px;
  border-radius: var(--k-r-sm);
  background: color-mix(in srgb, var(--chip-color, var(--k-accent)) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--chip-color, var(--k-accent)) 24%, transparent);
}

/* The day's own total, beside its date. */
.k .hist-day-head .in { color: var(--k-positive); }
.k .hist-day-head .out { color: var(--k-negative); }

/* ---------------------------------------------------------------------
   BRAND MARKS  ·  part of the system, not a migration
   Three sizes, one geometry. A monogram is not a placeholder for a missing
   logo: it is the answer for the shop that will never be in any icon set.
   --------------------------------------------------------------------- */
.k-brand {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: var(--k-r-sm);
  overflow: hidden;
  font-size: var(--k-icon-md);
}
/* brandMark() names every size it can emit, so every one has a rule here.
   md is the base size and adds nothing; it exists so the API never writes
   a class that does not resolve. */
.k-brand--md { }
.k-brand--sm { width: 30px; height: 30px; border-radius: 9px; font-size: var(--k-icon-sm); }
.k-brand--lg { width: 46px; height: 46px; border-radius: var(--k-r-md); font-size: var(--k-icon-lg); }

.k-brand img { width: 100%; height: 100%; object-fit: contain; }

/* A category's own colour, at the same strength as everywhere else. */
.k-brand--cat {
  background: color-mix(in srgb, var(--k-tint, var(--k-accent)) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--k-tint, var(--k-accent)) 24%, transparent);
  color: var(--k-tint, var(--k-accent));
}

/* The monogram. Hue comes from the merchant's own name, so a shop is the
   same colour on every screen forever; lightness and chroma are fixed, so no
   tile outshouts another. The letters sit at the weight of a figure, not of
   a label, which is what stops it reading as a fallback. */
.k-brand--mono {
  background: oklch(from oklch(70% 0.14 var(--k-hue, 206)) l c h / 0.14);
  border: 1px solid oklch(from oklch(70% 0.14 var(--k-hue, 206)) l c h / 0.28);
  color: oklch(80% 0.11 var(--k-hue, 206));
}
.k-brand__text {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-size: 0.78em;
  font-weight: var(--k-w-fig);
  letter-spacing: 0;
  line-height: 1;
  text-align: center;
  font-variant-numeric: tabular-nums;
  transform: translateY(-0.02em);
}
.k-brand__glyph {
  display: grid;
  place-items: center;
  width: 0.5em;
  height: 1em;
  flex: none;
}
.k-brand__glyph:only-child { width: 1em; }

/* Nothing known at all: a quiet tile rather than a hole in the row. */
.k-brand--none {
  background: color-mix(in srgb, var(--k-surface-elev) 55%, transparent);
  border: 1px solid var(--k-hairline);
}

/* Daylight. The monogram sets its own lightness from a hash rather than from
   a token, so it is the one thing in the system that does not follow the
   theme on its own. On paper its letters measured 1.57:1 - there, but not
   readable. The hue still comes from the name, so a shop keeps its identity
   in both themes; only the lightness changes, which is what a theme is. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .k-brand--mono {
    background: color-mix(in srgb, oklch(55% 0.14 var(--k-hue, 206)) 10%, transparent);
    border-color: color-mix(in srgb, oklch(55% 0.14 var(--k-hue, 206)) 26%, transparent);
    color: oklch(38% 0.12 var(--k-hue, 206));
  }
}
/* generated from the block above by tools/theme; do not edit by hand */
:root[data-theme="light"] .k-brand--mono {
    background: color-mix(in srgb, oklch(55% 0.14 var(--k-hue, 206)) 10%, transparent);
    border-color: color-mix(in srgb, oklch(55% 0.14 var(--k-hue, 206)) 26%, transparent);
    color: oklch(38% 0.12 var(--k-hue, 206));
  }

@supports not (color: oklch(from red l c h)) {
  /* Older engines without relative colour: the tint still varies by hue,
     just without the alpha derivation. */
  .k-brand--mono {
    background: color-mix(in srgb, oklch(70% 0.14 var(--k-hue, 206)) 14%, transparent);
    border-color: color-mix(in srgb, oklch(70% 0.14 var(--k-hue, 206)) 28%, transparent);
  }
}

/* ---------------------------------------------------------------------
   MIGRATION · Add  (phase 9C)
   --------------------------------------------------------------------- */

/* --- the bank SMS shortcut, first thing on the screen ---------------- */
.k .k-add-sms {
  display: flex;
  align-items: center;
  gap: var(--k-3);
  width: 100%;
  margin: var(--k-1) 0 var(--k-5);
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-color: color-mix(in srgb, var(--k-accent) 22%, transparent);
}
.k .k-add-sms:active { background-color: var(--k-surface-press); }
.k .k-add-sms__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.k .k-add-sms__go { color: var(--k-accent-text); font-size: var(--k-value); flex: none; }

/* --- the amount, still the answer this screen exists for ------------- */
.k .amount-hero { margin-bottom: var(--k-5); }
.k .amount-hero .field { margin: 0; position: relative; padding-bottom: var(--k-3); }
.k .amount-hero .amount-input-wrap {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  gap: var(--k-1);
  align-items: baseline;
}
/* The line that says where the caret is, since the box no longer does. */
.k .amount-hero .amount-input-wrap::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--k-border);
  transition: background var(--k-t-normal) var(--k-ease);
}
.k .amount-hero .amount-input-wrap:focus-within::after {
  background: var(--k-accent);
  box-shadow: 0 0 10px color-mix(in srgb, var(--k-accent) 45%, transparent);
}
.k .amount-hero .amount-prefix { font-size: var(--k-display); color: var(--k-text-2); font-weight: var(--k-w-fig); }
.k .amount-hero .amount-input {
  font-size: var(--k-hero);
  font-weight: var(--k-w-strong);
  line-height: var(--k-lh-tight);
  letter-spacing: var(--k-track-hero);
  padding: var(--k-2) 0 var(--k-1) !important;
}
.k .amount-hero .amount-input::placeholder { color: var(--k-text-3); opacity: 1; }

/* Spent or received: one track, one lit cell. */
.k .amount-hero .direction-toggle { margin: var(--k-4) 0 0; width: 100%; }
.k .amount-hero .k-seg__btn { flex: 1; min-height: var(--k-ctl-md); border: 0; }

/* --- fields ---------------------------------------------------------- */
.k .k-field { margin-bottom: var(--k-4); }
.k .k-field > .k-label { margin-bottom: var(--k-2); display: block; }

/* One row that says what is chosen, and opens the rest. */
.k .k-picker {
  display: flex;
  align-items: center;
  gap: var(--k-3);
  width: 100%;
  min-height: var(--k-ctl-lg);
  padding: 0 var(--k-4);
  border-radius: var(--k-r-md);
  border: 1px solid var(--k-border-subtle);
  background-color: var(--k-glass-1);
  background-image: var(--k-sheen);
  color: var(--k-text);
  font: inherit;
  font-size: var(--k-body);
  text-align: left;
  cursor: pointer;
  position: relative;
}
.k .k-picker:active { background-color: var(--k-surface-press); }
.k .k-picker__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.k .k-picker__mark { display: inline-flex; flex: none; }

/* The chevron, the same one the whole app uses. */
.k .k-picker::after {
  content: "";
  flex: none;
  width: 0.42em;
  height: 0.42em;
  margin-left: auto;
  border-right: 1.75px solid var(--k-text-2);
  border-bottom: 1.75px solid var(--k-text-2);
  transform: rotate(-45deg);
}

/* The account picker wraps a real select, so the select fills the row and
   the mark sits on top of it. Every native behaviour is kept. */
.k .k-picker--select { padding-right: 0; cursor: default; }
.k .k-picker--select::after { margin-right: var(--k-4); }
.k .k-picker--select .k-select {
  flex: 1;
  min-width: 0;
  min-height: var(--k-ctl-lg);
  border: 0;
  background: none;
  padding: 0;
  color: var(--k-text);
  font-size: var(--k-body);
  cursor: pointer;
}
.k .k-picker--select .k-select:focus-visible { outline: none; box-shadow: none; }
.k .k-picker--select:focus-within {
  border-color: color-mix(in srgb, var(--k-accent) 60%, transparent);
  box-shadow: var(--k-glow-cyan);
}

.k .field-date .k-input { min-height: var(--k-ctl-lg); }

/* --- the repeat switch ------------------------------------------------ */
.k .k-switch-row {
  display: flex;
  align-items: center;
  gap: var(--k-4);
  min-height: var(--k-tap);
  padding: var(--k-2) 0 var(--k-4);
}
.k .k-switch-row__text { flex: 1; font-size: var(--k-body); }
.k .k-switch-row__sub { display: block; font-size: var(--k-label); color: var(--k-text-3); margin-top: 2px; }
.k-vis-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* --- the things the app usually works out on its own ------------------ */
.k .k-add-more { border-top: 1px solid var(--k-hairline); margin-top: var(--k-2); }
.k .k-add-more > summary { color: var(--k-text-2); font-size: var(--k-label); }
.k .k-add-more__body { padding-bottom: var(--k-4); }
.k .k-add-more .field { margin: 0; }
.k .k-add-more .field > span { font-size: var(--k-label); color: var(--k-text-2); margin-bottom: var(--k-2); display: block; }
.k .k-add-more select {
  width: 100%;
  min-height: var(--k-ctl-md);
  border-radius: var(--k-r-md);
  border: 1px solid var(--k-border-subtle);
  background-color: var(--k-glass-1);
  color: var(--k-text);
}

.k .add-form .btn-primary { width: 100%; margin-top: var(--k-4); }

/* --- the category sheet ----------------------------------------------- */
.k #add-cat-sheet .k-scrim { z-index: 40; }
.k #add-cat-sheet .k-sheet { z-index: 41; max-height: 78vh; display: flex; flex-direction: column; }
.k .k-sheet__head {
  display: flex;
  align-items: center;
  gap: var(--k-3);
  padding-bottom: var(--k-3);
  border-bottom: 1px solid var(--k-hairline);
}
.k .k-sheet__title { font-size: var(--k-heading); font-weight: var(--k-w-strong); flex: 1; }
.k .k-sheet__close { min-height: var(--k-tap); padding: 0 var(--k-3); color: var(--k-accent-text); font-weight: var(--k-w-fig); }
.k .k-sheet__scroll { overflow-y: auto; -webkit-overflow-scrolling: touch; margin: 0 calc(var(--k-5) * -1); padding: 0 var(--k-5); }

/* A category is a row, not a chip: a name you read, at a size you can hit. */
.k .k-cat-row { min-height: 56px; border-radius: 0; }
.k .k-cat-row .k-row__title { font-weight: var(--k-w-label); }
.k .k-cat-row.active .k-row__title { font-weight: var(--k-w-fig); color: var(--k-text); }
.k .k-cat-row__tick { width: 18px; flex: none; }
.k .k-cat-row.active .k-cat-row__tick {
  border-right: 2px solid var(--k-accent);
  border-bottom: 2px solid var(--k-accent);
  width: 7px;
  height: 12px;
  margin-right: 6px;
  transform: rotate(45deg);
}
/* ======================================================================
   DESIGN LAB 2.0  ·  the evolution (phase 9D)

   Everything below is an addition to the system, not a replacement. No token
   above was renamed and no component above changed shape, because three
   screens are already built on them.

   What this section adds, and why each thing earns its place:

     MATERIAL LEVEL 0   the honest answer to "this does not need glass"
     EDITORIAL          a figure with a sentence around it, composed
     CONTEXT            the same truth, emphasised for the moment it is in
     CHARTS 2.0         four drawings, each answering one stated question
     STATES             what the app says when something worked or did not
     MOTION             the budget, expressed as usable classes

   Nothing here is used by any production screen yet. It is class-based
   throughout and introduces no element selectors, so loading this file
   cannot change Accounts, Plan or Coach while they wait their turn.
   ====================================================================== */

/* --- Material level 0 -------------------------------------------------
   The system has four glass levels. It needed a fifth thing: a surface that
   is not glass at all.

   Blur is the most expensive thing a phone does here, and a mid-range
   Android pays for every layer of it on every frame. A container that holds
   low-priority structure - a group of settings, a legend, a footnote - gains
   nothing from sampling the atmosphere behind it. So it does not.

   This is what stops "depth communicates hierarchy" from decaying into
   "everything is glass": the bottom of the hierarchy is opaque, and the
   difference is visible.

     L0  .k-pane--flat   solid, no blur        structure
     L1  .k-pane--quiet  10px blur             supporting containers
     L2  .k-pane         16px blur             content, the default
     L3  .k-pane--focus  22px blur             opened, chosen, pointed at
     L4  .k-hero         30px blur             one per screen, the answer
   --------------------------------------------------------------------- */

/* --- Editorial composition -------------------------------------------
   A figure on its own is a readout. A figure with a sentence built around
   it is a statement, and a person remembers a statement.

     You are spending less.
     18,420
     this month          -12.4% vs August

   The rules that keep this from becoming ornament: the sentence is short
   enough to read in one go, the figure stays the largest thing, and the
   tail line carries the comparison rather than repeating the figure. The
   lede is set at the heading size and a lighter weight than the figure, so
   it introduces without competing.
   --------------------------------------------------------------------- */

/* The emphasised clause in a lede. One per sentence, never two. */

/* The line under the figure: what period it covers, and what it is against.
   Baseline-aligned so the two read as one line rather than two stacked. */

/* A change against a previous period. The arrow is part of the text, so it
   survives being read aloud, and the colour is the money colour, never a
   decorative one. Down is not automatically good: a fall in income is not a
   win, so the direction class is set by the caller, never inferred here. */

/* --- Context: the same truth, emphasised for the moment ---------------
   "42,500 available" and "8,240 left for 6 days" are the same kind of fact.
   The second one is said differently because the month is nearly over, not
   because the arithmetic changed. That distinction is the whole component:
   EMPHASIS IS PRESENTATION. It never reaches back into the figure.

   Three tones, and they map to states the app can actually know:
     calm       nothing needs attention
     attention  a period is running out, or a limit is close
     alert      something is outside its usual range

   Tone sets one custom property and everything else follows, so no tone can
   drift into having its own layout.
   --------------------------------------------------------------------- */
.k-context {
  --k-tint: var(--k-accent);
  display: flex;
  gap: var(--k-3);
  align-items: flex-start;
  padding: var(--k-4);
  border-radius: var(--k-r-lg);
  background-color: var(--k-glass-2);
  background-image: var(--k-sheen);
  border: 1px solid color-mix(in srgb, var(--k-tint) 24%, transparent);
  box-shadow: var(--k-inner-top), var(--k-shadow-soft);
}
.k-context--calm { --k-tint: var(--k-positive); }
.k-context--attention { --k-tint: var(--k-warning); }
.k-context--alert { --k-tint: var(--k-negative); }

.k-context__mark {
  flex: none;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: var(--k-r-sm);
  background: color-mix(in srgb, var(--k-tint) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--k-tint) 26%, transparent);
  color: var(--k-tint);
  font-size: var(--k-icon-md);
}
.k-context__body { flex: 1; min-width: 0; }
.k-context__k {
  font-size: var(--k-caption);
  font-weight: var(--k-w-label);
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-tint);
}
/* The figure and the qualifier on one baseline: "8,240 left for 6 days".
   Keeping the qualifier out of the figure is what stops a person reading
   the number as something it is not. */

.k-context__note { margin: var(--k-2) 0 0; font-size: var(--k-label); color: var(--k-text-2); line-height: var(--k-lh-body); }

/* --- Charts 2.0 -------------------------------------------------------
   Four drawings. Each one exists because it answers a question a person
   actually asks, and the question is written next to it in the lab. A
   drawing that cannot state its question is decoration and is not built.

     RIVER    "is more coming in than going out, and how did that change?"
     RADIAL   "how much of the month is already committed?"
     PULSE    "when in the month do I spend?"
     SHARE    "where did it go, biggest first?"

   All four inherit the stroke family above: one weight, one cap, red kept
   for money that has actually gone.
   --------------------------------------------------------------------- */

/* Cash-flow river. Two lines, and the space between them shaded.
 *
 * The first version of this drew inflow and outflow as areas from a zero
 * baseline. It was wrong, and the lab showed it: a salary that never moves
 * and an outflow that swings by five thousand both became near-full slabs,
 * because the variation that matters is a tenth of the distance to zero.
 * The chart was honest and told you nothing.
 *
 * Two lines on a scale zoomed to the data fix it. The gap between them IS
 * the money kept, so the thing you are meant to read is the subject of the
 * picture rather than a third line competing with two others. Only the gap
 * is filled: filling down to a baseline the axis does not start at is the
 * lie this kind of chart usually tells.
 *
 * The axis is zoomed, so the lines are labelled with their own values
 * instead. On a phone, direct labels beat an axis nobody reads.
 */

/* Radial commitment meter. The figure sits in the hole, because the hole is
   the only place a ring leaves room for it. */

/* Spending pulse. One bar a day. Height is the amount; the lit bar is the
   day being pointed at. Bars keep a minimum height so a quiet day reads as
   "nearly nothing" rather than as missing data. */

/* Share. What replaced the bubble constellation: the same question, legible
   at 320px, and it stays legible with fourteen categories instead of seven.
   A bubble chart of category shares is a beautiful way to make a person
   squint at a small circle to find out whether it is bigger than another
   small circle. A ranked bar answers it at a glance. */

/* A legend is a label, not a chart. Kept small and never lit. */

/* --- States: what the app says when it worked, or did not -------------
   One shape for both, because they are the same event with different news,
   and a person should not have to learn two layouts to find out which.
   --------------------------------------------------------------------- */

/* Pull to refresh. The ring is the distance pulled, so it is feedback, not
   a spinner pretending the app is busy. */

/* --- Motion, as classes ----------------------------------------------
   The budget, stated once so nobody has to guess which duration to reach
   for. Every animation in the product is one of these three.

     FAST        --k-t-fast     140ms   a press, a toggle, a hover
     STANDARD    --k-t-normal   240ms   a sheet, a transition, a reveal
     EXPRESSIVE  --k-t-slow     420ms   something arriving
                 --k-t-draw     600ms   a chart, the ceiling

   Anything that would need longer is staggered, not stretched.
   --------------------------------------------------------------------- */

/* A figure changing to another figure. It moves a little and settles: the
   movement is what tells you it changed, since two numbers of the same size
   in the same place otherwise just swap without being noticed. */

/* A row arriving in a list it was not in a moment ago. It comes from the
   direction it came from - the top - and settles rather than bouncing. */

/* A meter or a bar filling toward its target, used by the radial and the
   share rows. Held here so a drawing cannot invent its own timing. */

/* The delta pill has to be corrected for daylight after it is defined,
   which is here rather than up with the other light-mode rules: a colour
   set by the later rule wins whatever the media query says. */

/* generated from the block above by tools/theme; do not edit by hand */

/* ---------------------------------------------------------------------
   MIGRATION · Accounts  (phase 9E)
   Scoped by `.k` on the Accounts container, exactly as the others are.

   The screen was a wall of boxes: a card per account, each with its own
   border, its own padding and its own shadow, so five accounts read as five
   separate objects rather than as one answer to "where is my money".

   It is now a list. One quiet surface per group, one row per account, and
   the balance is the biggest thing in the row.
   --------------------------------------------------------------------- */

/* --- the groups ------------------------------------------------------- */
.k .account-group-sec { margin-top: var(--k-6); }

/* A label, not a heading: it names the lane without competing with the
   figures inside it. */
.k .account-group-label {
  margin: 0 0 var(--k-2);
  padding: 0 var(--k-1);
  font-size: var(--k-caption);
  font-weight: var(--k-w-fig);
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-text-3);
}

/* One surface for the whole group. L1: a list is supporting structure, and
   does not need the blur a figure with something to say earns. */
.k .account-group { padding: 0 var(--k-4); }

.k .account-block + .account-block { border-top: 1px solid var(--k-hairline); }

/* --- the row ---------------------------------------------------------- */
.k .account-row {
  gap: var(--k-3);
  min-height: 64px;
  padding: var(--k-3) 0;
  width: 100%;
}
.k button.account-row { cursor: pointer; }
.k button.account-row:active { background: var(--k-surface-press); }

/* A long name ellipses. It used to be cut off mid-word, which reads as a
   different account rather than as a shortened one. */
.k .account-row .k-row__title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.k .account-row .k-row__meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The balance: the reason the screen was opened, so it is the largest thing
   in the row and it never wraps or shrinks to fit a name. */
.k .account-balance {
  flex: none;
  margin-left: auto;
  font-size: var(--k-value);
  font-weight: var(--k-w-fig);
  letter-spacing: var(--k-track-title);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.k .account-balance.out { color: var(--k-negative); }
.k .account-balance.in { color: var(--k-positive); }

/* The one chevron the product uses, turned down when the row is open. */
.k .account-row__chev {
  flex: none;
  width: 0.4em;
  height: 0.4em;
  margin-left: var(--k-1);
  border-right: 1.75px solid var(--k-text-3);
  border-bottom: 1.75px solid var(--k-text-3);
  transform: rotate(45deg) translate(-0.08em, -0.08em);
  transition: transform var(--k-t-normal) var(--k-ease), border-color var(--k-t-normal) var(--k-ease);
}
.k .account-open[aria-expanded="true"] .account-row__chev {
  border-color: var(--k-accent);
  transform: rotate(225deg) translate(-0.08em, -0.08em);
}

/* Rearranging: the arrows sit where the balance was. */
.k .account-row--move .account-move { display: flex; gap: var(--k-1); margin-left: auto; flex: none; }
.k .account-move .icon-btn {
  min-width: var(--k-tap);
  min-height: var(--k-tap);
  display: grid;
  place-items: center;
  border-radius: var(--k-r-sm);
  border: 1px solid var(--k-border-subtle);
  background: var(--k-glass-1);
  color: var(--k-text-2);
}
.k .account-move .icon-btn[disabled] { opacity: 0.35; }

/* --- what an account says about itself -------------------------------- */
/* A fact the account already knows, shown whether or not the row is open:
   a bill that has been raised and cannot be seen yet is not a detail. */
.k .account-note {
  margin: 0 0 var(--k-3);
  padding: var(--k-2) var(--k-3);
  border-radius: var(--k-r-sm);
  border: 1px solid color-mix(in srgb, var(--k-warning) 24%, transparent);
  background: color-mix(in srgb, var(--k-warning) 8%, transparent);
  font-size: var(--k-label);
  color: var(--k-text-2);
}

.k .account-detail { padding: 0 0 var(--k-4); }
.k .account-detail > :first-child { margin-top: 0; }

/* The latest payments: rows again, one level in, with no surface of their
   own. A list inside a list does not need a second box around it. */
/* Indented to sit under the account name, so the payments read as belonging
   to the row above rather than as more accounts. 50px is the brand mark plus
   its gap, which is where the name starts. */
.k .account-detail.account-recent { padding-left: 50px; }
.k .account-recent-rows { margin-bottom: var(--k-2); }
.k .account-recent-row .k-row__title { font-size: var(--k-label); }
.k .account-recent-row { min-height: 52px; }
.k .account-recent-row .k-row__title { font-weight: var(--k-w-label); }
.k .account-recent-row .k-row__value { font-size: var(--k-value-sm); margin-left: auto; flex: none; white-space: nowrap; }

/* --- the actions ------------------------------------------------------ */
/* Quiet on purpose. Edit and Add a spend are things you do occasionally;
   the balance is the thing you came for. */
.k .account-actions-inline {
  display: flex;
  gap: var(--k-2);
  flex-wrap: wrap;
  margin-top: var(--k-2);
}
.k .account-actions-inline .k-btn { min-height: var(--k-tap); padding: 0 var(--k-3); }

/* The screen's own actions, after the money rather than above it. */
.k .accounts-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k-2);
  margin: var(--k-8) 0 var(--k-4);
  padding-top: var(--k-5);
  border-top: 1px solid var(--k-hairline);
}
.k .accounts-actions .k-btn { flex: 1 1 auto; min-height: var(--k-ctl-md); }
.k .accounts-actions #add-account-btn { flex-basis: 100%; }
.k .accounts-actions .k-btn--ghost { flex: 1 1 0; justify-content: center; text-align: center; padding-inline: var(--k-2); }

/* --- the bits of the old screen that stay ----------------------------- */
.k .account-block .loan-lines,
.k .account-block .loan-line { font-size: var(--k-label); }
.k .account-block .loan-line { display: flex; justify-content: space-between; gap: var(--k-3); padding: var(--k-2) 0; }
.k .account-block .loan-line + .loan-line { border-top: 1px solid var(--k-hairline); }
.k .account-block .loan-line dd { margin: 0; font-variant-numeric: tabular-nums; }

.k .account-block .totals-row {
  display: flex;
  justify-content: space-between;
  gap: var(--k-3);
  padding: var(--k-2) 0;
  font-size: var(--k-label);
}
.k .account-block .totals-row + .totals-row { border-top: 1px solid var(--k-hairline); }

/* --- the account form ------------------------------------------------
   Two things here were already wrong before this screen was migrated, and
   both break a rule the system is meant to keep.

   The six account-type buttons shared a 282px row, which cannot hold six
   44px targets however they are divided. They wrap to a second line now
   rather than each being shaved to 37px.

   The delete button holds a whole sentence - "Delete this account and its
   83 transactions" - and was set to never wrap, so the end of it was cut
   off. A button that destroys data should be able to finish telling you
   what it will destroy. */
.k .af-type-group { flex-wrap: wrap; gap: var(--k-1); }
.k .af-type {
  flex: 1 0 auto;
  min-width: var(--k-tap);
  min-height: var(--k-tap);
}

.k .btn-tiny.danger {
  color: var(--k-negative);
  border-color: color-mix(in srgb, var(--k-negative) 45%, transparent);
  white-space: normal;
  height: auto;
  min-height: var(--k-tap);
  padding: var(--k-2) var(--k-3);
  line-height: var(--k-lh-snug);
}

/* The empty screen: nothing set up yet, so it is one sentence and one way on. */
.k .empty-state { text-align: center; padding: var(--k-10) var(--k-5); }
.k .empty-state-what { font-size: var(--k-heading); font-weight: var(--k-w-strong); margin: 0 0 var(--k-2); }
.k .empty-state-why { font-size: var(--k-label); color: var(--k-text-2); line-height: var(--k-lh-body); margin: 0 0 var(--k-5); }
/* ---------------------------------------------------------------------
   MIGRATION · Plan and Coach  (phase 9F)

   These two screens share several class names with Summary - .cat-chip,
   .breakdown-label, .fts-breakdown - so every rule that touches a shared
   name is scoped to `.k-plan` or `.k-coach` rather than to `.k`. Summary's
   composition is finished and must not move because Plan needed a row.

   Names that belong only to these screens (.budget-card, .seg-dot,
   .coach-q, .attention-row) are scoped to `.k` in the ordinary way.
   --------------------------------------------------------------------- */

/* --- shared: two figures side by side may stack ----------------------
   Summary puts "In bank" and "After salary and bills" on one nowrap row.
   At 320 the pair needs 273px in a 246px box, so the second amount was cut
   off. A money figure that is only partly on screen is worse than one on a
   line of its own, so at that width they stack. Nothing changes at 360 and
   above, where the pair already fits. --------------------------------- */
/* Only where it actually breaks. With nowrap the pair shrinks to fit down to
   about 360; below that it cannot shrink any further and the second amount
   is cut. Allowing the wrap at every width moved them onto two lines at 390
   as well, which is a change to a screen that is finished. */
@media (max-width: 340px) {
  .k .bank-figures { flex-wrap: wrap; }
}
/* Crore-sized amounts (Rs 1.2 crore in the bank, a bank short by as much) do not fit side by side at any phone width; wrapping only
   when the two cannot fit leaves every ordinary pair exactly where it was (checked on the year household at 390 and 320). */
.k .bank-figures { flex-wrap: wrap; row-gap: var(--k-2, 8px); }

/* --- shared: small controls keep a fingertip-sized target -------------
   Summary carries several controls that are 32 to 35px tall - dismiss an
   anomaly, mark a commitment paid, skip it, untag a match. They are small
   on purpose: they sit beside a figure and must not compete with it. Small
   to look at is fine; small to hit is not.

   The strip is invisible, adds nothing to the layout and changes nothing
   about how any of them appear. It is the same technique the toggle and the
   segmented control already use, said once for the rest of them.

   Width is left alone: every one of these already clears 44px across. Only
   the height was short. --------------------------------------------------- */
.k .btn-tiny,
.k .icon-btn {
  position: relative;
  /* The whole control lifts, not just the strip. A strip left on the parent
     stacking level was painted over by whatever came after it in the row,
     so the extra height existed but nothing could be tapped in it. */
  z-index: 1;
}

.k .btn-tiny::before,
.k .icon-btn::before {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: var(--k-tap);
  transform: translateY(-50%);
}

/* --- shared: the figures under a hero --------------------------------- */
.k .hero-figures {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k-2) var(--k-6);
  margin-top: var(--k-4);
  font-size: var(--k-label);
  font-weight: var(--k-w-fig);
  font-variant-numeric: tabular-nums;
}
.k .hero-figures .muted { font-weight: var(--k-w-body); color: var(--k-text-3); }

/* --- shared: a row of something needing attention --------------------- */
/* Used by Plan, Coach, Settings and Setup - never by Summary. */
.k .attention-row {
  display: flex;
  align-items: center;
  gap: var(--k-3);
  min-height: 56px;
  padding: var(--k-3) 0;
  font-size: var(--k-body);
}
.k .attention-row + .attention-row { border-top: 1px solid var(--k-hairline); }
.k .attention-row .muted-note { font-size: var(--k-label); color: var(--k-text-3); }
.k .attention-actions { display: flex; gap: var(--k-2); margin-left: auto; flex: none; }

/* ======================================================================
   PLAN
   ====================================================================== */

/* --- where the budget comes from -------------------------------------- */
/* The sums used to live inside the hero, which made the most important
   thing on the screen also the longest thing on it. They are their own
   section now, directly under the figure they explain. */
.k-plan .plan-sums { margin: 0 0 var(--k-6); padding: var(--k-4) var(--k-5) var(--k-5); }
.k-plan .plan-sums__head {
  margin: 0 0 var(--k-1);
  font-size: var(--k-caption);
  font-weight: var(--k-w-fig);
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-text-3);
}
.k-plan .plan-sums .totals-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--k-3);
  padding: var(--k-3) 0;
  font-size: var(--k-body);
}
.k-plan .plan-sums .totals-row + .totals-row { border-top: 1px solid var(--k-hairline); }
.k-plan .plan-sums .totals-row span:last-child {
  font-weight: var(--k-w-fig);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.k-plan .plan-sums .in { color: var(--k-positive); }
.k-plan .plan-sums .out { color: var(--k-negative); }
.k-plan .saved-row { color: var(--k-text-2); }

/* The dots that tie a line to its slice of the bar in the hero. */
.k-plan .seg-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 7px;
  vertical-align: middle;
  background: var(--k-text-3);
}
.k-plan .seg-free { background: var(--k-positive); }
.k-plan .seg-must { background: var(--k-accent); }
.k-plan .seg-flex { background: var(--k-violet); }

/* Changing the figures: a disclosure, not a form sitting open on a screen
   that is meant to be read. */
.k-plan .plan-amounts { margin-top: var(--k-2); border-top: 1px solid var(--k-hairline); }
.k-plan .plan-amounts > summary { color: var(--k-text-2); font-size: var(--k-label); }
.k-plan .plan-amounts .field { margin-top: var(--k-3); }

/* A bare date or month input has no height of its own - the browser sizes it
   to its text, which came out 21px. Every other field on this screen is a
   control; this one has to be too. */
.k-plan .ff-end,
.k-plan input[type="month"],
.k-plan input[type="date"] {
  min-height: var(--k-ctl-md);
  width: 100%;
}

/* --- a commitment ------------------------------------------------------ */
.k-plan .plan-row { gap: var(--k-3); min-height: 62px; }
/* The name never wraps: a two-line label pushed the amount into the middle
   of the row and left it looking like part of the name. */
.k-plan .plan-row .k-row__title,
.k-plan .plan-row .k-row__meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.k-plan .plan-row__amount {
  flex: none;
  margin-left: auto;
  font-size: var(--k-value-sm);
  font-weight: var(--k-w-fig);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--k-negative);
}
.k-plan .plan-row__amount .freq-per-month { font-size: var(--k-caption); color: var(--k-text-3); font-weight: var(--k-w-body); }
.k-plan .plan-row__actions { display: flex; gap: 2px; flex: none; }

/* The row and its remove button sit side by side: a row cannot hold a button
   inside a button, and removing something must never be a thing you do by
   tapping the line it is on. */
.k-plan .plan-row-wrap { display: flex; align-items: stretch; gap: var(--k-1); }
.k-plan .plan-row-wrap + .plan-row-wrap,
.k-plan .plan-row-wrap + .k-row,
.k-plan .k-row + .plan-row-wrap { border-top: 1px solid var(--k-hairline); }
.k-plan .plan-row__main { flex: 1; min-width: 0; cursor: pointer; }
.k-plan .plan-row__main:active { background: var(--k-surface-press); }
.k-plan .plan-row__remove {
  position: relative;
  flex: none;
  align-self: center;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  background: none;
  color: var(--k-text-3);
  border-radius: var(--k-r-xs);
}
.k-plan .plan-row__remove::before {
  content: "";
  position: absolute;
  inset: 50% 50% auto auto;
  width: var(--k-tap);
  height: var(--k-tap);
  transform: translate(50%, -50%);
}
.k-plan .plan-row__remove:active { background: var(--k-surface-press); }

/* A glyph may be small; its target may not. The strip is invisible and adds
   nothing to the layout, exactly as the toggle's does. */
.k-plan .plan-row__actions .icon-btn {
  position: relative;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  background: none;
  color: var(--k-text-3);
  border-radius: var(--k-r-xs);
}
.k-plan .plan-row__actions .icon-btn::before {
  content: "";
  position: absolute;
  inset: 50% 50% auto auto;
  width: var(--k-tap);
  height: var(--k-tap);
  transform: translate(50%, -50%);
}
.k-plan .plan-row__actions .icon-btn:active { background: var(--k-surface-press); }
.k-plan .plan-row__actions .icon-btn[disabled] { opacity: 0.32; }

/* --- a category budget -------------------------------------------------- */
.k-plan .budget-card { padding: var(--k-2) 0 var(--k-4); }
.k-plan .budget-card + .budget-card { border-top: 1px solid var(--k-hairline); }
.k-plan .budget-row { min-height: 56px; }
.k-plan .budget-nums { flex: none; margin-left: auto; font-size: var(--k-value-sm); font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; white-space: nowrap; }
.k-plan .budget-nums .muted { color: var(--k-text-3); font-weight: var(--k-w-body); }
.k-plan .budget-meter { margin-top: var(--k-1); }
/* Over budget is the one state that changes the bar's colour, because it is
   the one state that is about money already gone. */
.k-plan .budget-fill.over { background: var(--k-negative); box-shadow: none; }
.k-plan .budget-fill.close { background: var(--k-warning); box-shadow: none; }

/* --- goals -------------------------------------------------------------- */
.k-plan .goal-card {
  display: flex;
  align-items: center;
  gap: var(--k-4);
  padding: var(--k-4) 0;
}
.k-plan .goal-card + .goal-card { border-top: 1px solid var(--k-hairline); }
.k-plan .goal-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.k-plan .goal-name { font-size: var(--k-body); font-weight: var(--k-w-fig); }
.k-plan .goal-text .muted-note { font-size: var(--k-label); color: var(--k-text-3); }

/* --- the costs people usually have ------------------------------------- */
.k-plan .common-costs { display: flex; flex-wrap: wrap; gap: var(--k-2); margin-top: var(--k-3); }

/* ======================================================================
   COACH
   The calmest screen in the product. It was already composed well, so this
   changes its material and its type and leaves its shape alone.
   ====================================================================== */

.k-coach .coach-questions { display: flex; flex-direction: column; gap: var(--k-2); margin-bottom: var(--k-4); }

/* A question is a row with an answer behind it. */
.k-coach .coach-q {
  gap: var(--k-3);
  min-height: var(--k-ctl-lg);
  padding: var(--k-3) var(--k-4);
  border: 1px solid var(--k-border-subtle);
  border-radius: var(--k-r-md);
  background-color: var(--k-glass-1);
  background-image: var(--k-sheen);
  color: var(--k-text);
  text-align: left;
  transition: border-color var(--k-t-fast) var(--k-ease), background-color var(--k-t-fast) var(--k-ease);
}
.k-coach .coach-q:active { background-color: var(--k-surface-press); }
.k-coach .coach-q.active {
  border-color: color-mix(in srgb, var(--k-accent) 55%, transparent);
  background-color: var(--k-glass-3);
}
.k-coach .coach-q .k-row__title { font-weight: var(--k-w-label); }
.k-coach .coach-q.active .k-row__title { font-weight: var(--k-w-fig); }

.k-coach .coach-q__chev {
  flex: none;
  width: 0.4em;
  height: 0.4em;
  margin-left: auto;
  border-right: 1.75px solid var(--k-text-3);
  border-bottom: 1.75px solid var(--k-text-3);
  transform: rotate(45deg) translate(-0.08em, -0.08em);
  transition: transform var(--k-t-normal) var(--k-ease), border-color var(--k-t-normal) var(--k-ease);
}
.k-coach .coach-q.active .coach-q__chev {
  border-color: var(--k-accent);
  transform: rotate(225deg) translate(-0.08em, -0.08em);
}

/* The answer. One surface, one level up from the question that opened it. */
.k-coach .coach-panel {
  padding: var(--k-5);
  margin-bottom: var(--k-5);
  border-radius: var(--k-r-lg);
  border: 1px solid var(--k-hairline);
  background-color: var(--k-glass-2);
  background-image: var(--k-sheen);
  box-shadow: var(--k-inner-top);
  animation: k-rise var(--k-t-normal) var(--k-ease);
}
.k-coach .coach-panel .field { margin-bottom: var(--k-4); }
.k-coach .coach-panel .amount-input-wrap {
  display: flex;
  align-items: baseline;
  gap: var(--k-1);
  padding: var(--k-2) var(--k-4);
  border-radius: var(--k-r-md);
  border: 1px solid var(--k-border-subtle);
  background-color: var(--k-glass-1);
}
.k-coach .coach-panel .amount-input-wrap:focus-within {
  border-color: color-mix(in srgb, var(--k-accent) 60%, transparent);
  box-shadow: var(--k-glow-cyan);
}
.k-coach .coach-panel .amount-prefix { font-size: var(--k-value); color: var(--k-text-2); font-weight: var(--k-w-fig); }
.k-coach .coach-panel .amount-input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--k-text);
  font-family: inherit;
  font-size: var(--k-display);
  font-weight: var(--k-w-strong);
  letter-spacing: var(--k-track-display);
  padding: var(--k-1) 0;
}
.k-coach .coach-panel .amount-input::placeholder { color: var(--k-text-3); opacity: 1; }

/* What the app noticed. The tone is the planner's; the shape is the
   system's context block, so a thing noticed here looks like a thing
   noticed anywhere else. */
.k-coach .coach-note { margin-bottom: var(--k-3); }
.k-coach .coach-note .k-context__k { text-transform: none; letter-spacing: normal; font-size: var(--k-body); font-weight: var(--k-w-fig); color: var(--k-text); }
.k-coach .coach-note-info { --k-tint: var(--k-accent); }
/* ---------------------------------------------------------------------
   PHASE 12 · the Design Lab drawings, in production
   --------------------------------------------------------------------- */

/* --- a total split into parts ---------------------------------------- */
.k .alloc { position: relative; display: flex; flex-direction: column; align-items: center; margin-top: var(--k-4); }
.k .alloc-ring { display: block; }
.k .alloc-centre { position: absolute; top: 0; left: 0; right: 0; height: 132px; display: grid; place-items: center; pointer-events: none; }
.k .alloc-centre-v { font-size: var(--k-value); font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; }
.k .alloc-legend { width: 100%; margin-top: var(--k-4); display: flex; flex-direction: column; gap: var(--k-2); }
.k .alloc-item { display: flex; align-items: baseline; gap: var(--k-2); font-size: var(--k-label); }
.k .alloc-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.k .alloc-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--k-text-2); }
.k .alloc-val { flex: none; font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* --- how much is already spoken for ----------------------------------- */
.k .meter-radial { position: relative; display: grid; place-items: center; margin: var(--k-3) auto 0; width: 150px; }
.k .meter-radial svg { display: block; }
.k .meter-radial-mid { position: absolute; display: flex; flex-direction: column; align-items: center; gap: 1px; pointer-events: none; }
.k .meter-radial-v { font-size: var(--k-display); font-weight: var(--k-w-strong); letter-spacing: var(--k-track-display); line-height: 1; font-variant-numeric: tabular-nums; }
.k .meter-radial-v.over { color: var(--k-negative); }
.k .meter-radial-k { font-size: var(--k-caption); color: var(--k-text-3); }
.k .meter-radial-legend { display: flex; justify-content: space-between; gap: var(--k-3); margin-top: var(--k-4); font-size: var(--k-label); font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; }
.k .meter-radial-legend .muted { font-weight: var(--k-w-body); color: var(--k-text-3); }

/* --- when the money goes ---------------------------------------------- */
.k .pulse { display: flex; align-items: flex-end; gap: 2px; height: 76px; margin-top: var(--k-2); }

/* --- money in against money out --------------------------------------- */
.k .river-legend { display: flex; flex-wrap: wrap; gap: var(--k-2) var(--k-4); margin-top: var(--k-2); font-size: var(--k-caption); color: var(--k-text-2); }
.k .river-legend span { display: inline-flex; align-items: center; gap: 6px; }
.k .river-dot { display: block; width: 8px; height: 8px; border-radius: 50%; flex: none; }
.k .river-band { display: block; width: 16px; height: 9px; border-radius: 2px; flex: none; background: color-mix(in srgb, var(--k-positive) 16%, transparent); }

/* --- the blocks these sit in ------------------------------------------ */
.k .summary-viz {
  margin-top: var(--k-4);
  padding: var(--k-5);
  border-radius: var(--k-r-lg);
  border: 1px solid var(--k-hairline);
  background-color: var(--k-glass-1);
  background-image: var(--k-sheen);
  box-shadow: var(--k-inner-top);
}
.k .summary-viz__head {
  margin: 0 0 var(--k-2);
  font-size: var(--k-caption);
  font-weight: var(--k-w-fig);
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-text-3);
}
.k .summary-insight { margin-top: var(--k-4); }

/* --- Accounts: the controls, now at the top --------------------------- */
.k .accounts-actions--top { margin: var(--k-1) 0 var(--k-5); padding-top: 0; border-top: 0; }

/* Every account row lines up on the same grid, whatever type it is: the
   mark, then the name and its line, then the figure hard right. */
.k .account-row .k-icon,
.k .account-row .k-brand { flex: none; align-self: center; }
.k .account-row .k-row__body { align-self: center; }

/* The note an account makes about itself is part of the same block, so it
   starts where the name starts rather than at the card edge. */
.k .account-note { margin-left: 50px; }

/* --- History: closer together, still easy to hit ---------------------- */
.k .hist-day .k-row,
.k .hist-row { min-height: 52px; padding-top: var(--k-2); padding-bottom: var(--k-2); }

/* --- "How it's worked out" was touching the card edges ---------------- */
.k .hero-work { margin-top: var(--k-3); }
.k .hero-work > .totals-card { padding: var(--k-4) var(--k-5); }
.k .hero-work .totals-row { gap: var(--k-5); }
.k .hero-work .totals-row > span:first-child { flex: 1 1 0; min-width: 0; overflow-wrap: anywhere; }
.k .hero-work .totals-row > span:last-child { flex: 0 0 auto; margin-left: var(--k-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.k .summary-spending-split { display: flex; flex-wrap: wrap; gap: var(--k-2) var(--k-5); margin: var(--k-3) var(--k-4) 0; color: var(--k-text-3); font-size: var(--k-caption); }
.k .summary-spending-split strong { margin-left: var(--k-1); color: var(--k-text); font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; }

/* A section header and its count/chevron on one baseline, off the edges. */
.k .section-fold > summary { padding: var(--k-3) var(--k-1); gap: var(--k-3); }
.k .section-fold > summary .summary-sub { margin-left: auto; color: var(--k-text-3); font-variant-numeric: tabular-nums; }

/* --- Import: an entry the statement did not show ---------------------- */
.k .unmatched-row { display: flex; align-items: center; gap: var(--k-3); flex-wrap: wrap; padding: var(--k-3) 0; }
.k .unmatched-row + .unmatched-row { border-top: 1px solid var(--k-hairline); }
.k .unmatched-what { flex: 1; min-width: 0; }
.k .unmatched-when { font-size: var(--k-caption); }
.k .unmatched-actions { flex: none; margin-left: auto; }
.k .unmatched-actions .btn-tiny { min-height: var(--k-tap); padding: 0 var(--k-3); border-radius: var(--k-r-pill); }
.k .unmatched-row--moved { opacity: 0.62; }

/* --- Plan: the meter, and one clear action ---------------------------- */
.k-plan .plan-meter { margin: var(--k-4) 0 var(--k-2); padding: var(--k-5); }
.k-plan .plan-common { margin-top: var(--k-3); border-top: 1px solid var(--k-hairline); }
.k-plan .plan-common > summary { color: var(--k-text-2); font-size: var(--k-label); }
.k-plan #plan-add-btn { width: 100%; min-height: var(--k-ctl-lg); }

/* --- Accounts: everything under a row lines up with its name ---------- */
/* The mark is 38 wide with a 12 gap, so the name starts 50 in. Anything
   belonging to that account - its detail, its Edit, its notes - starts
   there too. They were sitting at the card edge, which read as a second
   column that did not line up with anything. */
.k .account-detail { padding-left: 50px; }
.k .account-detail.account-recent { padding-left: 50px; }

/* The line under an account name explains it, so it is allowed a second
   line. Cutting "same as your passbook" to "same as your pass..." saved a
   few pixels and lost the sentence. */
.k .account-row .k-row__meta {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: var(--k-lh-snug);
}
.k .account-row { min-height: 66px; }

@media (max-width: 340px) {
  /* At the narrowest width the indent costs more than the alignment gains. */
  .k .account-detail, .k .account-detail.account-recent { padding-left: var(--k-3); }
}

/* --- Kawach's own artwork on an empty screen -------------------------- */
.k .empty-state-art { display: block; margin: 0 auto var(--k-4); color: var(--k-accent-text); opacity: .85; }
.k .river-fold { margin-top: var(--k-3); }
.k .river-fold > summary { color: var(--k-text-2); font-size: var(--k-label); }

/* Form controls, scrollbars and the like follow the chosen daylight too,
   otherwise a forced-light app still draws a dark dropdown. */
:root { color-scheme: dark; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) { color-scheme: light; }
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

/* A balance the person has asked to keep off the glass. Same width as the
   figure it stands in for, so nothing shifts when it is uncovered. */
.amount-covered { letter-spacing: 0.12em; color: var(--k-text-3); font-variant-numeric: tabular-nums; }

/* --- Text size and spacing -----------------------------------------
   Type is in rem everywhere, so one font-size on :root carries every
   size in both stylesheets with it. The percentages are modest on purpose:
   at 125% a ten-digit rupee figure still has to fit a 320px screen.

   Spacing is restated rather than scaled, because the DNA holds it in
   pixels. --k-tap and --k-1 are the same at every setting: a tighter screen
   must not become a harder one to hit.
*/
:root[data-text="large"] { font-size: 112.5%; }
:root[data-text="largest"] { font-size: 125%; }

:root[data-density="compact"] {
  --k-1: 4px;
  --k-2: 6px;
  --k-3: 9px;
  --k-4: 12px;
  --k-5: 15px;
  --k-6: 18px;
  --k-8: 24px;
  --k-10: 30px;
  --k-12: 36px;
  --k-16: 48px;
}

/* Where this month's spending was paid from, as one strip rather than two
   drawings. It is deliberately thin and unlabelled: the burn line above
   answers "am I ahead or behind", and a second chart with an axis would
   argue with it. */
.k .split-bar { flex: 1 0 100%; display: flex; height: 6px; border-radius: var(--k-r-pill); overflow: hidden; background: color-mix(in srgb, var(--k-text-3) 26%, transparent); margin-bottom: var(--k-1); }
.k .split-bar__card { background: var(--k-accent); }
.k .split-k { display: inline-flex; align-items: center; gap: var(--k-1); }
.k .split-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.k .split-dot--card { background: var(--k-accent); }
.k .split-dot--bank { background: color-mix(in srgb, var(--k-text-3) 46%, transparent); }
/* One figure and its total on a line, with the word under it like every
   other stat on this screen. */

/* The same payment written down twice. The two rows are shown as one group
   so the pair reads as a pair, and the amount they share sits above them
   because the matching amount is the reason they are here. */
.k .dupe-note { margin: 0 0 var(--k-4); }
.k .dupe-pair { padding: var(--k-3) 0; border-top: 1px solid var(--k-hairline); }
.k .dupe-pair:first-of-type { border-top: 0; padding-top: 0; }
.k .dupe-amount { display: block; font-weight: var(--k-w-fig); color: var(--k-text); font-variant-numeric: tabular-nums; margin-bottom: var(--k-2); }
.k .dupe-row { padding: var(--k-2) 0; }
.k .dupe-keep, .k .dupe-see { margin-top: var(--k-2); }
.k .dupe-see { margin-right: var(--k-2); }

/* Marks the pair that is actually costing something: both were typed in, so
   both are already coming out of the budget. */
.k .dupe-flag { font-size: var(--k-caption); font-weight: 400; letter-spacing: var(--k-track-caption); text-transform: uppercase; color: var(--k-warning); margin-left: var(--k-2); }

/* --- Reimbursable, card bills and what is owed (4.16) ------------------
   Every value is a token; nothing here is a raw colour or size. */

/* A card's bill is one line: when it is due on the left, the exact amount on
   the right. It wraps only if a very narrow screen forces it to. */
.k .bill-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--k-1) var(--k-3);
  padding: var(--k-2) 0 0;
  font-size: var(--k-label);
}
.k .bill-when { flex: 1 1 auto; min-width: 0; color: var(--k-text-2); }
.k .bill-when.bill-urgent { color: var(--k-warning); font-weight: var(--k-w-fig); }
.k .bill-when.bill-overdue { color: var(--k-negative); font-weight: var(--k-w-fig); }
.k .bill-amount { flex: none; font-size: var(--k-value-sm); font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; white-space: nowrap; }
.k .bill-amount.in { color: var(--k-positive); }

/* "Mark bill paid": a link, right-aligned, still a 44px target. */
.k .bill-actions { display: flex; justify-content: flex-end; }
.k .bill-actions .link-btn {
  min-height: var(--k-tap);
  margin: 0;
  padding: 0 var(--k-1);
  color: var(--k-accent-text);
  font-size: var(--k-label);
}

/* The panel behind it: no pane of its own (a pane inside a pane stacks the
   glass), just a hairline and room. */
.k .bill-pay { padding: var(--k-3) 0 var(--k-2); border-top: 1px solid var(--k-hairline); }
.k .bill-pay .k-field { margin-bottom: var(--k-3); }
.k .bill-pay textarea.k-input { min-height: 72px; padding: var(--k-3) var(--k-4); resize: vertical; line-height: 1.4; }
.k .bill-pay-note { margin: 0 0 var(--k-3); font-size: var(--k-label); color: var(--k-warning); }
.k .bill-pay-note:empty { display: none; }
.k .bill-pay .k-btn { width: 100%; }

/* Summary: the two owed figures, in the row of supporting numbers. */
.k .summary-owed { display: flex; flex-wrap: wrap; gap: var(--k-3) var(--k-8); }

/* History: a small tag on a payment still to be claimed from an employer, and
   on the money that settled one. Quiet - it sits in the line that already
   says which account it was. */
.k .hist-tag {
  display: inline-block;
  margin-left: var(--k-1);
  padding: 0 var(--k-2);
  border: 1px solid color-mix(in srgb, var(--k-text-3) 45%, transparent);
  border-radius: var(--k-r-pill);
  font-size: var(--k-caption);
  line-height: 1.5;
  letter-spacing: var(--k-track-caption);
  text-transform: uppercase;
  color: var(--k-text-2);
  white-space: nowrap;
}
.k .hist-tag--in { border-color: color-mix(in srgb, var(--k-positive) 50%, transparent); color: var(--k-positive); }

/* With a tag on the line, the words and the tag sit side by side: the words
   give way (and are cut with an ellipsis), the tag never does. */
.k .hist-sub:has(.hist-tag) { display: flex; align-items: center; gap: var(--k-1); }
.k .hist-sub-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.k .hist-sub:has(.hist-tag) .hist-tag { flex: none; margin-left: 0; }

/* The work-cost checkbox in a payment's Edit panel. */
.k .hist-flag {
  display: flex;
  align-items: center;
  gap: var(--k-3);
  min-height: var(--k-tap);
  font-size: var(--k-label);
  color: var(--k-text-2);
}
.k .hist-flag input { width: 22px; height: 22px; margin: 0; flex: none; accent-color: var(--k-accent); }

/* --- Month bar on Summary (4.16) --------------------------------------
   The History month bar again, so it is already familiar. High contrast:
   the arrows are full ink, not the muted grey History uses, because here
   they are the way back to what was spent yesterday. */
.k .summary-month { margin: var(--k-1) 0 var(--k-2); }

/* A switch that is not available yet (the next-month one, until a
   commitment is chosen). */
.k .k-toggle:disabled { opacity: 0.4; cursor: not-allowed; }

/* The Time box in a payment's Edit panel: the label on the left, the
   control taking the rest of the line. */

/* The bank card's second figure (what it would read if the work costs are paid
   back) and the line for a late refund; and the note under "Owed back by
   employer". Quiet: the cautious figure above them stays the loud one. */
.k .bank-refund {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--k-3);
  margin: var(--k-3) 0 0;
  font-size: var(--k-label);
}
.k .bank-refund span:last-child { font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; white-space: nowrap; }
.k .bank-late { margin: var(--k-2) 0 0; color: var(--k-warning); }

/* ---- Summary: the ring, and one card of rows (4.22) ----------------------
 * The ring is the Summary's headline: a thick arc for the share of the budget
 * spent, a thin violet one for the share of the month gone. The arc is green, then
 * amber from 75% of the budget spent, red from 90%: about the budget only. It draws itself once as the screen
 * arrives (.is-arriving, set by countUpHeroes in js/ui.js) and then sits
 * still; a screen redrawing itself never replays it. */
.k .hero--ring { text-align: center; }
.k .hero--ring .hero-top { text-align: left; }
.k .hero-ring { position: relative; width: min(256px, 70vw); aspect-ratio: 1; margin: var(--k-3) auto var(--k-1); }
.k .hero-ring svg { display: block; width: 100%; height: 100%; overflow: visible; }
.k .hero-ring circle { fill: none; }
.k .hero-ring__track { stroke: var(--k-surface-elev); stroke-width: 14; }
.k .hero-ring__track--days { stroke: color-mix(in srgb, var(--k-text) 7%, transparent); stroke-width: 5; }
.k .hero-ring__spent { stroke: var(--k-positive); stroke-width: 14; stroke-linecap: round; filter: drop-shadow(0 0 6px color-mix(in srgb, var(--k-positive) 50%, transparent)); }
.k .hero-ring--warn .hero-ring__spent { stroke: var(--k-warning); filter: drop-shadow(0 0 6px color-mix(in srgb, var(--k-warning) 50%, transparent)); }
.k .hero-ring--over .hero-ring__spent { stroke: var(--k-negative); filter: drop-shadow(0 0 6px color-mix(in srgb, var(--k-negative) 50%, transparent)); }
.k .hero-ring__days { stroke: var(--k-violet); stroke-width: 5; stroke-linecap: round; }
.k .hero-ring__mid { position: absolute; inset: 0; display: grid; place-content: center; }
.k .hero--ring .hero-amount { margin: 0; font-size: calc(min(256px, 70vw) * 0.165); }
.k .hero--ring .hero-amount--long { font-size: calc(min(256px, 70vw) * 0.13); }
.k .hero-ring__of { margin: var(--k-1) 0 0; font-size: var(--k-caption); color: var(--k-text-2); }
.k .hero--ring .hero-status { margin-top: var(--k-2); }
.k .hero-ring__key { display: flex; justify-content: center; gap: var(--k-5); margin: var(--k-3) 0 0; font-size: var(--k-caption); color: var(--k-text-3); }
.k .hero-ring__key span::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 6px; border-radius: 50%; background: var(--c); }
.k .hero-ring__key-spent { --c: var(--k-positive); }
.k .hero-ring--warn .hero-ring__key-spent { --c: var(--k-warning); }
.k .hero-ring--over .hero-ring__key-spent { --c: var(--k-negative); }
.k .hero-ring__key-days { --c: var(--k-violet); }
.is-arriving .hero-ring__spent { animation: hero-ring-in 900ms var(--k-ease) 80ms both; }
.is-arriving .hero-ring__days { animation: hero-ring-in 900ms var(--k-ease) 200ms both; }
@keyframes hero-ring-in { from { stroke-dasharray: 0 100; } }

/* The figures under it: one card, one figure a row (no side-by-side cards). */
.k .summary-rows { margin: var(--k-4) 0 0; padding: 0 var(--k-5); border-radius: var(--k-r-lg); background: var(--k-surface); }
.k .summary-owed { display: contents; }
.k .summary-row { display: flex; align-items: center; gap: var(--k-3); width: 100%; padding: var(--k-4) 0; border: 0; border-top: 1px solid var(--k-hairline); background: none; color: inherit; font: inherit; text-align: left; }
.k .summary-rows > :first-child,
.k .summary-rows > :first-child > .summary-row:first-child { border-top: 0; }
.k .summary-row__k { flex: 1; min-width: 0; display: grid; gap: 2px; font-weight: 600; }
.k .summary-row__k small { font-size: var(--k-caption); font-weight: 400; color: var(--k-text-3); }
.k .summary-row__k .summary-row__late { color: var(--k-warning); }
.k .summary-row__v { font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.k .summary-row__v--cards { color: var(--k-accent-text); }
.k .summary-row__v--back { color: var(--k-positive); }
.k .summary-row--tap { cursor: pointer; }
.k .summary-row--tap:active { background: var(--k-surface-press); }
.k .summary-spark { flex: none; width: 64px; height: 24px; }
.k .summary-spark polyline { fill: none; stroke: var(--k-positive); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.is-arriving .summary-row { animation: summary-rise 480ms var(--k-ease) 160ms both; }
.is-arriving .summary-owed .summary-row { animation-delay: 230ms; }
.is-arriving .summary-owed .summary-row + .summary-row { animation-delay: 300ms; }
@keyframes summary-rise { from { opacity: 0; transform: translateY(10px); } }

/* ---- Add: the work-cost switch, Save, and a pasted SMS filling in (4.23) --
 * A work cost switched on gets a green edge, the colour of money coming back.
 * Save turns green with a tick and one soft ring for a moment. A message just
 * pasted into the SMS inbox lights its fields one after another. */
.k .k-switch-row:has(#add-reimb:checked),
.k .k-switch-row:has(#add-settle:checked) {
  margin: 0 calc(-1 * var(--k-3));
  padding: var(--k-3);
  border-radius: var(--k-r-md);
  box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--k-positive) 70%, transparent), 0 0 18px color-mix(in srgb, var(--k-positive) 22%, transparent);
  transition: box-shadow var(--k-t-normal) var(--k-ease);
}
.k .k-switch-row:has(#add-reimb:checked) .k-toggle,
.k .k-switch-row:has(#add-settle:checked) .k-toggle { background: color-mix(in srgb, var(--k-positive) 45%, transparent); box-shadow: none; }
.k .k-switch-row:has(#add-reimb:checked) .k-toggle::after,
.k .k-switch-row:has(#add-settle:checked) .k-toggle::after { background: var(--k-positive); }
.k .add-form .btn-primary { position: relative; transition: background var(--k-t-normal) var(--k-ease); }
.k .add-form .btn-primary.is-saved { background: var(--k-positive); box-shadow: 0 0 22px color-mix(in srgb, var(--k-positive) 45%, transparent); display: inline-flex; align-items: center; justify-content: center; gap: var(--k-2); }
.k .add-form .btn-primary.is-saved .icon { width: 20px; height: 20px; }
.k .add-form .btn-primary.is-saved::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 0 2px var(--k-positive);
  animation: saved-ring 800ms var(--k-ease) forwards;
}
@keyframes saved-ring { from { opacity: 0.9; transform: scale(1); } to { opacity: 0; transform: scale(1.18, 1.9); } }
.alert-card.is-fresh { animation: fresh-in 480ms var(--k-ease) both; }
.alert-card.is-fresh .field,
.alert-card.is-fresh .alert-amount { position: relative; }
.alert-card.is-fresh .field::after,
.alert-card.is-fresh .alert-amount::after {
  content: ""; position: absolute; inset: -4px; border-radius: 12px; pointer-events: none;
  animation: fresh-field 900ms var(--k-ease) both;
  animation-delay: calc(var(--i, 0) * 140ms + 260ms);
}
@keyframes fresh-in { from { opacity: 0; transform: translateY(12px); } }
@keyframes fresh-field {
  0% { box-shadow: 0 0 0 0 transparent; }
  25% { box-shadow: 0 0 0 1.5px var(--k-accent), 0 0 18px color-mix(in srgb, var(--k-cyan) 40%, transparent); }
  100% { box-shadow: 0 0 0 1.5px transparent, 0 0 18px transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .k .add-form .btn-primary.is-saved::after { animation: none; opacity: 0; }
}

/* ---- Accounts: status dots, cards flipping in, a bill paid (4.24) -------
 * The bill line carries a dot in its own colour: cyan due, amber due within
 * three days, red overdue (both pulse three times, then stop), green paid.
 * A savings pot says once that it never counts as spendable. The cards flip
 * up as the screen arrives, and a bill just paid glows its card green. */
.k .bill-when { display: inline-flex; align-items: center; gap: var(--k-2); }
.k .bill-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--k-cyan); box-shadow: 0 0 10px color-mix(in srgb, var(--k-cyan) 60%, transparent); }
.k .bill-urgent .bill-dot { background: var(--k-warning); box-shadow: 0 0 10px color-mix(in srgb, var(--k-warning) 60%, transparent); animation: bill-pulse 1.6s ease-in-out 3; }
.k .bill-overdue .bill-dot { background: var(--k-negative); box-shadow: 0 0 10px color-mix(in srgb, var(--k-negative) 60%, transparent); animation: bill-pulse 1.6s ease-in-out 3; }
.k .bill-paid { color: var(--k-positive); }
.k .bill-paid .bill-dot { background: var(--k-positive); box-shadow: 0 0 10px color-mix(in srgb, var(--k-positive) 60%, transparent); }
@keyframes bill-pulse { 50% { transform: scale(1.5); box-shadow: 0 0 0 5px transparent, 0 0 16px currentColor; } }
.k .acc-state { display: flex; align-items: center; gap: var(--k-2); margin: 0; padding: 0 var(--k-4) var(--k-3); font-size: var(--k-label); }
.k .acc-state--saved { color: var(--k-violet); }
.k .acc-state--saved .bill-dot { background: var(--k-violet); box-shadow: 0 0 10px color-mix(in srgb, var(--k-violet) 60%, transparent); }
.is-arriving .account-block { animation: acc-flip 520ms var(--k-ease) both; transform-origin: top center; }
.is-arriving .account-block:nth-child(2) { animation-delay: 60ms; }
.is-arriving .account-block:nth-child(3) { animation-delay: 120ms; }
.is-arriving .account-block:nth-child(4) { animation-delay: 180ms; }
.is-arriving .account-block:nth-child(5) { animation-delay: 240ms; }
.is-arriving .account-block:nth-child(n + 6) { animation-delay: 300ms; }
@keyframes acc-flip { from { opacity: 0; transform: perspective(700px) rotateX(-12deg) translateY(8px); } }
.k .account-block.just-paid { border-radius: var(--k-r-lg); animation: just-paid 1.8s var(--k-ease) both; }
@keyframes just-paid {
  0%, 30% { box-shadow: 0 0 0 1.5px var(--k-positive), 0 0 26px color-mix(in srgb, var(--k-positive) 40%, transparent); }
  100% { box-shadow: 0 0 0 1.5px transparent, 0 0 26px transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .k .bill-urgent .bill-dot, .k .bill-overdue .bill-dot { animation: none; }
}

/* ---- Plan: this month (4.25) ---- */
.k .plan-month { padding: var(--k-4) var(--k-4) var(--k-3); }
.is-arriving .committed-bar i { transform-origin: left center; animation: grow-x 700ms var(--k-ease) 120ms both; }
@keyframes grow-up { from { transform: scaleY(0); } }
@keyframes grow-x { from { transform: scaleX(0); } }

/* ---- History: the month day by day (4.26) --------------------------------
 * A bar for what went out each day, the biggest day named under it; tapping a
 * bar takes the list to that day, which glows for a moment. The bars draw
 * themselves left to right as the screen arrives. */
.k .hist-days { margin: var(--k-4) 0 var(--k-2); }
.k .hist-days__bars { display: flex; align-items: flex-end; gap: 2px; height: 84px; }
.k .hist-days__bar, .k .hist-days__none { flex: 1 1 0; min-width: 0; }
.k .hist-days__bar { height: var(--h); padding: 0; border: 0; border-radius: 3px 3px 1px 1px; background: color-mix(in srgb, var(--k-cyan) 55%, transparent); cursor: pointer; transform-origin: bottom center; }
.k .hist-days__bar.is-top { background: var(--k-cyan); box-shadow: 0 0 12px color-mix(in srgb, var(--k-cyan) 55%, transparent); }
.k .hist-days__bar:focus-visible { outline: 2px solid var(--k-text); outline-offset: 2px; }
.k .hist-days__none { height: 3px; border-radius: 2px; background: color-mix(in srgb, var(--k-text) 8%, transparent); }

.k .hist-day { scroll-margin-top: 80px; }
.k .hist-day.is-picked .hist-day-card { animation: day-picked 1.4s var(--k-ease); }
@keyframes day-picked { 0%, 35% { box-shadow: 0 0 0 1.5px var(--k-cyan), 0 0 22px color-mix(in srgb, var(--k-cyan) 35%, transparent); } }
.is-arriving .hist-days__bar { animation: grow-up 520ms var(--k-ease) calc(var(--i) * 14ms) both; }
@media (prefers-reduced-motion: reduce) {
  .k .hist-day.is-picked .hist-day-card { animation: none; }
}

/* ---- Coach: the hub and the answer card (4.27) ---------------------------
 * Kawach's mark in two rings that draw once as the screen arrives (nothing
 * keeps spinning). "Can I afford this?" answers with its verdict as a
 * coloured pill, a bar for how much of what is left the purchase takes, and
 * the sums counting to their figures. */
.k .coach-hub { width: 112px; height: 112px; margin: var(--k-2) auto 0; }
.k .coach-hub svg { display: block; width: 100%; height: 100%; overflow: visible; }
.k .coach-hub circle { fill: none; stroke-linecap: round; }
.k .coach-hub__track { stroke: color-mix(in srgb, var(--k-text) 6%, transparent); stroke-width: 3; }
.k .coach-hub__arc { stroke-dasharray: 72 100; }
.k .coach-hub__arc--outer { stroke: var(--k-cyan); stroke-width: 3; filter: drop-shadow(0 0 5px color-mix(in srgb, var(--k-cyan) 55%, transparent)); }
.k .coach-hub__arc--inner { stroke: var(--k-violet); stroke-width: 2.5; stroke-dasharray: 46 100; }
.k .coach-hub g path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.k .coach-hub__shield { stroke: var(--k-cyan); stroke-width: 3; filter: drop-shadow(0 0 6px color-mix(in srgb, var(--k-cyan) 60%, transparent)); }
.k .coach-hub__rupee { stroke: var(--k-text); stroke-width: 6.6; }
.k .coach-hub__note { margin: var(--k-2) 0 var(--k-3); text-align: center; font-size: var(--k-caption); color: var(--k-accent-text); letter-spacing: 0.04em; }
.is-arriving .coach-hub__arc--outer { animation: hub-draw-outer 1.1s var(--k-ease) 120ms both; }
.is-arriving .coach-hub__arc--inner { animation: hub-draw-inner 1.1s var(--k-ease) 260ms both; }
@keyframes hub-draw-outer { from { stroke-dasharray: 0 100; } }
@keyframes hub-draw-inner { from { stroke-dasharray: 0 100; } }
.k .coach-verdict.coach-pill { display: inline-flex; align-items: center; gap: var(--k-2); padding: 6px 12px; border-radius: 999px; font-size: var(--k-caption); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; background: color-mix(in srgb, currentColor 12%, transparent); border: 1px solid color-mix(in srgb, currentColor 40%, transparent); animation: pill-in 420ms var(--k-ease) both; }
.k .coach-pill::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; box-shadow: 0 0 8px currentColor; }
@keyframes pill-in { from { opacity: 0; transform: scale(0.85); } }
.k .coach-share { height: 10px; margin: var(--k-3) 0 var(--k-2); border-radius: 5px; background: color-mix(in srgb, var(--k-text) 7%, transparent); overflow: hidden; }
.k .coach-share i { display: block; height: 100%; border-radius: 5px; background: var(--k-positive); transform-origin: left center; animation: grow-x 800ms var(--k-ease) 200ms both; }
.k .coach-share--warn i { background: var(--k-warning); box-shadow: 0 0 12px color-mix(in srgb, var(--k-warning) 50%, transparent); }
.k .coach-share--bad i { background: var(--k-negative); box-shadow: 0 0 12px color-mix(in srgb, var(--k-negative) 50%, transparent); }
.k .coach-answer { animation: summary-rise 480ms var(--k-ease) both; }
@media (prefers-reduced-motion: reduce) {
  .k .coach-verdict.coach-pill, .k .coach-share i, .k .coach-answer { animation: none; }
}

/* ---- Settings: one line per setting (4.28) -------------------------------
 * Switches act at once, a row with an arrow opens a screen, and what is read
 * rarely (privacy, import history) folds away. The three small links share
 * one line at the foot. */
.k.settings-k .settings-card { padding: 0 var(--k-4); }
.k.settings-k .settings-card > * + * { border-top: 1px solid var(--k-hairline); }
.k.settings-k .settings-switch { min-height: 60px; padding: var(--k-2) 0; gap: var(--k-3); }
.k.settings-k .settings-row { min-height: 60px; }
.k.settings-k .settings-chev { display: inline-flex; color: var(--k-text-3); }
.k.settings-k .settings-chev svg { width: 16px; height: 16px; }
.k.settings-k .settings-days { flex: none; font: inherit; font-size: var(--k-label); color: var(--k-text-2); background: var(--k-surface-elev); border: 1px solid var(--k-hairline); border-radius: var(--k-r-sm); padding: 6px 8px; }
.k.settings-k .settings-card .status { margin: 0; padding: var(--k-2) 0 var(--k-3); border-top: 0; }
.k.settings-k .settings-fold { margin-top: var(--k-3); }
.k.settings-k .settings-fold .setup-points { margin: var(--k-2) 0; }
.k.settings-k .settings-foot { display: flex; justify-content: center; align-items: center; gap: var(--k-2); margin: var(--k-5) 0 var(--k-3); font-size: var(--k-label); color: var(--k-text-3); white-space: nowrap; }
.k.settings-k .settings-foot .link-btn { font-size: var(--k-label); padding: var(--k-2) 0; min-height: var(--k-tap); }
.k.settings-k .settings-fold > summary { justify-content: flex-start; }
.k.settings-k .settings-fold > summary .summary-sub { margin-left: auto; margin-right: var(--k-2); }
.k.settings-k .settings-fold > summary::after { margin-left: 0; }
.k.settings-k .settings-foot > * { display: inline-flex; align-items: center; min-height: var(--k-tap); }
.k.settings-k .settings-foot a.link-btn { text-decoration: none; }
/* A drawn dot, centred on the line, between the three links. */
.k.settings-k .settings-foot .foot-dot { min-height: 0; width: 3px; height: 3px; border-radius: 50%; background: var(--k-text-3); }

/* ==== 5.0 · THE CHARTS STYLE ==============================================
 * The default style (decided 2 Oct 2026). Every new feature is built here
 * first; Tactile comes later as a layer over it, falling
 * back to this wherever they have not restyled something yet. Colours come
 * from the colouring (css/looks.css): the three gradients are --k-grad-1
 * (accent to second accent), -2 (third to fourth) and -3 (warning to accent).
 */

/* The tracking card: the figure, three figures in a row, three rings. */
.hero.hero--tracking { padding: var(--k-5) var(--k-5) var(--k-4); }
.hero--tracking .tracking-fig { display: flex; align-items: baseline; gap: var(--k-3); flex-wrap: wrap; margin-top: var(--k-3); }
.hero--tracking .hero-amount { font-weight: 300; letter-spacing: -0.035em; margin: 0; }
.hero--tracking .tracking-under { font-size: var(--k-label); color: var(--k-text-3); }
.hero--tracking .tracking-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--k-2); margin-top: var(--k-4); }
.hero--tracking .tracking-stats small { display: block; font-size: var(--k-caption); color: var(--k-text-3); letter-spacing: var(--k-track-caption); }
.hero--tracking .tracking-stats b { display: block; margin-top: 4px; font-size: var(--k-value-sm); font-weight: var(--k-w-fig); font-variant-numeric: tabular-nums; }
.hero--tracking .tracking-rings { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--k-2); margin-top: var(--k-4); }
.hero--tracking .tracking-rings:has(> :nth-child(2):last-child) { grid-template-columns: repeat(2, 1fr); padding: 0 12%; }
.tracking-ring { position: relative; margin: 0; }
.tracking-ring svg { display: block; width: 100%; }
.tracking-ring__track { fill: none; stroke: color-mix(in srgb, var(--k-text) 7%, transparent); stroke-width: 12; }
.tracking-ring__arc { fill: none; stroke-width: 12; stroke-linecap: round; }
.tracking-ring--spent { --tg-a: var(--k-grad-1a); --tg-b: var(--k-grad-1b); }
.tracking-ring--month { --tg-a: var(--k-grad-2a); --tg-b: var(--k-grad-2b); }
.tracking-ring--aside { --tg-a: var(--k-grad-3a); --tg-b: var(--k-grad-3b); }
.tracking-ring--warn .tracking-ring__arc { stroke: var(--k-warning) !important; }
.tracking-ring--over .tracking-ring__arc { stroke: var(--k-negative) !important; }
.tracking-ring figcaption { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; }
.tracking-ring figcaption b { font-size: 1.05rem; font-weight: 300; font-variant-numeric: tabular-nums; }
.tracking-ring figcaption small { font-size: 0.66rem; color: var(--k-text-3); line-height: 1.2; max-width: 7ch; margin: 2px auto 0; }
.is-arriving .tracking-ring__arc { animation: hero-ring-in 1100ms var(--k-ease) both; }
.is-arriving .tracking-ring:nth-child(2) .tracking-ring__arc { animation-delay: 120ms; }
.is-arriving .tracking-ring:nth-child(3) .tracking-ring__arc { animation-delay: 240ms; }

/* The month as layered waves, with the biggest day marked. */
.waves-card { position: relative; padding: var(--k-3) 0 var(--k-4); overflow: hidden; }
.waves { display: block; width: 100%; height: auto; }
.waves__fill { stroke: none; }
.waves__line { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; }
.waves--spent.waves__fill { fill: color-mix(in srgb, var(--k-grad-2a) 22%, transparent); }
.waves--spent.waves__line { stroke: var(--k-grad-2a); filter: drop-shadow(0 0 4px color-mix(in srgb, var(--k-grad-2a) 60%, transparent)); }
.waves--pace.waves__fill { fill: color-mix(in srgb, var(--k-grad-3a) 12%, transparent); }
.waves--pace.waves__line { stroke: var(--k-grad-3a); stroke-dasharray: 5 5; }
.waves--day.waves__fill { fill: color-mix(in srgb, var(--k-grad-1b) 30%, transparent); }
.waves--day.waves__line { stroke: var(--k-grad-1a); }
.waves__dot { fill: var(--k-grad-1a); stroke: var(--k-surface); stroke-width: 2; }

.waves__key { display: grid; gap: 6px; padding: var(--k-2) var(--k-4) 0; font-size: var(--k-label); color: var(--k-text-3); }
.waves__k { display: grid; grid-template-columns: 14px 104px 1fr; align-items: center; }
.waves__k::before { content: ""; width: 9px; height: 9px; border-radius: 50%; border: 2px solid currentColor; }
.waves__k b { color: var(--k-text); font-weight: var(--k-w-label); font-variant-numeric: tabular-nums; }
.waves__k.waves--spent::before { color: var(--k-grad-2a); }
.waves__k.waves--pace::before { color: var(--k-grad-3a); }
.waves__k.waves--day::before { color: var(--k-grad-1a); }

/* Pill columns: this week with today lit, what is owed on each card. */
.pills-card { display: grid; gap: var(--k-2); padding: var(--k-2); }
.pills-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--k-3); padding: var(--k-3) var(--k-4); border-radius: var(--k-r-md); background: color-mix(in srgb, var(--k-text) 3%, transparent); }
.pills-row small { display: block; font-size: var(--k-label); color: var(--k-text-3); }
.pills-row b { display: block; margin-top: 4px; font-size: 1.7rem; font-weight: 300; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.pill-cols { display: flex; gap: 6px; height: 64px; flex: none; }
.pill-col { display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 4px; width: 18px; }
.pill-col i { display: block; width: 100%; border-radius: 6px; background: color-mix(in oklch, var(--k-grad-3a) 18%, var(--k-surface)); }

.pill-col--lit i { background: linear-gradient(180deg, var(--k-grad-3a), var(--k-grad-3b)); box-shadow: 0 0 12px color-mix(in srgb, var(--k-grad-3a) 45%, transparent); }

.pill-col small { font-size: 0.66rem; color: var(--k-text-3); white-space: nowrap; overflow: hidden; max-width: 30px; text-align: center; }

/* A card's bar names it (5.10): its name over its last digits, centred under it. */

.is-arriving .pill-col i { animation: grow-up 600ms var(--k-ease) both; transform-origin: bottom; }

/* The strip: the figures under the cards, a coloured line under each. */
.summary-rows.summary-strip { display: grid; grid-template-columns: 1fr 1fr; gap: var(--k-4) var(--k-3); padding: var(--k-4); }
.summary-strip > *, .summary-strip .summary-owed > * { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 0 0 var(--k-2); border: 0; text-align: left; }
.summary-strip .summary-owed { display: contents; }
.summary-strip .summary-row__k { font-size: var(--k-caption); letter-spacing: 0.08em; text-transform: uppercase; color: var(--k-text-2); }
.summary-strip .summary-row__k small { text-transform: none; letter-spacing: 0; }
.summary-strip .summary-row__v { font-size: 1.2rem; font-weight: 400; font-variant-numeric: tabular-nums; }
.summary-strip > *::after, .summary-strip .summary-owed > *::after { content: ""; align-self: stretch; height: 3px; border-radius: 2px; margin-top: 4px; background: var(--k-grad-3a); }
.summary-strip > *:nth-child(2)::after, .summary-strip .summary-owed > *:nth-child(1)::after { background: var(--k-grad-1a); }
.summary-strip .summary-owed > *:nth-child(2)::after { background: var(--k-grad-2a); }

/* The strip's tappable "Kept back" sheds its old button look, and the
   wrapper that holds the owed figures draws no line of its own. */
.summary-strip > button.summary-row { width: 100%; margin: 0; background: none; box-shadow: none; border-radius: 0; color: inherit; font: inherit; cursor: pointer; }
.summary-strip > button.summary-row .summary-row__k, .summary-strip > button.summary-row .summary-row__v { text-align: left; }
.summary-strip > .summary-owed::after { content: none; }
/* The strip's rows are tiles, whatever row style they had before. */
.k .summary-rows.summary-strip .summary-row { display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start; gap: 4px; padding: 0 0 var(--k-2); min-height: 0; }
.k .summary-rows.summary-strip .summary-row__k { display: block; }
.k .summary-rows.summary-strip .summary-row__k small { display: block; margin-top: 2px; }

/* ---- Add in the Charts style (5.1) ---------------------------------------
 * The amount on the second gradient with a wave across it and Spent or
 * Received as a white pill; the chosen category lit on the first gradient;
 * Save on the first gradient. Text on a gradient takes that gradient's own
 * ink from the colouring, so it reads in every one. */
.k .amount-hero { position: relative; overflow: hidden; padding: var(--k-5) var(--k-5) var(--k-4); border-radius: var(--k-r-lg); background: linear-gradient(160deg, var(--k-grad-2a), var(--k-grad-2b)); box-shadow: 0 14px 30px -14px color-mix(in srgb, var(--k-grad-2b) 60%, transparent); color: var(--k-grad-2-ink); }
.k .amount-hero::before { content: none; }
.k .amount-hero .hero-label, .k .amount-hero .amount-prefix, .k .amount-hero .amount-input { color: var(--k-grad-2-ink); }
.k .amount-hero .hero-label { opacity: 0.8; }
.k .amount-hero .amount-input { font-weight: 300; }
.k .amount-hero .amount-input::placeholder { color: var(--k-grad-2-ink); opacity: 0.45; }
.k .amount-hero .amount-input-wrap::after { background: color-mix(in srgb, var(--k-grad-2-ink) 30%, transparent); }
.k .amount-hero .amount-input-wrap:focus-within::after { background: var(--k-grad-2-ink); box-shadow: none; }
.k .amount-hero .amount-wave { display: block; width: 100%; height: auto; margin: var(--k-2) 0 0; fill: none; stroke: var(--k-grad-2-ink); stroke-width: 2; opacity: 0.55; }
.k .amount-hero .amount-wave circle { fill: var(--k-grad-2-ink); stroke: none; }
.k .amount-hero .direction-toggle { background: rgb(255 255 255 / 0.92); border: 0; padding: 4px; box-shadow: 0 6px 14px rgb(0 0 0 / 0.15); }
.k .amount-hero .k-seg__btn { color: color-mix(in srgb, black 62%, white); font-weight: var(--k-w-strong); letter-spacing: 0.06em; text-transform: uppercase; font-size: var(--k-caption); }
.k .amount-hero .k-seg__btn[aria-selected="true"] { background: none; color: color-mix(in srgb, black 87%, white); box-shadow: none; }
.k .amount-hero .k-seg__btn + .k-seg__btn { border-left: 1px solid color-mix(in srgb, black 13%, white); border-radius: 0 999px 999px 0; }
.k .k-picker.is-chosen { border-color: transparent; background: linear-gradient(90deg, var(--k-grad-1a), var(--k-grad-1b)); color: var(--k-grad-1-ink); }
.k .k-picker.is-chosen::after { border-color: var(--k-grad-1-ink); }
.k .add-form .k-btn--primary { background: linear-gradient(90deg, var(--k-grad-1a), var(--k-grad-1b)); color: var(--k-grad-1-ink); box-shadow: 0 10px 22px -10px color-mix(in srgb, var(--k-grad-1b) 70%, transparent); }
.k .amount-hero .amount-input { background: transparent !important; border: 0 !important; box-shadow: none !important; }

/* ---- Accounts in the Charts style (5.2) ----------------------------------
 * Each account's mark is a gradient circle by kind (cards on the third
 * gradient, banks and cash on the second, savings, the fund and loans on the
 * first); the split ring takes the gradient ends; a loan shows the tick
 * gauge. */
.k .account-row .k-brand { border-radius: 50% !important; border: 0 !important; box-shadow: none !important; color: var(--k-grad-2-ink) !important; background: linear-gradient(160deg, var(--k-grad-2a), var(--k-grad-2b)) !important; }
.k .account-row--card .k-brand { color: var(--k-grad-3-ink) !important; background: linear-gradient(160deg, var(--k-grad-3a), var(--k-grad-3b)) !important; }
.k .account-row--savings .k-brand, .k .account-row--pf .k-brand, .k .account-row--loan .k-brand { color: var(--k-grad-1-ink) !important; background: linear-gradient(160deg, var(--k-grad-1a), var(--k-grad-1b)) !important; }
.k .account-row .k-brand .k-brand__glyph, .k .account-row .k-brand svg { color: inherit !important; }
.alloc-ring circle:not(.chart-ring-track) { stroke-width: 13; }
.tick-gauge { margin: var(--k-2) auto var(--k-1); max-width: 240px; text-align: center; }
.tick-gauge svg { display: block; width: 100%; height: auto; }
.gauge-tick { stroke: var(--k-grad-3a); stroke-width: 3.4; stroke-linecap: round; opacity: 0.2; }
.gauge-tick--far { stroke: var(--k-grad-3b); }
.gauge-tick--lit { opacity: 1; }
.tick-gauge__v { fill: var(--k-text); font: 300 30px var(--k-font); }
.tick-gauge figcaption { margin-top: 2px; font-size: var(--k-caption); letter-spacing: 0.12em; text-transform: uppercase; color: var(--k-text-2); }
.is-arriving .gauge-tick--lit { animation: tick-in 500ms var(--k-ease) both; }
@keyframes tick-in { from { opacity: 0.2; } }

/* ---- History in the Charts style (5.4) -----------------------------------
 * Money in and out on the second and first gradients, the month day by day
 * on the first gradient with the biggest day lit, the net figure in light
 * numerals, category marks as round chips. */
.k .bar-in { fill: var(--k-grad-2a); filter: drop-shadow(0 0 4px color-mix(in srgb, var(--k-grad-2a) 45%, transparent)); }
.k .bar-out { fill: var(--k-grad-1a); filter: drop-shadow(0 0 4px color-mix(in srgb, var(--k-grad-1a) 45%, transparent)); }
.k #hist-hero .hero-amount { font-weight: 300; letter-spacing: -0.035em; }
.k .hist-days__bar { background: linear-gradient(180deg, var(--k-grad-1a), var(--k-grad-1b)); opacity: 0.55; }
.k .hist-days__bar.is-top { opacity: 1; background: linear-gradient(180deg, var(--k-grad-1a), var(--k-grad-1b)); box-shadow: 0 0 12px color-mix(in srgb, var(--k-grad-1a) 55%, transparent); }

.k .hist-cat { border-radius: 50%; }
.k .hist-day.is-picked .hist-day-card { animation-name: day-picked-charts; }
@keyframes day-picked-charts { 0%, 35% { box-shadow: 0 0 0 1.5px var(--k-grad-1a), 0 0 22px color-mix(in srgb, var(--k-grad-1a) 35%, transparent); } }

/* ---- Coach in the Charts style (5.5) -------------------------------------
 * The tracking card with one ring, the questions' marks as gradient circles,
 * the answer's share bar on the third gradient. */
.hero--tracking .tracking-rings:has(> :only-child) { grid-template-columns: 1fr; padding: 0 30%; }
.hero--tracking .tracking-rings:has(> :only-child) figcaption small { max-width: 12ch; }
.k-coach .coach-q-icon { border-radius: 50%; border: 0; color: var(--k-grad-1-ink); background: linear-gradient(160deg, var(--k-grad-1a), var(--k-grad-1b)); }
.k-coach .coach-q:nth-child(2) .coach-q-icon { color: var(--k-grad-2-ink); background: linear-gradient(160deg, var(--k-grad-2a), var(--k-grad-2b)); }
.k-coach .coach-q:nth-child(3) .coach-q-icon { color: var(--k-grad-3-ink); background: linear-gradient(160deg, var(--k-grad-3a), var(--k-grad-3b)); }
.k .coach-share--good i { background: linear-gradient(90deg, var(--k-grad-2a), var(--k-grad-2b)); }
.k .coach-share--warn i { background: linear-gradient(90deg, var(--k-grad-3a), var(--k-grad-3b)); }
.k .coach-hub__arc--outer { stroke: var(--k-grad-1a); }
.k .coach-hub__arc--inner { stroke: var(--k-grad-2a); }
.k .coach-hub__shield { stroke: var(--k-grad-1a); }

/* --- Charts: what is coming up (5.10, summary-looks.js chartsComing) ------ */
.ch-coming { display: grid; gap: var(--k-3); }
.ch-coming__k { font-size: var(--k-label); font-weight: var(--k-w-label); letter-spacing: var(--k-track-caption); text-transform: uppercase; color: var(--k-text-3); }
.ch-coming__row { display: grid; grid-template-columns: 32px 1fr auto; gap: var(--k-3); align-items: center; }
.ch-coming__ic { width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; color: var(--k-grad-1a); background: color-mix(in srgb, var(--k-grad-1a) 14%, var(--k-surface)); }
.ch-coming__ic svg { width: 16px; height: 16px; }
.ch-coming__t { display: grid; gap: 2px; min-width: 0; font-size: var(--k-body); color: var(--k-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ch-coming__t small { font-size: var(--k-label); color: var(--k-text-3); }
.ch-coming__row b { font-weight: var(--k-w-label); font-variant-numeric: tabular-nums; color: var(--k-text); }
.ch-coming__row b.is-late { color: var(--k-negative); }

/* A fold with a count or a note: it sits at the right, by the chevron
   (5.10). The count and the chevron both pushed themselves right, split the
   space, and the count floated in the middle of the row. */
.section-fold > summary > .muted,
.section-fold > summary > .summary-sub { margin-left: auto; margin-right: var(--k-2); }
.section-fold > summary:has(> .muted, > .summary-sub)::after { margin-left: 0; }
.ch-coming__head { display: flex; justify-content: space-between; align-items: baseline; }
.ch-coming__still { font-size: var(--k-label); color: var(--k-text-2); font-variant-numeric: tabular-nums; }
.ch-coming { margin-top: var(--k-3); }

/* --- Add: the five recent categories as chips (5.12), every style ------- */
.k .k-quick { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--k-3); }
.k .k-quick__chip { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--k-border-subtle); background: color-mix(in srgb, var(--k-text) 4%, transparent); color: var(--k-text-2); font: inherit; font-size: var(--k-label); cursor: pointer; }
.k .k-quick__chip svg { width: 15px; height: 15px; flex: none; }
.k .k-quick__chip.on { background: linear-gradient(135deg, var(--k-grad-1a), var(--k-grad-1b)); color: var(--k-grad-1-ink); border-color: transparent; }

/* Amounts where a percentage used to be (5.18): smaller, to fit the ring. */
.tracking-ring figcaption b.is-amount { font-size: 14px; letter-spacing: -0.01em; }
.k .meter-radial-v--amount { font-size: 22px; }
.tick-gauge__v--amount { font-size: 20px; }

/* --- The short Summary (5.18): set up, Needs you, the fold --------------- */
.k .setup-card { display: grid; gap: var(--k-4); padding: var(--k-5) var(--k-4) var(--k-4); border-radius: var(--k-r-lg); background: var(--k-surface); border: 1px solid var(--k-hairline); }
.k .setup-card h2 { margin: 0; font-size: 22px; font-weight: 650; letter-spacing: -0.01em; }
.k .setup-card__sub { margin: 4px 0 0; font-size: var(--k-label); color: var(--k-text-3); }
.k .setup-progress { height: 6px; border-radius: 3px; background: color-mix(in srgb, var(--k-text) 8%, transparent); overflow: hidden; }
.k .setup-progress i { display: block; height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--k-grad-1a), var(--k-grad-1b)); }
.k .setup-steps { margin: 0; padding: 0; list-style: none; display: grid; }
.k .setup-step { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 14px 0; }
.k .setup-step + .setup-step { border-top: 1px solid var(--k-hairline); }
.k .setup-step__n { width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; font-weight: 650; color: var(--k-text-2); border: 1.5px solid color-mix(in srgb, var(--k-text) 22%, transparent); }
.k .setup-step__n svg { width: 16px; height: 16px; }
.k .setup-step.is-next .setup-step__n { color: var(--k-grad-1-ink); border: 0; background: linear-gradient(135deg, var(--k-grad-1a), var(--k-grad-1b)); }
.k .setup-step.is-done .setup-step__n { color: var(--k-positive); border-color: var(--k-positive); }
.k .setup-step__body { display: grid; gap: 2px; }
.k .setup-step__body b { font-weight: 600; }
.k .setup-step__body small { font-size: var(--k-label); color: var(--k-text-3); }
.k .setup-step.is-done .setup-step__body b { color: var(--k-text-2); }
.k .setup-step .k-btn { min-height: 36px; padding: 0 16px; }
.k .setup-step.is-later .k-btn { opacity: .55; }
.k .setup-tour { justify-self: start; gap: 8px; }
.k .setup-tour svg { width: 16px; height: 16px; }
.k .setup-strip { display: grid; gap: 10px; padding: 14px 16px; margin-bottom: var(--k-3); border-radius: var(--k-r-md); background: var(--k-surface); border: 1px solid var(--k-hairline); }
.k .setup-strip__row { display: flex; justify-content: space-between; align-items: center; gap: 12px; font-size: var(--k-label); color: var(--k-text-2); }
.k .setup-strip__row b { color: var(--k-text); font-weight: 600; }
.k .setup-strip .k-btn { min-height: 34px; padding: 0 14px; flex: none; }
.k .sum-answer { margin: 6px 0 4px !important; font-size: var(--k-body) !important; font-weight: 500; color: var(--k-text) !important; }
.k .sum-answer.bad { color: var(--k-negative) !important; }
.k .sum-needs { margin: var(--k-4) 0; padding: 4px var(--k-4) 4px; border-radius: var(--k-r-lg); background: var(--k-surface); border: 1px solid var(--k-hairline); }
.k .sum-needs__head { margin: 0; padding: 12px 0 4px; font-size: var(--k-label); font-weight: 600; letter-spacing: var(--k-track-caption); text-transform: uppercase; color: var(--k-text-3); }
.k .need-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 12px 0; --tint: var(--k-grad-2a); }
.k .need-row + .need-row, .k .need-more { border-top: 1px solid var(--k-hairline); }
.k .need-row.is-alert, .k .need-row.bill-overdue { --tint: var(--k-negative); }
.k .need-row.is-soon, .k .need-row.bill-urgent { --tint: var(--k-warning); }
.k .need-row__ic { width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; color: var(--tint); background: color-mix(in srgb, var(--tint) 14%, transparent); }
.k .need-row__ic svg { width: 17px; height: 17px; }
.k .need-row__t { display: grid; gap: 2px; font-size: var(--k-body); line-height: 1.35; }
.k .need-row__t b { font-weight: 650; }
.k .need-row__t small { font-size: var(--k-label); color: var(--k-text-3); }
.k .need-row__go { display: flex; gap: 6px; align-items: center; }
.k .need-row__go .btn-tiny, .k .need-row__go select { min-height: 34px; padding: 0 14px; border-radius: 999px; font-size: 14px; font-weight: 600; }
.k .need-more > summary { padding: 12px 0; font-size: var(--k-label); font-weight: 600; color: var(--k-text-2); cursor: pointer; }
.k .sum-calm { display: flex; gap: 10px; align-items: center; margin: var(--k-4) 0; padding: 12px 16px; border-radius: var(--k-r-md); color: var(--k-text-2); background: color-mix(in srgb, var(--k-positive) 8%, transparent); }
.k .sum-calm svg { width: 18px; height: 18px; color: var(--k-positive); flex: none; }
.k .sum-more { margin-top: var(--k-4); border-radius: var(--k-r-lg); background: var(--k-surface); border: 1px solid var(--k-hairline); }
.k .sum-more > summary { list-style: none; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; align-items: center; padding: 16px; cursor: pointer; }
.k .sum-more > summary::-webkit-details-marker { display: none; }
.k .sum-more > summary::after { content: "+"; grid-row: 1 / span 2; grid-column: 2; color: var(--k-text-3); font-size: 18px; }
.k .sum-more[open] > summary::after { content: "−"; }
.k .sum-more__t { font-weight: 600; }
.k .sum-more__body { padding: 0 var(--k-3) var(--k-3); display: grid; gap: var(--k-3); }
.k .sum-more__body > * { margin-top: 0; margin-bottom: 0; }
.k.settings-k .version-line, .settings-k .version-line { display: flex; justify-content: center; align-items: center; gap: var(--k-3); margin-top: var(--k-5); font-size: var(--k-label); color: var(--k-text-3); }

/* --- Lent and borrowed (5.20) ------------------------------------------
 * Add: who, as chips with their initials, under the way the money went.
 * Accounts: the two totals, then one row per person, opened like an account. */
.k .add-person { display: grid; gap: var(--k-4); }
.k .add-people { flex-wrap: wrap; }
.k .add-people .k-quick__chip { padding-left: 5px; }
.k .add-people .k-quick__chip:last-child { padding-left: 12px; }
.k .add-people .k-brand { width: 26px; height: 26px; border-radius: 50%; font-size: 11px; }
.k #add-person-name { margin-top: var(--k-2); }
.k .person-open[aria-expanded="true"] .account-row__chev { border-color: var(--k-accent); transform: rotate(225deg) translate(-0.08em, -0.08em); }
.k .person-open .k-brand { border-radius: 50%; }
.k .people-late { color: var(--k-warning); }
.k .people-sums { display: flex; gap: var(--k-3); margin-bottom: var(--k-3); }
.k .people-sums > div { flex: 1; display: grid; gap: 2px; padding: 12px 14px; border-radius: var(--k-r-md); background: var(--k-surface); border: 1px solid var(--k-hairline); }
.k .people-sums span { font-size: var(--k-caption); font-weight: var(--k-w-fig); letter-spacing: var(--k-track-caption); text-transform: uppercase; color: var(--k-text-3); }
.k .people-sums b { font-size: 20px; font-weight: 650; font-variant-numeric: tabular-nums; }
.k .people-sums b.pos { color: var(--k-positive); }
.k .account-detail .person-backby { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: var(--k-3); margin: var(--k-2) 0; font-size: var(--k-label); color: var(--k-text-2); }
.k .account-detail .person-backby input { max-width: 11em; margin: 0; }
.k .account-detail .person-backby > span { margin: 0; }
.k .hist-person { margin-top: var(--k-2); }
/* "Lent, borrowed" is the longest of the three, so it takes the room it needs. */
.k .direction-toggle .k-seg__btn { flex: 1 1 auto; white-space: nowrap; padding-inline: 10px; }
/* For your CA (5.21): a field and two buttons, so the card keeps its padding all round. */
.k.settings-k .settings-card.ca-card { display: grid; gap: var(--k-3); padding: var(--k-4); }
/* Salary at a month's end (5.22): one question, asked once, under the net. */
.k .hist-salary { display: grid; gap: var(--k-3); margin: var(--k-3) 0; padding: var(--k-4); border-radius: var(--k-r-md); background: var(--k-surface); border: 1px solid var(--k-hairline); }
.k .hist-salary p { margin: 0; color: var(--k-text-2); }
.k .hist-salary b { color: var(--k-text); }
.k .hist-salary__go { display: flex; gap: var(--k-2); flex-wrap: wrap; }
/* What the month brought forward and ends with (5.21.5): one quiet line. */
.k .hist-carry { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2px var(--k-3); margin: 2px 0 var(--k-3); font-size: var(--k-label); color: var(--k-text-3); }
.k .hist-carry[hidden] { display: none; }
.k .hist-carry span { white-space: nowrap; }
.k .hist-carry b { font-weight: 600; color: var(--k-text-2); font-variant-numeric: tabular-nums; }

/* =======================================================================
   5.23 - month charts that say what they are, work costs, tappable months,
   and the alignment fixes found going through every screen
   ===================================================================== */

/* The header is solid down to its last sliver: at 62% a figure scrolling
   under it showed through behind the title and the two collided. */
body:has(#view-container.k) .app-header {
  background: linear-gradient(180deg, var(--k-bg) 0%, var(--k-bg) 90%, transparent 100%);
}

/* --- the month chart ---------------------------------------------------- */
.k .chart-head { display: grid; gap: 2px; padding: 0 var(--k-4) var(--k-2); }
.k .chart-head b { font-size: var(--k-body); font-weight: var(--k-w-fig); color: var(--k-text); }
.k .chart-head small { font-size: var(--k-caption); line-height: 1.35; color: var(--k-text-2); }
.k .waves__bar { fill: color-mix(in srgb, var(--k-grad-1a) 40%, transparent); }
.k .waves__bar.is-picked { fill: var(--k-grad-1a); }
.k .waves__guide { stroke: var(--k-text-2); stroke-width: 1; stroke-dasharray: 2 3; vector-effect: non-scaling-stroke; }
.k .waves__tick { fill: var(--k-text-2); font-size: 10.5px; font-family: var(--k-font); }
.k .waves { touch-action: pan-y; cursor: crosshair; }
.k .chart-readout { margin: var(--k-2) var(--k-4) 0; padding: 9px 12px; border-radius: var(--k-r-sm); font-size: var(--k-label); line-height: 1.4; color: var(--k-text); background: color-mix(in srgb, var(--k-text) 6%, transparent); }
.k .waves__key { padding-inline: var(--k-4); }
.k .waves__k { grid-template-columns: 14px 140px minmax(0, 1fr); }
.k button.waves__k { width: 100%; margin: 0; padding: 0; border: 0; border-radius: 6px; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.k button.waves__k:active { background: var(--k-surface-press); }

/* --- Owed back opens its list --------------------------------------------- */
.k #owed-back-stat { cursor: pointer; font: inherit; text-align: left; }
.k #owed-back-stat[aria-expanded="true"] { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--k-positive) 60%, transparent); }
.k .owed-list { margin: var(--k-3) 0; padding: var(--k-3) var(--k-4); border-radius: var(--k-r-lg); background: var(--k-surface); border: 1px solid var(--k-hairline); animation: owed-in 180ms ease-out both; }
@keyframes owed-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .k .owed-list { animation: none; } }
.k .owed-list__head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--k-3); padding: 2px 0 var(--k-2); font-size: var(--k-caption); font-weight: var(--k-w-fig); letter-spacing: var(--k-track-caption); text-transform: uppercase; color: var(--k-text-2); }
.k .owed-list__head b { font-size: var(--k-label); letter-spacing: 0; color: var(--k-positive); font-variant-numeric: tabular-nums; }
.k .owed-list__head--sub { margin-top: var(--k-3); padding-top: var(--k-3); border-top: 1px solid var(--k-hairline); }
.k .owed-row { display: grid; grid-template-columns: 52px minmax(0, 1fr) auto; gap: var(--k-3); align-items: center; width: 100%; margin: 0; padding: 10px 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; }
.k button.owed-row { cursor: pointer; }
.k button.owed-row:active { background: var(--k-surface-press); }
.k .owed-row + .owed-row { border-top: 1px solid var(--k-hairline); }
.k .owed-row__d { font-size: var(--k-label); color: var(--k-text-2); }
.k .owed-row__t { display: grid; gap: 1px; min-width: 0; font-size: var(--k-body); }
.k .owed-row__t small { font-size: var(--k-caption); color: var(--k-text-2); }
.k .owed-row__v { font-weight: 600; font-variant-numeric: tabular-nums; }
.k .owed-row--in .owed-row__v { color: var(--k-positive); }
/* The "Yes, paid back" button sits under the text, in the text column, at full tap size. */
.k .owed-ask { grid-column: 2 / -1; display: flex; flex-wrap: wrap; gap: var(--k-2); margin: 0 0 4px; }
.k .owed-yes, .k .owed-no { min-height: 44px; }
.k .owed-list__late { margin: var(--k-2) 0 0; font-size: var(--k-caption); color: var(--k-warning); }
.k .owed-list__tip, .k .owed-list__none { margin: var(--k-3) 0 0; font-size: var(--k-caption); line-height: 1.4; color: var(--k-text-2); }

/* --- what is work on a card ------------------------------------------------- */
.k .tl-thin { position: relative; }
/* A card's bar on Summary: yours, owed by the company, planned (hatched), as one run (5.27.2). */
.k .cb { position: absolute; left: 0; top: 0; bottom: 0; display: flex; border-radius: inherit; overflow: hidden; }
.k .cb u { display: block; height: 100%; text-decoration: none; }
.k .cb .own { background: var(--k-accent); }
.k .cb .work { background: var(--k-positive); }
.k .cb .plan { background: repeating-linear-gradient(135deg, var(--k-text-2) 0 3px, transparent 3px 6px); }
.k .card-key { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 2px 14px; margin: -2px 0 6px; font-size: 11px; color: var(--k-text-2); }
.k .card-key > span { display: inline-flex; align-items: center; gap: 5px; }
.k .card-key > span::before { content: ""; width: 8px; height: 8px; border-radius: 2px; background: var(--k-accent); }
.k .card-key .work::before { background: var(--k-positive); }
.k .card-key .plan::before { background: repeating-linear-gradient(135deg, var(--k-text-2) 0 2px, transparent 2px 4px); border: 1px solid var(--k-text-3); }
.k .card-key b { font-weight: 600; color: var(--k-text); font-variant-numeric: tabular-nums; }
.k .card-legend { margin: 8px 0 0; font-size: 11px; color: var(--k-text-3); }
.k .card-split { display: grid; gap: 6px; padding: 0 0 var(--k-3); }
.k .card-split__bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; background: color-mix(in srgb, var(--k-text) 8%, transparent); }
.k .card-split__bar i { display: block; height: 100%; }
.k .card-split__bar .own { background: var(--k-accent); }
.k .card-split__bar .work { background: var(--k-positive); }
.k .card-split__bar .coming { background: repeating-linear-gradient(135deg, var(--k-text-2) 0 3px, transparent 3px 6px); }
.k .card-split__key { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px var(--k-3); font-size: var(--k-caption); color: var(--k-text-2); }
.k .card-split__key span { display: inline-flex; align-items: center; gap: 6px; }
.k .card-split__key span::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--k-accent); }
.k .card-split__key .work::before { background: var(--k-positive); }
.k .card-split__key .coming::before { background: repeating-linear-gradient(135deg, var(--k-text-2) 0 2px, transparent 2px 4px); border: 1px solid var(--k-text-3); }
.k .card-split__coming { margin: 0; font-size: var(--k-caption); color: var(--k-text-3); }
.k .card-split__bill { display: flex; justify-content: space-between; align-items: baseline; margin: 2px 0 0; padding-top: 6px; border-top: 1px solid var(--k-hairline); font-size: var(--k-label); color: var(--k-text-2); }
.k .card-split__bill b { font-size: var(--k-body); font-weight: 600; color: var(--k-text); font-variant-numeric: tabular-nums; }
.k .card-split__key b { margin-left: 2px; font-weight: 600; color: var(--k-text); font-variant-numeric: tabular-nums; }
.k .card-split__note { margin: 0; padding: 0 0 var(--k-3); font-size: var(--k-caption); color: var(--k-positive); }

/* --- this month's sheet ----------------------------- */
#month-sheet .k-scrim, #quick-sheet .k-scrim { z-index: 40; }
#month-sheet .k-sheet, #quick-sheet .k-sheet { z-index: 41; max-height: 78vh; display: flex; flex-direction: column; }
.month-sheet__line { margin: var(--k-3) 0 var(--k-2); font-size: var(--k-label); color: var(--k-text-2); }
.month-sheet__line b { color: var(--k-text); font-variant-numeric: tabular-nums; }
.month-act { width: 100%; text-align: left; }

/* --- the week's columns say what each day was -------------------------------- */
.k .tl-cols { height: 98px; }
.k .tl-cols i.tl-other, .k .tl-hatch-note { display: none; }
.k .tl-cols em { font-style: normal; font-size: 10.5px; line-height: 1; color: var(--k-text-2); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* --- History: what went out each day ------------------------------------------ */
.k .hist-days__title { margin: 0 0 var(--k-3); font-size: var(--k-caption); font-weight: var(--k-w-fig); letter-spacing: var(--k-track-caption); text-transform: uppercase; color: var(--k-text-2); }
.k .hist-days__col { flex: 1 1 0; min-width: 0; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 1px; margin: 0; padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.k .hist-days__col .hist-days__bar { display: block; width: 100%; flex: none; }
.k .hist-days__col.is-picked .hist-days__bar { opacity: 1; box-shadow: 0 0 10px color-mix(in srgb, var(--k-grad-1a) 55%, transparent); }
.k .hist-days__col:focus-visible { outline: 2px solid var(--k-text); outline-offset: 2px; }
.k .seg-fixed { display: block; width: 100%; min-height: 3px; border-radius: 2px; background: repeating-linear-gradient(135deg, color-mix(in srgb, var(--k-text) 34%, transparent) 0 2px, transparent 2px 4px); }
.k .seg-fixed.is-cut { clip-path: polygon(0 4px, 25% 0, 50% 4px, 75% 0, 100% 4px, 100% 100%, 0 100%); }
.k .hist-days__ticks { display: flex; justify-content: space-between; margin-top: 4px; font-size: 10.5px; color: var(--k-text-2); font-variant-numeric: tabular-nums; }
.k .hist-days__read { margin: var(--k-2) 0 0; font-size: var(--k-caption); line-height: 1.4; color: var(--k-text-2); }
.k .hist-days__read strong { color: var(--k-text); font-variant-numeric: tabular-nums; }
.k .hist-days__fixed { display: flex; align-items: flex-start; gap: 8px; margin: 6px 0 0; font-size: var(--k-caption); line-height: 1.4; color: var(--k-text-2); }
.k .hist-days__fixed i { flex: none; width: 12px; height: 8px; margin-top: 4px; border-radius: 2px; background: repeating-linear-gradient(135deg, color-mix(in srgb, var(--k-text) 34%, transparent) 0 2px, transparent 2px 4px); }

/* --- tick boxes: ours, not the browser's orange square ------------------------ */
.k .hist-flag input[type="checkbox"], .k .checkbox-row input[type="checkbox"] {
  -webkit-appearance: none; appearance: none;
  flex: none; display: grid; place-content: center;
  width: 24px; height: 24px; margin: 0;
  border-radius: 8px; border: 1.5px solid var(--k-border-emphasis); background: var(--k-surface);
  cursor: pointer; transition: background var(--k-t-fast) var(--k-ease), border-color var(--k-t-fast) var(--k-ease);
}
.k .hist-flag input[type="checkbox"]::after, .k .checkbox-row input[type="checkbox"]::after {
  content: ""; width: 12px; height: 7px; margin-top: -2px;
  border-left: 2.5px solid var(--k-accent-ink); border-bottom: 2.5px solid var(--k-accent-ink);
  transform: rotate(-45deg) scale(0); transition: transform var(--k-t-fast) var(--k-ease);
}
.k .hist-flag input[type="checkbox"]:checked, .k .checkbox-row input[type="checkbox"]:checked { background: var(--k-accent); border-color: var(--k-accent); }
.k .hist-flag input[type="checkbox"]:checked::after, .k .checkbox-row input[type="checkbox"]:checked::after { transform: rotate(-45deg) scale(1); }
.k .hist-flag input[type="checkbox"]:disabled { opacity: .45; cursor: default; }
.k .hist-flag, .k .checkbox-row { gap: var(--k-3); align-items: center; line-height: 1.35; }
.k .hist-flag > span, .k .checkbox-row > span { flex: 1; min-width: 0; }

/* --- a payment's Edit panel: one rhythm -------------------------------------- */
.k .txn-edit-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--k-2); align-items: stretch; }
.k .txn-edit-row .rv-field[type="date"] { flex: none; width: 100%; min-height: 44px; }
.k .txn-edit-row .direction-toggle { align-self: stretch; }

.k .hist-edit .rv-field { width: 100%; }

/* Small text that was already here, brought up to AA on the light looks. */
.k .waves__key { color: var(--k-text-2); }
.k button.waves__k { min-height: 36px; }
.k .waves__key { gap: 2px; }
.k .hist-days__bar.is-cut { clip-path: polygon(0 4px, 25% 0, 50% 4px, 75% 0, 100% 4px, 100% 100%, 0 100%); }

/* ---- 5.24: the tap-to-explain bubble in Charts, with the colouring's own rim ---- */
:root:not([data-style]) .explain-pop { border: 1px solid color-mix(in srgb, var(--k-grad-1a) 45%, transparent); box-shadow: 0 14px 28px -8px rgb(0 0 0 / 0.6), 0 0 18px color-mix(in srgb, var(--k-grad-1a) 22%, transparent); }
:root:not([data-style]) .explain-pop b { color: var(--k-text); }

/* 5.24: found measuring the Tactile-first pieces in every colouring. The bubble's
   title is the text colour with a small accent dot (the accent itself failed AA on
   several colourings); a late reminder is warning-tinted but legible on light; and
   the short Summary's small labels use the stronger grey. */
.explain-pop b::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 7px; border-radius: 50%; background: var(--k-accent); vertical-align: 1px; }
.k .people-late { color: color-mix(in srgb, var(--k-warning) 55%, var(--k-text)); }
.k .people-sums span { color: var(--k-text-2); }
.k .people-sums b.pos { color: color-mix(in srgb, var(--k-positive) 70%, var(--k-text)); }
.k .sum-needs__head, .k .need-row__t small, .k .setup-card__sub, .k .setup-step__body small { color: var(--k-text-2); }

/* --- Tap targets, the last few without one (5.26) ------------------------
 * The app widens small controls with an invisible strip (see the 44px rules
 * above and in style.css). These had none: the tab buttons were separated by
 * dead margin, so a thumb between two labels hit nothing. The margin is now a
 * transparent border, which keeps the look and puts the gap inside the target. */
.nav-btn { margin-inline: 0; border-inline: var(--space-3xs) solid transparent; background-clip: padding-box; }
.k .k-quick__chip, .k button.waves__k, .pf-month, .money-kind, .btn-secondary.btn-block { min-height: var(--k-tap); }
.muted-note a { display: inline-block; padding: 14px 4px; margin: -14px -4px; }

/* --- Charts: the cards as rows of yours, owed by the company and planned (5.28) --- */
.k .ch-cards { display: grid; gap: 10px; padding: var(--k-4); }
.k .ch-cards__head { display: flex; align-items: center; gap: var(--k-3); }
.k .ch-cards__k { font-size: var(--k-label); color: var(--k-text-2); }
.k .ch-cards__head > b { margin-left: auto; font-size: var(--k-value); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--k-text); }
.k .ch-cardrow { display: grid; grid-template-columns: 74px minmax(0, 1fr) 84px; gap: 6px 10px; align-items: center; font-size: 12.5px; color: var(--k-text-2); }
.k .ch-cardrow > b { text-align: right; font-weight: 700; color: var(--k-text); font-variant-numeric: tabular-nums; }
.k .ch-track { position: relative; display: block; height: 8px; border-radius: 4px; background: color-mix(in srgb, var(--k-text) 10%, transparent); overflow: hidden; }

/* --- Keyboard and focus (5.29) --------------------------------------------
 * The amount field is wrapped in a box that is lit all the time, so focusing it changed
 * nothing; it now gets a ring. The month charts can be focused and read with the arrow keys. */
.k .amount-input-wrap:focus-within { outline: 2px solid var(--k-accent); outline-offset: 2px; }
.k .waves:focus-visible { outline: 2px solid var(--k-accent); outline-offset: 2px; border-radius: 6px; }

/* --- The safety cushion on Accounts (5.30): six cells, one for each month aimed for --- */
.k .cushion { display: grid; gap: 10px; padding: var(--k-4); }
.k .cushion__top { display: flex; align-items: baseline; gap: var(--k-3); }
.k .cushion__k { font-size: var(--k-label); color: var(--k-text-2); }
.k .cushion__top > b { margin-left: auto; font-size: var(--k-value); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--k-text); }
.k .cushion__top > em { font-style: normal; font-size: 12px; font-weight: 600; color: var(--k-text-2); padding: 2px 8px; border-radius: 999px; border: 1px solid var(--k-border); }
.k .cushion__bar { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; }
.k .cushion__bar i { position: relative; display: block; height: 10px; border-radius: 3px; overflow: hidden; background: color-mix(in srgb, var(--k-text) 12%, transparent); }
.k .cushion__bar u { position: absolute; inset: 0 auto 0 0; background: var(--k-positive); text-decoration: none; }
.k .cushion__line { margin: 0; font-size: 12px; color: var(--k-text-2); }

/* Subscriptions on Plan (5.30): the first row is the total, one that has stopped billing is flagged in words and amber. */
.k .subs-total .k-row__title { font-weight: 600; }
.k .subs-total .k-row__value { font-weight: 600; }
.k .subs-row.is-stale .k-row__meta { color: var(--k-warning); }

/* --- The app lock (5.31, js/lock.js) --------------------------------------
 * A full screen over everything, opaque, with a keypad of 64px keys. Until the PIN is
 * right the screens underneath are hidden from the very first paint (index.html puts
 * is-locked on the page when a lock is set), then taken out of reach (inert). */
html.is-locked .app-header, html.is-locked #view-container, html.is-locked #tabs { visibility: hidden; }
.lock { position: fixed; inset: 0; z-index: 10000; display: grid; place-items: center; padding: var(--k-4); overflow-y: auto; background: var(--k-bg); color: var(--k-text); }
.lock__box { position: relative; width: min(100%, 320px); display: grid; justify-items: center; gap: var(--k-3); text-align: center; }
.lock__cancel { position: absolute; top: -8px; right: -8px; width: 44px; height: 44px; display: grid; place-items: center; border: 0; border-radius: 50%; background: none; color: var(--k-text-2); }
.lock__mark { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 16px; color: var(--k-accent-text); background: color-mix(in srgb, var(--k-accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--k-accent) 30%, transparent); }
.lock__mark svg { width: 26px; height: 26px; }
.lock__title { margin: 4px 0 0; font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
.lock__sub { margin: 0; min-height: 1.4em; font-size: var(--k-label); color: var(--k-text-2); }
.lock__sub.is-error { color: var(--k-negative); }
.lock__dots { display: flex; gap: 14px; margin: 8px 0 6px; }
.lock__dots i { width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--k-text-3); transition: background-color var(--k-t-fast) var(--k-ease), border-color var(--k-t-fast) var(--k-ease); }
.lock__dots i.on { background: var(--k-accent); border-color: var(--k-accent); }
.lock__pad { display: grid; grid-template-columns: repeat(3, 72px); gap: 12px; justify-content: center; }
.lock__key { width: 72px; height: 64px; display: grid; place-items: center; border: 1px solid var(--k-border); border-radius: 18px; background: var(--k-surface); color: var(--k-text); font: inherit; font-size: 24px; font-weight: 500; font-variant-numeric: tabular-nums; }
.lock__key:active { background: var(--k-surface-press); }
.lock__key svg { width: 22px; height: 22px; }
.lock__next { width: 100%; min-height: 48px; }
.lock__link { min-height: 44px; padding: 0 var(--k-3); border: 0; background: none; color: var(--k-accent-text); font: inherit; font-size: var(--k-label); font-weight: 600; }
.lock :is(button):focus-visible { outline: 2px solid var(--k-accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .lock__dots.shake { animation: none; } }
@media (max-height: 640px) { .lock__key { height: 54px; } .lock__mark { display: none; } }
.k.settings-k .settings-lock-note { margin: 0; padding: var(--k-2) 0 var(--k-3); border-top: 1px solid var(--k-hairline); }

/* --- Card smarts (5.32): quiet lines under a card's bar ---------------------- */
.k .card-facts { display: grid; gap: 2px; padding: 0 0 var(--k-3); }
.k .card-facts p, .k .bill-payby { margin: 0; font-size: 12px; color: var(--k-text-2); }
.k .bill-payby { padding: 0 0 var(--k-2); }
.k .bill-payby.is-overdue { color: var(--k-negative); }

/* What you did not spend, in the month in review (5.32): a name, its figures, what was left. */
.recap-flex { list-style: none; margin: var(--k-3) 0 0; padding: 0; display: grid; }
.recap-flex li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0 var(--k-3); padding: var(--k-2) 0; border-top: 1px solid var(--k-hairline); }
.recap-flex__name { font-weight: 600; color: var(--k-text); }
.recap-flex small { grid-column: 1; font-size: 12px; color: var(--k-text-2); }
.recap-flex b { grid-row: 1 / span 2; grid-column: 2; align-self: center; font-variant-numeric: tabular-nums; color: var(--k-positive); }
.recap-flex b.out { color: var(--k-negative); }

/* --- a sheet is pulled down to close (5.36): the grip and the title row are the handle ----- */
.k-sheet__grip.is-handle, .k-sheet__head.is-handle { touch-action: none; cursor: grab; }
.k-sheet__grip.is-handle { position: relative; }
.k-sheet__grip.is-handle::after { content: ''; position: absolute; inset: -14px -48px; }

/* ======================================================================
   Motion (5.37). Corporate-premium: short, decelerating in, accelerating out, only transform
   and opacity moving. Every rule that moves has a reduced-motion answer at the end.
   ====================================================================== */

/* 1. A button answers a press: it sinks a little and darkens, then comes back. */
.btn-primary, .btn-secondary, .btn-tiny, .k-btn, .dir-btn, .plan-chip, .lock__key {
  transition-property: transform, filter, background-color, border-color, box-shadow, color;
  transition-duration: 120ms;
  transition-timing-function: var(--k-ease, cubic-bezier(0.16, 1, 0.3, 1));
}
.btn-primary:active:not(:disabled), .btn-secondary:active:not(:disabled), .btn-tiny:active:not(:disabled),
.k-btn:active:not(:disabled), .dir-btn:active, .plan-chip:active, .lock__key:active {
  transform: scale(0.97);
  filter: brightness(0.9);
  transition-duration: 60ms;
}
/* 4. The switch's thumb squashes a touch under the finger; thumb and track share one time and curve. */
.k-toggle::after { transition-property: transform, background, scale; }
.k-toggle:active::after { scale: 1.1 1; }

/* 5. A PIN dot pops as it fills; a right PIN turns the dots green before the lock lets go. */
@keyframes dot-pop { 0% { transform: scale(0.7); } 60% { transform: scale(1.12); } 100% { transform: scale(1); } }
.lock__dots i.on { animation: dot-pop 140ms var(--k-ease) both; }
.lock.is-ok .lock__dots i.on { background: var(--k-positive); border-color: var(--k-positive); }
@keyframes lock-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-9px); } 40% { transform: translateX(8px); } 60% { transform: translateX(-5px); } 80% { transform: translateX(2px); }
}
.lock__dots.shake { animation: lock-shake 320ms cubic-bezier(0.65, 0, 0.35, 1); }

/* 23. After the right PIN the lock fades and the app clears from a soft blur instead of cutting. */
.lock.is-leaving { pointer-events: none; animation: lock-leave 300ms cubic-bezier(0.7, 0, 0.84, 0) 120ms both; }
@keyframes lock-leave { to { opacity: 0; } }
@keyframes app-unveil { from { opacity: 0; transform: scale(1.02); filter: blur(8px); } to { opacity: 1; transform: none; filter: blur(0); } }
@media (prefers-reduced-motion: no-preference) {
  html.is-unveiling .app-header, html.is-unveiling #view-container, html.is-unveiling #tabs { animation: app-unveil 380ms var(--k-ease) 160ms both; }
}

/* 6. The toast rises in (220 ms) and drops out (160 ms); a hairline counts down the two seconds it stays. */
.toast { overflow: hidden; transition: opacity 160ms cubic-bezier(0.7, 0, 0.84, 0), transform 160ms cubic-bezier(0.7, 0, 0.84, 0); transform: translateX(-50%) translateY(12px); }
.toast.visible { transition: opacity 220ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)), transform 220ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)); }
.toast__bar { position: absolute; left: 0; bottom: 0; height: 2px; width: 100%; background: color-mix(in srgb, var(--accent-ink, #000) 35%, transparent); transform-origin: left; animation: toast-run 2000ms linear 220ms both; }
@keyframes toast-run { to { transform: scaleX(0); } }

/* 17. A sheet opens in stages: the dim, the sheet rising, then its rows one after another. */
@keyframes sheet-dim { from { opacity: 0; } }
@keyframes sheet-row { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: no-preference) {
  #month-sheet .k-scrim, #quick-sheet .k-scrim, #add-cat-sheet .k-scrim { animation: sheet-dim 200ms var(--k-ease) both; }
  #month-sheet .k-rows > *, #quick-sheet .k-rows > *, #add-cat-sheet .k-cat-row { animation: sheet-row 220ms var(--k-ease) both; animation-delay: calc(180ms + var(--r, 0) * 40ms); }
  #month-sheet .k-rows > :nth-child(2), #quick-sheet .k-rows > :nth-child(2), #add-cat-sheet .k-cat-row:nth-child(2) { --r: 1; }
  #month-sheet .k-rows > :nth-child(3), #quick-sheet .k-rows > :nth-child(3), #add-cat-sheet .k-cat-row:nth-child(3) { --r: 2; }
  #month-sheet .k-rows > :nth-child(4), #quick-sheet .k-rows > :nth-child(4), #add-cat-sheet .k-cat-row:nth-child(4) { --r: 3; }
  #month-sheet .k-rows > :nth-child(n+5), #quick-sheet .k-rows > :nth-child(n+5), #add-cat-sheet .k-cat-row:nth-child(n+5) { --r: 4; }
}

/* 18. Press and hold a payment: it sinks and a hairline fills along its edge, so the menu is expected. */
.k .hist-row { position: relative; }
.k .hist-row.is-pressing { transform: scale(0.985); transition: transform 160ms var(--k-ease); }
.k .hist-row.is-pressing::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--k-accent); transform-origin: left; animation: press-fill 480ms linear both; }
@keyframes press-fill { from { transform: scaleX(0); } }

/* 2. Saved: the ring and tick draw themselves, the word follows. */
@keyframes tick-ring { from { stroke-dashoffset: 57; } }
@keyframes tick-mark { from { stroke-dashoffset: 14; } }
@keyframes saved-pop { from { transform: scale(0.92); } }
@keyframes saved-word { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: no-preference) {
  .k .add-form .btn-primary.is-saved { animation: saved-pop 300ms var(--k-ease) both; }
  .k .add-form .btn-primary.is-saved .icon circle { stroke-dasharray: 57; animation: tick-ring 300ms var(--k-ease) both; }
  .k .add-form .btn-primary.is-saved .icon path { stroke-dasharray: 14; animation: tick-mark 200ms var(--k-ease) 260ms both; }
  .k .add-form .btn-primary.is-saved span { animation: saved-word 240ms var(--k-ease) 380ms both; }
}

/* 3. A value that will not do: the field shakes once and says why, in words under it. */
@keyframes field-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-8px); } 40% { transform: translateX(7px); } 60% { transform: translateX(-4px); } 80% { transform: translateX(2px); }
}
@keyframes field-error-in { from { opacity: 0; transform: translateY(-4px); } }
.is-invalid { border-color: var(--k-negative, #d44) !important; }
/* a field with no border of its own (the import review's boxes) still has to show it is refused */
.import-row .ir-field.is-invalid, .split-row .split-amount.is-invalid { box-shadow: inset 0 0 0 2px var(--k-negative, #d44) !important; }
/* History's amount box keeps its border on the label around it, so the label turns red */
.hist-amount:has(.is-invalid) { border-color: var(--k-negative, #d44) !important; box-shadow: 0 0 0 1px var(--k-negative, #d44); }
.is-shaking { animation: field-shake 320ms cubic-bezier(0.65, 0, 0.35, 1); }
.field-error { margin: 6px 0 0; font-size: var(--k-label, 13px); color: var(--k-negative, #d44); animation: field-error-in 200ms var(--k-ease, ease-out) both; }

@media (prefers-reduced-motion: reduce) {
  .btn-primary:active:not(:disabled), .btn-secondary:active:not(:disabled), .btn-tiny:active:not(:disabled), .k-btn:active:not(:disabled), .dir-btn:active, .plan-chip:active, .lock__key:active { transform: none; }
  .k-toggle:active::after { scale: none; }
  .lock__dots i.on, .lock__dots.shake, .is-shaking, .toast__bar, .k .hist-row.is-pressing::after { animation: none; }
  .lock.is-leaving { animation: lock-leave 160ms linear both; }
  .k .hist-row.is-pressing { transform: none; }
}

/* 24. The message lights up as its fields land: each word glows as its field arrives, 80 ms apart. */
.alert-sms { margin: 8px 0 4px; padding: 8px 10px; font-size: var(--k-label, 13px); line-height: 1.45; color: var(--k-text-2); background: color-mix(in srgb, var(--k-text) 5%, transparent); border-radius: 6px; overflow: hidden; overflow-wrap: anywhere; }
.alert-sms mark { background: transparent; color: var(--k-text); border-radius: 3px; animation: sms-glow 700ms linear calc(var(--k, 0) * 80ms) both; }
@keyframes sms-glow { 0%, 100% { background-color: transparent; } 50% { background-color: color-mix(in srgb, var(--k-accent) 35%, transparent); } }
.alert-card.is-fresh .field::after, .alert-card.is-fresh .alert-amount::after { animation-delay: calc(var(--i, 0) * 80ms + 340ms); }
@media (prefers-reduced-motion: reduce) { .alert-sms mark { animation: none; } }

/* 25. A purchase and the refund that undid it: a tag says so (js/views/transactions.js); the icon and amount are in fit.css. */

/* 26. A slow screen: grey shapes where the figures will be, one shimmer crossing them all together. */
.view-skeleton { display: grid; gap: 14px; justify-items: center; align-content: start; padding: 28px 16px; }
.view-skeleton { position: absolute; inset: 0; background: var(--k-bg, var(--bg)); z-index: 2; }
.view-skeleton .sk { display: block; border-radius: 6px; background-color: var(--k-surface-elev, #2a2f38); background-image: linear-gradient(100deg, transparent 30%, rgb(255 255 255 / 0.1) 50%, transparent 70%); background-size: 60vw 100%; background-repeat: no-repeat; background-attachment: fixed; animation: sk-sweep 1600ms linear infinite; }
.view-skeleton .sk--cap { width: 90px; height: 12px; }
.view-skeleton .sk--fig { width: 170px; height: 40px; }
.view-skeleton .sk--line { width: 220px; height: 12px; }
.view-skeleton .sk--card { width: min(100%, 420px); height: 84px; border-radius: 12px; }
@keyframes sk-sweep { from { background-position: -60vw 0; } to { background-position: 160vw 0; } }
@media (prefers-reduced-motion: reduce) { .view-skeleton .sk { animation: none; background-image: none; } }

/* 22. A goal that is reached: the ring draws to its end, a tick badge draws, one ripple leaves the ring. */
@keyframes ring-draw { from { stroke-dasharray: 0 999; } }
@keyframes badge-tick { from { stroke-dashoffset: 14; } }
@keyframes ring-ripple { from { opacity: 0.7; transform: scale(1); } to { opacity: 0; transform: scale(1.35); } }
.goal-ring__done circle { fill: var(--k-positive); }
.goal-ring__done path { stroke: var(--k-bg, #000); stroke-width: 2.2; stroke-dasharray: 14; }
.goal-ring__ripple { stroke: var(--k-positive); stroke-width: 2; opacity: 0; transform-box: fill-box; transform-origin: center; }
.goal-ring.is-done .chart-ring-fill { stroke: var(--k-positive); }
@media (prefers-reduced-motion: no-preference) {
  .is-arriving .goal-ring .chart-ring-fill { animation: ring-draw 600ms var(--k-ease-io) both; }
  .is-arriving .goal-ring__done { animation: saved-pop 300ms var(--k-ease) 560ms both; }
  .is-arriving .goal-ring__done path { animation: badge-tick 260ms var(--k-ease) 600ms both; }
  .is-arriving .goal-ring__ripple { animation: ring-ripple 600ms var(--k-ease) 560ms both; }
}

/* Coach: the questions arrive one after another, 50 ms apart, top first. */
@keyframes coach-in { from { opacity: 0; transform: translateY(12px); } }
@media (prefers-reduced-motion: no-preference) {
  .k-coach.is-arriving .coach-q, .k-coach.is-arriving #coach-panel { animation: coach-in 240ms var(--k-ease) both; animation-delay: calc(var(--c, 0) * 50ms); }
  .k-coach.is-arriving .coach-q:nth-child(2) { --c: 1; } .k-coach.is-arriving .coach-q:nth-child(3) { --c: 2; }
  .k-coach.is-arriving .coach-q:nth-child(4) { --c: 3; } .k-coach.is-arriving .coach-q:nth-child(n+5) { --c: 4; }
  .k-coach.is-arriving #coach-panel { --c: 5; }
}

/* A chosen quick chip gives one small pop as it lights. */
@keyframes chip-pop { 0% { transform: scale(0.94); } 60% { transform: scale(1.05); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: no-preference) { .k .k-quick__chip.on { animation: chip-pop 160ms var(--k-ease) both; } }

/* Pull to refresh: the sync icon above the screen, turning anticlockwise as far as you pull. */
.ptr { position: fixed; left: 50%; top: calc(var(--header-h, 64px) + 4px); z-index: 20; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; background: var(--k-surface, var(--surface)); border: 1px solid var(--k-hairline, var(--border)); color: var(--k-text-2, var(--text-dim)); opacity: 0; pointer-events: none; transform: translate(-50%, 0); }
.ptr .icon { width: 18px; height: 18px; }
.ptr__arrows, .ptr__tick { position: absolute; inset: 0; display: grid; place-items: center; }
.ptr__tick { opacity: 0; color: var(--k-positive, #3ddc97); }
.ptr.is-busy .ptr__arrows { animation: sync-turn 1000ms linear infinite; }
.ptr.is-done .ptr__arrows { opacity: 0; transition: opacity 160ms ease-in; }
.ptr.is-done .ptr__tick { opacity: 1; animation: sync-ok 300ms var(--k-ease) both; }
html { overscroll-behavior-y: contain; }

/* The big title shrinks into the header as the screen scrolls (scroll-linked, so it is the finger's motion). */
.app-header { --shrink: 0; }
.app-header h1 { transform-origin: left center; transform: scale(calc(1 - var(--shrink) * 0.22)); }
.app-header::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--k-hairline, var(--border)); opacity: var(--shrink); pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .app-header h1 { transform: none; } .ptr__arrows { transition: none; } }

/* ======================================================================
   What was spent outside the budget, on every look (5.38): hatched, as Instrument had it since 5.33.
   ====================================================================== */
.k .waves__other { stroke: none; opacity: 0.85; }
.k .waves__hatch, .k .scale__hatch { stroke: var(--k-text-2); stroke-width: 1.4; }
.k .waves__note { display: flex; align-items: flex-start; gap: 8px; margin: 8px var(--k-4) 0; font-size: var(--k-caption); line-height: 1.4; color: var(--k-text-2); }
.k .waves__note i { flex: none; width: 12px; height: 8px; margin-top: 4px; border-radius: 2px; background: repeating-linear-gradient(135deg, color-mix(in srgb, var(--k-text) 34%, transparent) 0 2px, transparent 2px 4px); }

.k .pills-note { margin: 10px 0 0; }
/* Charts: a hatched block above a day's pill. */
.k .pill-col i.pill-other { background: repeating-linear-gradient(135deg, color-mix(in srgb, var(--k-text) 34%, transparent) 0 2px, transparent 2px 4px); box-shadow: none; min-height: 3px; border-radius: 3px; }
.k .pill-col i.pill-other.is-cut { clip-path: polygon(0 4px, 25% 0, 50% 4px, 75% 0, 100% 4px, 100% 100%, 0 100%); }
/* Tactile: the week strip's hatched part and its key, as on Instrument. */

/* ======================================================================
   Motion on every look (5.38): what Instrument had since 5.36 and 5.37, now the same on all.
   ====================================================================== */

/* A closed month with money to spare says so, and its card takes one soft glow. */
.k .closed-note { margin: 10px 0 0; font-size: var(--k-label); color: var(--k-text-2); }
.k .closed-note b { color: var(--k-positive); font-weight: var(--k-w-strong, 700); }
@keyframes closed-word { from { opacity: 0; transform: translateY(6px); } }
@keyframes closed-glow { 50% { box-shadow: 0 0 26px color-mix(in srgb, var(--k-positive) 38%, transparent); } }
@media (prefers-reduced-motion: no-preference) {
  .is-arriving .closed-note { animation: closed-word 280ms var(--k-ease) 900ms backwards; }
  .is-arriving .is-closed-under:not(.in-hero) { animation: closed-glow 900ms var(--k-ease-io) 600ms both; }
}
/* One soft ring when the month turns worse (the figure's own colour is animated by script). */
.pace-pulse { position: absolute; border: 2px solid var(--k-negative); border-radius: 10px; pointer-events: none; }
/* While a figure rolls, the bars and arcs that draw it follow it directly: no transition of their own. */
[data-roll-scope].is-rolling [data-follow] { transition: none !important; }

/* The waves draw themselves once per arrival, as Instrument's ruled chart does. */
@keyframes line-draw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes bar-rise { from { transform: scaleY(0); } }
@keyframes dot-land { from { opacity: 0; } }
@keyframes fill-in-soft { from { opacity: 0; } }

.k .waves-card:not(.scale-card).is-armed .waves__bar, .k .waves-card:not(.scale-card).is-armed .waves__other { transform-box: fill-box; transform-origin: 50% 100%; transform: scaleY(0); }
.k .waves-card:not(.scale-card).is-armed .waves--spent.waves__line { stroke-dasharray: 100; stroke-dashoffset: 100; }
.k .waves-card:not(.scale-card).is-armed .waves__fill, .k .waves-card:not(.scale-card).is-armed .waves__dot { opacity: 0; }
.k .waves-card:not(.scale-card).is-drawing .waves__bar, .k .waves-card:not(.scale-card).is-drawing .waves__other { transform-box: fill-box; transform-origin: 50% 100%; animation: bar-rise 300ms var(--k-ease) var(--d, 0ms) backwards; }
.k .waves-card:not(.scale-card).is-drawing .waves--spent.waves__line { stroke-dasharray: 100; stroke-dashoffset: 0; animation: line-draw 700ms linear 160ms backwards; }
.k .waves-card:not(.scale-card).is-drawing .waves__fill { animation: fill-in-soft 600ms linear 400ms backwards; }
.k .waves-card:not(.scale-card).is-drawing .waves__dot { animation: dot-land 120ms linear 860ms backwards; }
/* Scrubbing glides on every look: the guide and the dot move, the picked bar lifts. */
.k .waves__guide, .k .waves__dot { transition: transform 120ms var(--k-ease); }
.k .waves__bar { transition: transform 120ms var(--k-ease); }
.k .waves__bar.is-picked { transform: translateY(-3px); }

/* The lit mark of the tab bar and the lit choice of a toggle glide on every look; each look dresses them below. */
#tabs .nav-ind { display: none; }
.seg-pill { display: none; }
.k .has-pill { position: relative; }
.k .has-pill .seg-pill { display: block; position: absolute; top: 0; left: 0; width: var(--w, 0); height: var(--h, 0); transform: translate(var(--x, 0), var(--y, 0)); border-radius: var(--r, 999px); background: color-mix(in srgb, var(--k-accent) 15%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--k-accent) 38%, transparent); pointer-events: none; }
.k .has-pill .seg-pill.is-ready { transition: transform 200ms var(--k-ease), width 200ms var(--k-ease), height 200ms var(--k-ease); }
.k .has-pill .dir-btn, .k .has-pill .k-seg__btn { position: relative; z-index: 1; }
.k .has-pill .dir-btn.active, .k .has-pill .k-seg__btn[aria-selected="true"] { background: transparent !important; box-shadow: none !important; }
@media (prefers-reduced-motion: reduce) { .k .has-pill .seg-pill.is-ready { transition: none; } }

/* Charts (5.38.1): the lit tab's mark is a short bar that glides, in the style's accent. */
:root:not([data-style]) #tabs .nav-ind { display: block; position: absolute; bottom: 2px; left: 0; width: 16px; height: 2px; border-radius: 1px; background: var(--k-accent); box-shadow: 0 0 6px var(--k-accent); transform: translateX(calc(var(--x, 0px) + var(--w, 0px) / 2 - 8px)); pointer-events: none; }
:root:not([data-style]) #tabs .nav-ind.is-ready { transition: transform 280ms var(--k-ease); }
:root:not([data-style]) #tabs .nav-btn { transition: color 280ms var(--k-ease); }
@media (prefers-reduced-motion: reduce) { :root:not([data-style]) #tabs .nav-ind.is-ready, :root:not([data-style]) #tabs .nav-btn { transition: none; } }

/* ======================================================================
   Demo mode (5.40): the ribbon that is always there. One fixed colour in every look, so it can
   never be mistaken for the look's own accent: this is not your money.
   ====================================================================== */
:root { --demo-h: 0px; }
body.has-demo { --demo-h: calc(30px + env(safe-area-inset-top, 0px)); padding-top: var(--demo-h); }
.has-demo .app-header { top: var(--demo-h); padding-top: var(--space-md); }
.is-demo #update-banner { display: none !important; }
.demo-ribbon {
  position: fixed; top: 0; left: 0; right: 0; z-index: 9000;
  height: var(--demo-h); box-sizing: border-box; padding: env(safe-area-inset-top, 0px) 14px 0;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: #ffcf4a; color: #1a1400; border-bottom: 1px solid rgb(0 0 0 / 0.25);
  font: 600 11.5px/1 var(--font-body, system-ui); letter-spacing: 0.04em;
}
.demo-ribbon b { letter-spacing: 0.12em; }
.demo-ribbon__leave { min-height: 44px; margin: -8px 0; border: 0; background: none; color: inherit; font: inherit; text-decoration: underline; text-underline-offset: 3px; padding: 0 0 0 12px; }
.demo-ribbon__leave:focus-visible { outline: 2px solid #1a1400; outline-offset: -4px; }
.demo-card .btn-block { margin-top: 10px; }

/* --- the guide (5.41): one sentence at a time above the tab bar, and a ring on what to touch -------- */
.has-coach :is(#view-container, .view-still) { padding-bottom: calc(var(--coach-h, 170px) + var(--nav-height, 64px) + 24px); }
.demo-ring {
  position: fixed; z-index: 8000; pointer-events: none; border-radius: 18px;
  outline: 2px solid var(--k-accent, #ffb020);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--k-accent, #ffb020) 22%, transparent), 0 0 28px color-mix(in srgb, var(--k-accent, #ffb020) 40%, transparent);
  transition: top 160ms var(--k-ease, ease), left 160ms var(--k-ease, ease), width 160ms var(--k-ease, ease), height 160ms var(--k-ease, ease);
}
.demo-coach {
  position: fixed; z-index: 8500; left: 12px; right: 12px; bottom: calc(var(--nav-height, 64px) + 14px);
  display: grid; gap: 10px; padding: 14px 14px 12px; border-radius: 20px;
  background: var(--k-bg-elev, #14181d); color: var(--k-text, #fff);
  border: 1px solid var(--k-hairline, rgb(255 255 255 / 0.12)); box-shadow: 0 14px 40px rgb(0 0 0 / 0.45);
  max-width: 560px; margin-inline: auto;
}
.demo-coach__top { display: flex; justify-content: space-between; align-items: center; font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--k-text-3, #8a94a0); }
.demo-coach__skip { min-height: 44px; margin: -12px 0; border: 0; background: none; color: inherit; font: inherit; text-transform: none; letter-spacing: 0; text-decoration: underline; text-underline-offset: 3px; padding: 0 0 0 10px; }
.demo-coach__say { margin: 0; font-size: 16.5px; line-height: 1.4; font-weight: 600; letter-spacing: -0.01em; text-wrap: balance; }
.demo-coach__say small { display: block; margin-top: 4px; font-weight: 400; font-size: 13.5px; color: var(--k-text-2, #b2bcc6); }
.demo-coach__bar { height: 3px; border-radius: 2px; background: color-mix(in srgb, var(--k-text, #fff) 12%, transparent); overflow: hidden; }
.demo-coach__bar i { display: block; height: 100%; width: var(--p, 10%); background: var(--k-accent, #ffb020); border-radius: 2px; transition: width 240ms var(--k-ease, ease); }
.demo-coach__actions { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.demo-coach__back { min-height: 44px; border: 0; background: none; color: var(--k-text-2, #b2bcc6); font: 600 14px/1 inherit; padding: 0 8px; }
.demo-coach__next { min-height: 44px; padding: 0 22px; border: 0; border-radius: 14px; background: var(--k-accent, #ffb020); color: var(--k-accent-ink, #111); font: 700 14.5px/1 inherit; }
.demo-coach__wait { font-size: 13px; color: var(--k-text-2, #b2bcc6); display: inline-flex; align-items: center; gap: 8px; }
.demo-coach__wait::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: var(--k-accent, #ffb020); box-shadow: 0 0 0 4px color-mix(in srgb, var(--k-accent, #ffb020) 25%, transparent); }
.demo-end__row { display: grid; gap: 8px; }
.demo-end__row button { min-height: 44px; border-radius: 14px; border: 1px solid var(--k-hairline, rgb(255 255 255 / 0.18)); background: none; color: inherit; font: 600 14.5px/1 inherit; }
.demo-end__row .primary { background: var(--k-accent, #ffb020); color: var(--k-accent-ink, #111); border-color: transparent; }
.demo-end__leave { min-height: 44px; border: 0; background: none; color: var(--k-text-3, #8a94a0); text-decoration: underline; text-underline-offset: 3px; font: inherit; font-size: 13px; justify-self: center; }
@keyframes coach-rise { from { opacity: 0; transform: translateY(14px); } }
@keyframes ring-appear { from { opacity: 0; transform: scale(0.97); } }
@media (prefers-reduced-motion: no-preference) {
  .demo-coach { animation: coach-rise 240ms var(--k-ease, ease) both; }
  .demo-ring:not([hidden]) { animation: ring-appear 200ms var(--k-ease, ease) both; }
}
@media (prefers-reduced-motion: reduce) { .demo-ring, .demo-coach__bar i { transition: none; } }
