/* One Quarter — soft-pill UI, light and dark. */

/* Self-hosted so the app makes no third-party requests. One variable file per
   subset covers weights 400–800; latin-ext handles accented names. */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/fonts/plus-jakarta-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/fonts/plus-jakarta-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Bottle green, red orange, rodeo dust and dawn pink. Cream is the ground,
     green is the structure, orange is the one loud thing on any screen. */
  --bg: #f0ebe3;            /* dawn pink */
  --surface: #fffdfa;
  --surface-2: #e8dfd2;     /* rodeo dust, at rest */
  --surface-3: #dbcfbd;
  --ink: #12211c;           /* green-black, never neutral */
  --ink-2: #33463f;
  --muted: #6d7d76;
  --faint: #9aa8a1;

  --accent: #f9461c;        /* red orange */
  /* Small bold white-on-orange sits at 3.7:1 — under AA. Anything carrying
     text uses the deeper tone, which clears it at 4.7:1. */
  --accent-deep: #d33c10;
  --accent-ink: #ffffff;
  --accent-wash: #fde5dc;

  /* dust to orange, palest to strongest, for the progress blocks */
  --l1: #efe4d7;
  --l2: #e8c9b2;
  --l3: #f08a5f;
  --l4: #f9461c;

  --contrast: #0f3b2e;      /* bottle green — the dark pill */
  --contrast-ink: #f0ebe3;

  --wa: #1fa855;            /* WhatsApp's own green, not ours */
  --wa-ink: #ffffff;
  --ok: #1c7d55;
  --ok-wash: #e2efe8;
  --warn: #a8600c;
  --warn-wash: #f9ecd9;
  /* A deep maroon, deliberately far from the orange: a fine must never read
     as the primary action. */
  --danger: #9e2b20;
  --danger-wash: #f7e3df;

  --line: #ded4c6;          /* hairline between rows in a list */
  /* The bottom bar is bottle green in both themes: it is the one piece of
     furniture that should not change when the lights go out. */
  --nav: #0f3b2e;
  --nav-ink: #f0ebe3;

  --r-card: 24px;
  --r-mid: 18px;
  --r-input: 15px;
  --r-pill: 999px;

  --shadow: 0 2px 4px rgba(18, 33, 28, .04), 0 12px 32px -16px rgba(18, 33, 28, .18);
  --shadow-lift: 0 8px 28px -10px rgba(211, 60, 16, .45);

  --font: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* The same four colours after dark: the green becomes the ground, the
       cream becomes the ink, and the orange lifts so it still reads as loud. */
    --bg: #0c1613;
    --surface: #14211d;
    --surface-2: #1d2b26;
    --surface-3: #27362f;
    --ink: #f0ebe3;
    --ink-2: #d9d2c7;
    --muted: #9aa8a1;
    --faint: #6f7d76;

    --accent: #ff6a3d;
    --accent-deep: #ff8963;
    /* Dark ink on orange, not white: white sits at 2.9:1 on this. */
    --accent-ink: #1a0d07;
    --accent-wash: #33190f;

    --l1: #241d19;
    --l2: #3d2a20;
    --l3: #a8492a;
    --l4: #ff6a3d;

    --contrast: #f0ebe3;
    --contrast-ink: #12211c;

    --wa: #25d366;
    --wa-ink: #0d2716;
    --ok: #4ade80;
    --ok-wash: #14291f;
    --warn: #fbbf24;
    --warn-wash: #322610;
    --danger: #f08a7e;
    --danger-wash: #341814;

    --line: #26332d;
    --nav: #16382c;
    --nav-ink: #f0ebe3;

    --shadow: 0 2px 4px rgba(0, 0, 0, .3), 0 12px 32px -16px rgba(0, 0, 0, .7);
    --shadow-lift: 0 8px 28px -10px rgba(255, 106, 61, .32);
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -.01em;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

body { min-height: 100dvh; }

/* Must beat any component rule that sets `display` — .modal is display:flex, and
   an author rule outranks the browser's own [hidden] { display: none }. */
[hidden] { display: none !important; }

h1, h2, h3 { margin: 0; line-height: 1.1; font-weight: 700; letter-spacing: -.03em; }
h1 { font-size: 2rem; }
h2 { font-size: 1.3rem; letter-spacing: -.025em; }
h3 { font-size: 1.05rem; letter-spacing: -.02em; }
p { margin: 0 0 .75rem; }
p:last-child { margin-bottom: 0; }
a { color: var(--accent-deep); }

/* ---------------------------------------------------------------- layout */

.app { max-width: 640px; margin: 0 auto; padding: 0 18px calc(112px + env(safe-area-inset-bottom)); }
.boot { display: grid; place-items: center; min-height: 60dvh; }

.spinner {
  width: 26px; height: 26px; border-radius: 50%;
  border: 3px solid var(--surface-2); border-top-color: var(--accent);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Greeting-style header: big, tight, mixed weight. */
.topbar {
  display: flex; align-items: flex-start; gap: 12px;
  padding: calc(22px + env(safe-area-inset-top)) 0 18px;
}
.topbar__title { flex: 1; min-width: 0; }
.topbar__title h1 {
  font-size: clamp(1.7rem, 7vw, 2.3rem); font-weight: 500;
  /* Wrap to two lines rather than clipping — group names get long. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere; text-wrap: balance;
}
.topbar__title h1 b { font-weight: 800; }
.topbar__title .sub { font-size: .88rem; color: var(--muted); margin-top: 4px; font-weight: 500; }

.iconbtn {
  flex: none; width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: var(--surface); border: 0; color: var(--ink);
  font-size: 1.05rem; box-shadow: var(--shadow); font-family: inherit;
}
.iconbtn:active { transform: scale(.94); }

.stack { display: grid; gap: 12px; }
/* Grid items default to min-width:auto, so ONE nowrap child — a truncating
   goal title, a long email — widens the whole track and pushes the card past
   the screen. `.truncate` cannot save it: the row it sits in is the grid item.
   This is what made the Team page scroll sideways once people had real goals. */
.stack > * { min-width: 0; }
.row { display: flex; align-items: center; gap: 10px; }
.row--wrap { flex-wrap: wrap; }
.row--between { justify-content: space-between; }
.grow { flex: 1; min-width: 0; }
.right { margin-left: auto; }
.center { text-align: center; }
.muted { color: var(--muted); }
.small { font-size: .84rem; }
.tiny { font-size: .75rem; }
.strong { font-weight: 700; }
/* Monospaced runs are usually URLs and codes, which have no spaces to break
   at — left alone, one of them pushes the whole page sideways on a 320px
   phone. */
.mono { font-family: var(--mono); overflow-wrap: anywhere; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A member row carries up to three buttons. On a wide screen they sit beside
   the name; on a phone they would squeeze it to nothing — an email truncated
   to "katiede…" — so they drop to their own line instead, indented past the
   avatar so the row still reads as one person. */
.member {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 0; border-bottom: 1px solid var(--line);
}
.member:last-child { border-bottom: 0; padding-bottom: 0; }
.member__who { flex: 1 1 120px; min-width: 0; }
.member__actions { display: flex; gap: 8px; margin-left: auto; }
@media (max-width: 460px) {
  .member__actions { flex-basis: 100%; margin-left: 42px; }
}
/* A list of places to go, one per row, each with a line saying what is there. */
.menu { display: flex; flex-direction: column; }
.menu-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 12px 2px; min-height: 56px;
  font: inherit; color: var(--ink); text-align: left;
  background: none; border: 0; border-bottom: 1px solid var(--line); cursor: pointer;
}
.menu-row:last-child { border-bottom: 0; }
a.menu-row { text-decoration: none; }
.menu-row__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.menu-row svg { width: 18px; height: 18px; color: var(--muted); flex: none; }
.hide { display: none !important; }

/* ----------------------------------------------------------------- cards */

.card {
  background: var(--surface);
  border: 0;
  border-radius: var(--r-card);
  padding: 20px;
  box-shadow: var(--shadow);
}
.card--flat { box-shadow: none; background: var(--surface-2); }
.card--sunk { background: var(--surface-2); box-shadow: none; }
.card--accent {
  background: var(--accent); color: var(--accent-ink);
  box-shadow: var(--shadow-lift);
}
.card--accent .muted, .card--accent .tiny { color: color-mix(in srgb, var(--accent-ink) 72%, transparent); }
.card__head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.card__head h2, .card__head h3 { flex: 1; min-width: 0; }

.section-title {
  font-size: .72rem; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint); margin: 10px 4px 2px;
}

.empty { padding: 34px 18px; text-align: center; color: var(--muted); }
.empty__emoji { font-size: 2.1rem; display: block; margin-bottom: 10px; }

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

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 20px; min-height: 48px;
  font: inherit; font-weight: 700; font-size: .92rem; letter-spacing: -.01em;
  border-radius: var(--r-pill); border: 0;
  background: var(--surface); color: var(--ink);
  cursor: pointer; text-decoration: none;
  box-shadow: var(--shadow);
  transition: transform .1s ease, background .15s ease;
}
.btn:active { transform: scale(.97); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn--primary { background: var(--accent-deep); color: var(--accent-ink); box-shadow: var(--shadow-lift); }
.btn--contrast { background: var(--contrast); color: var(--contrast-ink); }
.btn--wa { background: var(--wa); color: var(--wa-ink); box-shadow: none; }
.btn--danger { background: var(--danger-wash); color: var(--danger); box-shadow: none; }
.btn--ghost { background: transparent; color: var(--muted); box-shadow: none; font-weight: 600; }
.btn--quiet { background: var(--surface-2); box-shadow: none; }
/* A button that is present but not yet pressable — the update button on any
   day that is not update day. Reads as an outline, not as a faded mistake, so
   .btn:disabled's dimming is undone here. */
.btn--outline {
  background: transparent; color: var(--muted);
  box-shadow: none; border: 1.5px solid var(--line);
}
.btn--outline:disabled { opacity: 1; }
.btn--block { width: 100%; }
.btn--sm { min-height: 36px; padding: 7px 15px; font-size: .81rem; }
.btn--lg { min-height: 56px; font-size: 1rem; }
.btn-group { display: flex; gap: 9px; flex-wrap: wrap; }

/* Google's own button. Their mark is not allowed on a colour of our choosing,
   and a white button is the one people are looking for. */
.btn--google {
  background: #fff; color: #1f1f1f; border: 1px solid #dadce0; font-weight: 600;
}
.btn--google:hover { background: #f8f9fa; }

/* ---------------------------------------------------------------- inputs */

label.field { display: block; }
.field__label { display: block; font-size: .8rem; font-weight: 700; color: var(--muted); margin: 0 0 6px 6px; }
.field__hint { font-size: .78rem; color: var(--muted); margin: 6px 6px 0; }

/* Every input type the app uses. An omission here is invisible in review and
   obvious on screen: the control simply loses its styling, which is how a
   typeless input once rendered white on white in dark mode. */
input:not([type]), input[type=text], input[type=email], input[type=number], input[type=date],
input[type=datetime-local], input[type=url], input[type=search], select, textarea {
  width: 100%; padding: 13px 16px; min-height: 48px;
  font: inherit; font-weight: 500; color: var(--ink);
  background: var(--surface-2); border: 0; border-radius: var(--r-input);
  appearance: none;
}
::placeholder { color: var(--faint); }
textarea { min-height: 92px; resize: vertical; line-height: 1.5; border-radius: var(--r-mid); }
input:focus-visible, select:focus-visible, textarea:focus-visible,
.btn:focus-visible, .tick:focus-visible, .tab:focus-visible, .iconbtn:focus-visible, .navbar__item:focus-visible {
  outline: 2px solid var(--accent-deep); outline-offset: 2px;
}
input[inputmode=numeric] { font-variant-numeric: tabular-nums; }
/* Safari puts its own cancel button inside search fields, at its own size. */
input[type=search]::-webkit-search-decoration,
input[type=search]::-webkit-search-cancel-button { appearance: none; }
/* iOS draws a date's value centred, in a part of its own, so a date sat in the
   middle of a form whose every other field reads from the left. */
input[type=date], input[type=datetime-local] { text-align: left; }
input[type=date]::-webkit-date-and-time-value,
input[type=datetime-local]::-webkit-date-and-time-value { text-align: left; }

/* The invite link, shown rather than put in a field: an input one line wide
   cut it off at "…/joir", losing the code — the only part that differs — and
   looked like something to type into. Wraps instead; Copy takes the full URL. */
.invite-link {
  min-width: 0; padding: 11px 14px; border-radius: var(--r-input);
  background: var(--surface-2); color: var(--ink);
  font-family: var(--mono); font-size: .82rem; line-height: 1.45; overflow-wrap: anywhere;
}
/* The code stays whole: it is what people read out, and it has hyphens to break at. */
.invite-link b { font-weight: 700; white-space: nowrap; }

.code-input {
  font-family: var(--mono); font-size: 1.7rem; font-weight: 600; letter-spacing: .3em;
  text-align: center; padding: 16px 12px; min-height: 62px;
}

/* ---------------------------------------------------------------- pieces */

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 13px; border-radius: var(--r-pill);
  font-size: .76rem; font-weight: 700; letter-spacing: -.005em;
  background: var(--surface-2); color: var(--ink-2); white-space: nowrap;
}
.pill--brand    { background: var(--accent-wash); color: var(--accent-deep); }
.pill--contrast { background: var(--contrast); color: var(--contrast-ink); }
.pill--ok       { background: var(--ok-wash); color: var(--ok); }
.pill--warn     { background: var(--warn-wash); color: var(--warn); }
.pill--danger   { background: var(--danger-wash); color: var(--danger); }
.pill--ghost    { background: transparent; color: var(--muted); box-shadow: inset 0 0 0 1.5px var(--surface-3); }

.avatar {
  display: grid; place-items: center; flex: none;
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--surface-2); font-size: 1.2rem;
}
.avatar--sm { width: 30px; height: 30px; font-size: .95rem; }
/* A picture fills the circle; the emoji sizing above still applies when there
   is no picture. */
.avatar { overflow: hidden; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar--lg { width: 58px; height: 58px; font-size: 1.8rem; }

.banner {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 16px 18px; border-radius: var(--r-card);
  background: var(--surface-2); font-size: .9rem; font-weight: 500;
}
.banner--warn   { background: var(--warn-wash); color: var(--warn); }
.banner--danger { background: var(--danger-wash); color: var(--danger); }
.banner--ok     { background: var(--ok-wash); color: var(--ok); }
.banner--accent { background: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow-lift); }
.banner__icon { font-size: 1.2rem; line-height: 1.3; }
.banner strong { display: block; font-weight: 800; margin-bottom: 1px; }

.bar { height: 8px; border-radius: var(--r-pill); background: var(--surface-2); overflow: hidden; }
.bar__fill { height: 100%; background: var(--accent); border-radius: var(--r-pill); transition: width .3s ease; }
.bar__fill--ok { background: var(--ok); }
/* A bar that measures without judging: the board's non-leaders. Green is kept
   for a goal actually done, so it never reads as praise for 20%. */
.bar__fill--quiet { background: var(--muted); }

/* Thin part-filled rule under a card title, as in the reference. */
.rule { height: 3px; border-radius: var(--r-pill); background: var(--surface-2); margin-top: 10px; overflow: hidden; }
.rule > i { display: block; height: 100%; background: var(--ink); border-radius: var(--r-pill); }
.card--accent .rule { background: color-mix(in srgb, var(--accent-ink) 28%, transparent); }
.card--accent .rule > i { background: var(--accent-ink); }

.list { display: grid; gap: 10px; }
.list__item {
  background: var(--surface); border-radius: var(--r-card); padding: 16px 18px;
  display: flex; align-items: center; gap: 13px; box-shadow: var(--shadow);
  border: 0; width: 100%; text-align: left; font: inherit; color: var(--ink);
}
.list__item--link { cursor: pointer; }
.list__item--link:active { transform: scale(.99); }

/* ------------------------------------------------------------ goal ticks */

.goal { display: flex; align-items: center; gap: 14px; padding: 14px 0; }
.goal + .goal { border-top: 1.5px solid var(--surface-2); }
.goal__body { flex: 1; min-width: 0; }
.goal__title { font-weight: 700; letter-spacing: -.015em; }
.goal__meta { font-size: .78rem; color: var(--muted); font-weight: 500; }

.tick {
  flex: none; width: 52px; height: 52px; border-radius: var(--r-mid);
  border: 0; background: var(--surface-2);
  display: grid; place-items: center; cursor: pointer;
  font-family: inherit; font-size: 1.05rem; font-weight: 800; color: var(--faint);
  box-shadow: inset 0 0 0 2px var(--surface-3);
  transition: transform .12s ease, background .18s ease, color .18s ease, box-shadow .18s ease;
}
/* Untapped, the check is a ghost — present enough to read as a control. */
.tick[aria-pressed="false"] { color: color-mix(in srgb, var(--faint) 55%, transparent); }
.tick:active { transform: scale(.92); }
.tick[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow-lift); }
.tick--count { font-size: .9rem; font-variant-numeric: tabular-nums; }
.tick--count.partial { background: var(--l2); color: var(--accent-deep); }
.tick--count.full { background: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow-lift); }
.tick--count.partial, .tick--count.full { box-shadow: none; }
.tick--count.full { box-shadow: var(--shadow-lift); }

/* A goal as a week: the title, what it asks for, and seven days you tap. The
   count used to be one square that cycled 0→1→2→3; it recorded how many, never
   which, and "3 a week" is a thing you do on days. */
.goalcard { padding: 16px 0; }
.goalcard + .goalcard { border-top: 1.5px solid var(--surface-2); }
.goalcard__head { margin-bottom: 12px; gap: 10px; }
.goalcard__per {
  flex: none; font-size: .76rem; font-weight: 700; color: var(--muted);
  white-space: nowrap;
}
.goalcard__per--hit { color: var(--ok); }

.days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.day { display: grid; justify-items: center; gap: 6px; min-width: 0; }
.day__label { font-size: .66rem; font-weight: 700; color: var(--muted); }
.day__label--ahead { color: var(--faint); }
.day__dot {
  width: 100%; aspect-ratio: 1; max-width: 40px; border-radius: 50%;
  border: 1.5px solid var(--surface-3); background: var(--surface-2);
  display: grid; place-items: center; cursor: pointer;
  font: inherit; font-size: .8rem; font-weight: 800; color: transparent;
  transition: transform .12s ease, background .16s ease, border-color .16s ease;
}
.day__dot:active { transform: scale(.9); }
.day__dot--on {
  background: var(--accent); border-color: var(--accent); color: #ffffff;
}
.day__dot:disabled { cursor: default; opacity: .55; }
/* A tick with a picture behind it: the photo fills the circle, the tick sits on top. */
.day__dot--photo {
  background-size: cover; background-position: center;
  text-shadow: 0 0 4px rgba(0, 0, 0, .7);
  border-color: var(--accent);
}

/* Timeline (Friends tab) ------------------------------------------------- */
.tl {
  background: var(--surface); border-radius: var(--r-card); box-shadow: var(--shadow);
  overflow: hidden; margin-bottom: 14px;
}
.tl__head { padding: 12px 14px; }
.tl__photo {
  display: block; width: 100%; max-height: 70dvh; object-fit: cover;
  background: var(--surface-2);
}
.tl__taken {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  font-size: .78rem; font-weight: 600; color: var(--muted);
}
.tl__taken svg { width: 16px; height: 16px; flex: none; }
.tl__taken--warn { background: var(--warn-wash); color: var(--warn); }
.tl__taken--muted { color: var(--faint); font-weight: 500; }

/* ----------------------------------------------- counted goal, not ticked */

/* Same weight as the row of day dots it stands in for, so a card with an
   amount and a card with seven days sit level in the same list. */
.count { display: flex; align-items: center; gap: 10px; }
.count__step {
  width: 40px; height: 40px; flex: 0 0 auto; border-radius: 50%;
  border: 1.5px solid var(--surface-3); background: var(--surface-2);
  display: grid; place-items: center; cursor: pointer;
  font: inherit; font-size: 1.1rem; font-weight: 800; color: var(--ink);
  transition: transform .12s ease, background .16s ease, border-color .16s ease;
}
.count__step:active { transform: scale(.9); }
.count__step:disabled { cursor: default; opacity: .4; }
/* Two classes, so this outranks the generic `input[type=…] { width: 100% }`
   rule. At one class it lost on specificity: the box took the full row,
   inherited the big field padding, and pushed + off the edge of the card. */
.count .count__value {
  width: 4.5rem; flex: 0 0 auto; text-align: center;
  font: inherit; font-size: 1.05rem; font-weight: 800; color: var(--ink);
  padding: 7px 4px; border-radius: 10px;
  border: 1.5px solid var(--surface-3); background: var(--surface-2);
}
.count__value:disabled { opacity: .55; }
/* The spinners are redundant next to the − and + and they crowd the box. */
.count__value::-webkit-outer-spin-button,
.count__value::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.count .count__value { -moz-appearance: textfield; appearance: textfield; }
.count__of { font-size: .82rem; font-weight: 700; color: var(--muted); flex: 1 1 auto; min-width: 0; }

/* ------------------------------------------- weekly progress block chart */

.chart { display: flex; align-items: flex-end; gap: 7px; overflow-x: auto; padding: 6px 2px 2px; scrollbar-width: none; }
.chart::-webkit-scrollbar { display: none; }

.chartcol { flex: none; width: 46px; display: grid; gap: 5px; justify-items: center; }
.chartcol__stack { display: grid; gap: 5px; width: 100%; align-content: end; }

.blk {
  border-radius: 13px; background: var(--l1);
  display: grid; place-items: center;
  font-size: .74rem; font-weight: 800; color: var(--accent-deep);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.blk--empty { background: var(--l1); color: transparent; }
.blk--miss  { background: var(--l1); color: var(--muted); }
.blk--part  { background: var(--l2); }
.blk--most  { background: var(--l3); color: #fff; }
.blk--full  { background: var(--l4); color: #fff; }
.blk--now   { box-shadow: 0 0 0 2.5px var(--accent-deep); }

.chartcol__label { font-size: .72rem; font-weight: 700; color: var(--faint); }
.chartcol__label--now { color: var(--accent-deep); }

/* Big headline stat, as in the reference's "65% Total progress". */
.bigstat {
  display: inline-flex; align-items: center; gap: 12px;
  background: var(--surface); border-radius: var(--r-pill);
  padding: 10px 18px 10px 20px; box-shadow: var(--shadow);
}
.bigstat__n { font-size: 1.75rem; font-weight: 800; letter-spacing: -.04em; line-height: 1; }
.bigstat__l { font-size: .78rem; font-weight: 600; color: var(--muted); line-height: 1.15; max-width: 8ch; }

/* ------------------------------------------------------------ leaderboard */

.lb { display: grid; gap: 10px; }
.lb__row {
  display: flex; align-items: center; gap: 13px; padding: 15px 18px;
  border-radius: var(--r-card); background: var(--surface); box-shadow: var(--shadow);
}
.lb__row--top { background: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow-lift); }
.lb__row--top .muted, .lb__row--top .tiny { color: color-mix(in srgb, var(--accent-ink) 75%, transparent); }
.lb__row--top .avatar { background: color-mix(in srgb, var(--accent-ink) 22%, transparent); }
.lb__rank { flex: none; width: 28px; font-weight: 800; color: var(--faint); font-variant-numeric: tabular-nums; }
.lb__row--top .lb__rank { color: var(--accent-ink); }
.lb__fines { font-weight: 800; font-variant-numeric: tabular-nums; text-align: right; letter-spacing: -.02em; }

/* ------------------------------------------------------------ fine list */

/* Every fine on the board, one row each. Deliberately not a table: a phone is
   375px and six columns are not, so the admin's button ends up somewhere only
   a sideways scroll can reach. Name and money on the first line, what it was
   for underneath, and the status and the button on a line of their own where
   they always fit. */

.fine {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 10px; align-items: baseline;
  padding: 13px 0; border-top: 1px solid var(--line);
}
.fine:first-child { border-top: 0; padding-top: 4px; }
.fine__who { min-width: 0; }
.fine__amount { font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -.02em; color: var(--ink); }
.fine__foot { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; margin-top: 8px; }
/* The button sits at the right-hand end of its own line, where a thumb expects
   it and nothing can push it off the screen. */
.fine__act { margin-left: auto; }

/* ----------------------------------------------------------------- table */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--r-mid); background: var(--surface-2); }
table { border-collapse: collapse; width: 100%; font-size: .85rem; }
th, td { padding: 11px 14px; text-align: left; white-space: nowrap; }
th {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--faint); font-weight: 800; position: sticky; top: 0; background: var(--surface-3);
}
tbody tr + tr td { border-top: 1.5px solid color-mix(in srgb, var(--surface-3) 60%, transparent); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------ tabs */

.tabs { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 10px; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex: none; padding: 10px 17px; border-radius: var(--r-pill); border: 0;
  background: var(--surface); color: var(--muted);
  font: inherit; font-size: .85rem; font-weight: 700; letter-spacing: -.01em;
  cursor: pointer; white-space: nowrap; box-shadow: var(--shadow);
}
.tab[aria-selected="true"] { background: var(--contrast); color: var(--contrast-ink); }

/* The floating bottom bar: five sections, line icons, bottle green in both
   themes. Emoji used to sit here and rendered differently on every device. */
.navbar {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(18px + env(safe-area-inset-bottom)); z-index: 30;
  display: flex; gap: 2px; padding: 7px;
  width: min(calc(100vw - 28px), 372px);
  background: var(--nav);
  border-radius: var(--r-pill);
  box-shadow: 0 10px 30px -8px rgba(9, 26, 20, .45);
}
.navbar__item {
  flex: 1; min-width: 0; height: 54px; border-radius: var(--r-pill); border: 0;
  display: grid; place-items: center; align-content: center; gap: 3px;
  cursor: pointer; background: transparent; color: var(--nav-ink);
  font-family: inherit;
}
.navbar__icon { width: 21px; height: 21px; display: block; }
.navbar__label {
  font-size: .56rem; font-weight: 700; letter-spacing: .01em;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.navbar__item[aria-current="page"] { background: var(--accent); color: #ffffff; }
/* A section you cannot reach yet — no group open — keeps its position rather
   than disappearing, so the bar never changes shape under your thumb. */
.navbar__item:disabled { opacity: .38; cursor: default; }

/* ---------------------------------------------------------- modal + toast */

.modal {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(19, 19, 22, .45); backdrop-filter: blur(4px);
}
@media (min-width: 560px) { .modal { align-items: center; padding: 24px; } }
.modal__panel {
  width: 100%; max-width: 500px; max-height: 90dvh; overflow-y: auto;
  background: var(--bg); border-radius: 28px 28px 0 0;
  padding: 24px 20px calc(24px + env(safe-area-inset-bottom));
  animation: rise .24s cubic-bezier(.2, .8, .3, 1);
}
@media (min-width: 560px) { .modal__panel { border-radius: 28px; padding-bottom: 24px; } }
@keyframes rise { from { transform: translateY(22px); opacity: 0; } }
.modal__head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 16px; }
.modal__head h2 { flex: 1; }

.preview {
  white-space: pre-wrap; word-break: break-word;
  font-size: .88rem; line-height: 1.55; font-weight: 500;
  background: var(--surface); color: var(--ink);
  border-radius: var(--r-mid); padding: 16px 18px;
}

.toast {
  position: fixed; left: 50%; bottom: calc(96px + env(safe-area-inset-bottom));
  transform: translate(-50%, 14px); z-index: 60;
  max-width: min(90vw, 420px);
  padding: 13px 20px; border-radius: var(--r-pill);
  background: var(--contrast); color: var(--contrast-ink);
  font-size: .87rem; font-weight: 700; text-align: center;
  opacity: 0; pointer-events: none; transition: opacity .2s ease, transform .2s ease;
}
.toast--on { opacity: 1; transform: translate(-50%, 0); }
.toast--error { background: var(--danger); color: #fff; }

details.help { border-radius: var(--r-mid); background: var(--surface-2); }
details.help > summary {
  cursor: pointer; padding: 14px 17px; font-size: .86rem; font-weight: 700;
  list-style: none; display: flex; align-items: center; gap: 8px;
}
details.help > summary::-webkit-details-marker { display: none; }
details.help > summary::after { content: "▾"; margin-left: auto; color: var(--muted); transition: transform .2s; }
details.help[open] > summary::after { transform: rotate(180deg); }
details.help .help__body { padding: 0 17px 16px; font-size: .86rem; color: var(--muted); font-weight: 500; }
details.help ol { margin: 0; padding-left: 20px; }
details.help li { margin-bottom: 7px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

.card--accent .avatar { background: color-mix(in srgb, var(--accent-ink) 20%, transparent); }

/* ------------------------------------------------------------- countdown */

.countdown {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 8px;
  padding: 5px 11px; border-radius: var(--r-pill);
  background: var(--accent-wash); color: var(--accent-deep);
  font-size: .76rem; font-weight: 700;
  /* The pill sits in a flex row beside a title. Wrapping "Ticks close in" onto
     three lines around its own countdown is worse than letting the row wrap. */
  white-space: nowrap;
}
.countdown b { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 700; letter-spacing: -.02em; }
.countdown--inline { display: block; background: none; padding: 2px 0 4px; margin: 0; color: inherit; font-size: .84rem; font-weight: 600; }

/* The mark on the sign-in screen: the same SVG the home screen icon uses. A ✅
   emoji stood here before, so the first thing anyone saw of the app was not
   its logo. Deliberately NOT called .mark — that is the 18px tick square on
   the team screen. */
.brandmark {
  display: block; margin: 0 auto; width: 72px; height: 72px;
  border-radius: 22px; box-shadow: var(--shadow);
}

/* Inside the App Store shell there is no browser chrome above the app, so the
   header needs the space the notch would otherwise take. The class is set by
   the script only when Capacitor is present. Pull-to-refresh is deliberately
   left alone: the gesture works the same in the shell, and hiding only its
   indicator would make a working refresh invisible. */
.is-native .topbar { padding-top: calc(30px + env(safe-area-inset-top)); }

/* In the iPhone app the web view runs underneath the status bar. With
   nothing behind the clock, anything scrolled past the top shows through
   it. A fixed strip the height of the safe area, in the page colour. */
.is-native body::before {
  content: ''; position: fixed; top: 0; left: 0; right: 0; z-index: 45;
  height: env(safe-area-inset-top); background: var(--bg); pointer-events: none;
}

/* --------------------------------------------------------- pull to refresh */

.ptr {
  position: fixed; top: calc(8px + env(safe-area-inset-top)); left: 50%; z-index: 40;
  transform: translate(-50%, 0); opacity: 0; pointer-events: none;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 16px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--muted); box-shadow: var(--shadow);
  font-size: .82rem; font-weight: 700; transition: opacity .15s ease;
}
.ptr__icon { display: inline-block; transition: transform .2s ease; }
.ptr--ready .ptr__icon { transform: rotate(180deg); color: var(--accent-deep); }
.ptr--busy .ptr__icon { animation: spin .7s linear infinite; }

/* ------------------------------------------------------------------ quiz */

.quiz__count {
  font-size: .72rem; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent-deep); margin-bottom: 6px;
}
.quiz__bar { height: 4px; border-radius: var(--r-pill); background: var(--surface-2); overflow: hidden; }
.quiz__bar > i { display: block; height: 100%; background: var(--accent); border-radius: var(--r-pill); transition: width .25s ease; }

.quiz__options { display: grid; gap: 9px; margin-bottom: 12px; }
.quiz__option {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 15px 17px; border: 0; border-radius: var(--r-mid);
  background: var(--surface); box-shadow: var(--shadow);
  font: inherit; font-weight: 700; font-size: .95rem; color: var(--ink);
  text-align: left; cursor: pointer;
  transition: transform .1s ease, background .15s ease;
}
.quiz__option:active { transform: scale(.98); }
.quiz__option:hover { background: var(--accent-wash); }
.quiz__emoji { font-size: 1.3rem; line-height: 1; }
.quiz__chev { color: var(--faint); font-size: 1.1rem; }

/* ------------------------------------------------------------- house rules */

.rules { display: grid; gap: 13px; }
.rules__row { display: flex; gap: 12px; align-items: flex-start; font-size: .89rem; line-height: 1.45; }
.rules__icon { flex: none; font-size: 1.05rem; line-height: 1.35; }

/* --------------------------------------------------- team tick indicators */

/* Emoji squares rendered as grey blocks and read as broken images. */
.mark {
  flex: none; width: 18px; height: 18px; border-radius: 6px;
  display: grid; place-items: center;
  background: var(--surface-2); box-shadow: inset 0 0 0 1.5px var(--surface-3);
  font-size: .68rem; font-weight: 800; color: transparent;
}
.mark--hit { background: var(--ok); box-shadow: none; color: #fff; }

/* The tab strip scrolls, and the fade says which way. Fading only the right
   was wrong once you had scrolled to Settings: the tabs out of sight were
   then the ones behind you, with nothing to suggest it. The state comes from
   the script, because CSS cannot see scroll position. */
.tabs { scroll-behavior: smooth; }
.tabs[data-edge="right"], .chart[data-edge="right"] {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent 100%);
}
.tabs[data-edge="left"], .chart[data-edge="left"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 26px);
  mask-image: linear-gradient(to right, transparent 0, #000 26px);
}
.tabs[data-edge="both"], .chart[data-edge="both"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 26px, #000 calc(100% - 26px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 26px, #000 calc(100% - 26px), transparent 100%);
}

/* Two sub-tabs inside a section: same pill, quieter, and never wide enough to
   need the scrolling the top strip was built for. */
.tabs--sub { padding-top: 0; }
.tabs--sub .tab { box-shadow: none; background: var(--surface-2); }
.tabs--sub .tab[aria-selected="true"] { background: var(--contrast); color: var(--contrast-ink); }

/* Tighter tabs on a narrow phone, so five of them stand a chance of fitting. */
@media (max-width: 400px) {
  .tab { padding: 10px 13px; font-size: .82rem; }
  .tabs { gap: 6px; }
}

/* ============================================================================
   One Quarter redesign (September 2026) — the brand canvas, applied.
   Everything below restyles the components above to match the canvas at
   claude.ai/code/artifact/828133e4…: bottle-green titles, mono labels,
   outlined paper cards, green-done day circles, a quieter navigation, the
   dark message pill. Same tokens; no new colours.
   ========================================================================== */

:root {
  --title: #0f3b2e;          /* headings are bottle green, not ink */
  --label: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
  :root { --title: #f0ebe3; }
}

/* Header: a mono label over a heavy bottle-green title. */
.topbar { align-items: center; padding-bottom: 20px; }
.topbar__title h1 { font-weight: 800; color: var(--title); letter-spacing: -.035em; }
.topbar__title h1 b { font-weight: 800; }
.topbar__title .sub {
  font-family: var(--label); font-size: .7rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; margin-top: 6px;
}
.iconbtn { background: var(--surface); box-shadow: none; border: 1px solid var(--line); color: var(--title); }
.iconbtn svg { width: 20px; height: 20px; display: block; }

/* The little lockup at the top of Home. */
.brandline { display: flex; align-items: center; gap: 10px; padding-top: calc(22px + env(safe-area-inset-top)); }
.is-native .brandline { padding-top: calc(30px + env(safe-area-inset-top)); }
.brandline svg { width: 30px; height: 30px; flex: none; }
.brandline span { font-weight: 800; font-size: 1.1rem; letter-spacing: -.035em; color: var(--title); }
.brandline + .topbar { padding-top: 14px; }

/* Cards: paper with a hairline, as on the canvas. */
.card, .list__item { border: 1px solid var(--line); }
.card--flat, .card--sunk { border-color: transparent; }
.card--accent { border-color: transparent; }
.card__head h2, .card__head h3 { color: var(--title); }

.section-title {
  font-family: var(--label); font-size: .68rem; font-weight: 600; letter-spacing: .12em;
  color: var(--muted); margin: 14px 4px 2px;
}

/* The update that's due: a bottle-green card with the button inside it. */
.banner--due {
  background: var(--nav); color: var(--nav-ink); align-items: center;
  border-radius: var(--r-card); padding: 16px 16px 16px 20px;
}
.banner--due strong { font-size: 1.05rem; letter-spacing: -.01em; }
.banner--due .countdown--inline { color: color-mix(in srgb, var(--nav-ink) 78%, transparent); }
.banner--due > div { flex: 1; min-width: 0; }
.banner--due .btn { flex: none; }
.banner svg { width: 20px; height: 20px; flex: none; margin-top: 1px; }

/* Goals: one card each. */
.goalcard.card { padding: 16px 18px; }
.goalcard.card + .goalcard.card { border-top: 1px solid var(--line); }
.goalcard .goal__title { font-size: 1.08rem; font-weight: 800; }
.goalcard__per { font-size: .82rem; }
.goalcard__per--hit { color: var(--ok); }

/* Day circles: done is bottle green with a cream tick, today is an orange
   ring, days not reached yet are dashed. */
.day__dot { border: 2px solid var(--surface-2); max-width: 42px; }
.day__dot--on { background: var(--contrast); border-color: var(--contrast); color: var(--contrast-ink); }
.day__dot--today:not(.day__dot--on) { background: var(--surface); border-color: var(--accent); }
.day__dot--ahead:not(.day__dot--on) { background: transparent; border: 2px dashed var(--surface-3); }
.day__label--today { color: var(--accent-deep); }

.count__step { border-width: 2px; }
.goalbar { margin-top: 12px; }

/* Navigation: bottle green, the current section lit orange rather than filled. */
.navbar { padding: 6px; box-shadow: 0 14px 30px -12px rgba(15, 59, 46, .55); }
.navbar__item { color: color-mix(in srgb, var(--nav-ink) 60%, transparent); }
.navbar__item[aria-current="page"] { background: color-mix(in srgb, var(--nav-ink) 10%, transparent); color: var(--accent); }
.navbar__item[aria-current="page"] .navbar__label { color: var(--nav-ink); }
.navbar__icon { width: 22px; height: 22px; }
.navbar__label { font-size: .62rem; }

/* The message pill: ink, not green, so it never reads as a button. */
.toast { background: var(--ink); color: var(--bg); box-shadow: 0 12px 24px -12px rgba(18, 33, 28, .6); }

/* Leaderboard: one card, rows with a bar each. */
.lb { gap: 0; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-card); padding: 4px 16px; box-shadow: var(--shadow); }
.lb__row { background: transparent; box-shadow: none; border-radius: 0; padding: 12px 0; border-top: 1px solid var(--line); }
.lb__row:first-child { border-top: 0; }
.lb__row--top { background: transparent; color: var(--ink); box-shadow: none; }
.lb__row--top .muted, .lb__row--top .tiny { color: var(--muted); }
.lb__row--top .avatar { background: var(--accent-wash); }
.lb__row--top .lb__rank { color: var(--accent-deep); }
.lb__rank { font-family: var(--label); font-size: .78rem; }
.lb__bar { height: 6px; margin-top: 7px; }
.lb__fines { color: var(--muted); }
.lb__fines--owed { color: var(--danger); }

/* Home: each group is a bottle-green card with the quarter as thirteen bars. */
.groupcard {
  display: grid; gap: 14px; width: 100%; text-align: left; cursor: pointer;
  background: var(--nav); color: var(--nav-ink); border: 0; font: inherit;
  border-radius: 28px; padding: 22px 20px; box-shadow: 0 14px 30px -16px rgba(15, 59, 46, .6);
}
.groupcard:active { transform: scale(.99); }
.groupcard__label {
  font-family: var(--label); font-size: .68rem; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: color-mix(in srgb, var(--nav-ink) 70%, transparent);
}
.groupcard__name { font-size: 1.6rem; font-weight: 800; letter-spacing: -.03em; line-height: 1.1; overflow-wrap: anywhere; }
.groupcard__weeks { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; }
.groupcard__weeks i { height: 8px; border-radius: var(--r-pill); background: color-mix(in srgb, var(--nav-ink) 20%, transparent); }
.groupcard__weeks i.done { background: var(--nav-ink); }
.groupcard__weeks i.now { background: var(--accent); }
.groupcard__foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: .85rem; font-weight: 600; }
.groupcard__pill { padding: 7px 12px; border-radius: var(--r-pill); background: color-mix(in srgb, var(--nav-ink) 12%, transparent); font-size: .78rem; font-weight: 700; }
.groupcard .countdown { background: color-mix(in srgb, var(--nav-ink) 12%, transparent); color: var(--nav-ink); margin: 0; }

/* House rules: an orange dot instead of an emoji per line. */
.rules__dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); margin-top: .5em; }

/* Icons that stood in for emoji: empty states, big step icons, buttons. */
.empty__icon {
  display: grid; place-items: center; width: 56px; height: 56px; margin: 0 auto 12px;
  border-radius: 18px; background: var(--surface-2); color: var(--title);
}
.empty__icon svg { width: 26px; height: 26px; }
.bigicon {
  display: grid; place-items: center; width: 64px; height: 64px; margin: 0 auto;
  border-radius: 20px; background: var(--accent-wash); color: var(--accent-deep);
}
.bigicon svg { width: 30px; height: 30px; }
.inline-icon { display: inline-grid; color: var(--title); }
.inline-icon svg { width: 22px; height: 22px; }
.btn svg { width: 18px; height: 18px; flex: none; }
.modal__head .btn--ghost { min-height: 40px; width: 40px; padding: 0; }

/* Settings, profile and the pop-up forms: titles in bottle green, and the
   sheet's own heading given the same weight as a screen title. */
.modal__head h2 { color: var(--title); font-weight: 800; letter-spacing: -.03em; font-size: 1.45rem; }
.modal__panel { border-top: 1px solid var(--line); }
details.help { border: 1px solid var(--line); background: var(--surface); }
.field__label { color: var(--ink-2); }
.member__who .strong { color: var(--ink); }

/* The booked dinner: the venue in an orange tile, the address with a pin. */
.venue__tile {
  flex: none; width: 52px; height: 52px; border-radius: 16px;
  display: grid; place-items: center;
  background: var(--accent-wash); color: var(--accent-deep);
}
.venue__tile svg { width: 24px; height: 24px; }
.venue__where { color: var(--ink-2); align-items: flex-start; }
.venue__where svg { width: 18px; height: 18px; flex: none; color: var(--accent-deep); margin-top: 1px; }

/* Dinner and board summaries: the canvas's stat tiles. */
.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.stat.stat--you b { color: var(--accent-deep); }

/* The bill slider: its own card under the booked dinner. */
.billslider { gap: 10px; }
.billslider__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: .82rem; font-weight: 700; color: var(--ink-2); }
.billslider__bill { font-size: 1.4rem; font-weight: 800; letter-spacing: -.03em; color: var(--title); font-variant-numeric: tabular-nums; }
.billslider input[type=range] { width: 100%; margin: 0; height: 28px; accent-color: var(--accent); cursor: pointer; background: transparent; }
.billslider .stat b { font-size: 1.15rem; }
.billslider__note { margin: 0 2px; }
.stat { background: var(--bg); border-radius: 14px; padding: 10px 12px; display: grid; gap: 2px; }
.stat b { font-size: 1.35rem; font-weight: 800; letter-spacing: -.025em; color: var(--title); font-variant-numeric: tabular-nums; white-space: nowrap; }
.stat span { font-size: .72rem; font-weight: 600; color: var(--muted); }
.stat--fine b { color: var(--danger); }

.topbar__title--plain h1 { font-size: 1.6rem; letter-spacing: -.03em; }
/* Your profile (/me): a centred hero, a groups summary card, then one
   rounded row per section with a tinted icon circle — after the profile
   mockup of September 2026. Sections open on their own screen. */
.iconbtn--wash { background: var(--accent-wash); border-color: transparent; color: var(--accent-deep); }

.avatar--xl { width: 96px; height: 96px; font-size: 2.9rem; }
.profile-hero { display: grid; justify-items: center; gap: 6px; text-align: center; padding: 0 0 8px; }
.profile-hero__pic { position: relative; display: block; margin-bottom: 8px; cursor: pointer; border-radius: 50%; }
.profile-hero__pic:active { transform: scale(.97); }
.profile-hero__pic:focus-within { outline: 2px solid var(--accent); outline-offset: 4px; }
/* The pencil on the picture: says it can be changed, and opens the photo picker. */
.profile-hero__edit {
  position: absolute; right: -2px; bottom: 2px;
  width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent-deep); color: var(--accent-ink);
  box-shadow: 0 0 0 3px var(--bg), 0 4px 10px -4px rgba(18, 33, 28, .5);
}
.profile-hero__edit svg { width: 16px; height: 16px; }
.profile-hero .avatar { box-shadow: 0 0 0 4px var(--surface), 0 10px 24px -12px rgba(18, 33, 28, .45); }
.profile-hero__name { font-size: 1.55rem; font-weight: 800; letter-spacing: -.03em; color: var(--title); overflow-wrap: anywhere; }
.profile-hero__contact { font-size: .88rem; color: var(--muted); overflow-wrap: anywhere; }
.profile-hero__contact span { margin: 0 4px; color: var(--faint); }
.profile-hero__badge { display: inline-flex; align-items: center; gap: 5px; font-size: .86rem; font-weight: 600; color: var(--accent-deep); }
.profile-hero__badge svg { width: 16px; height: 16px; }

.profile-groups { padding: 16px 20px 18px; }
.profile-groups__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.profile-groups__head h3 { font-size: 1rem; font-weight: 700; color: var(--ink); }
.linkbtn { background: none; border: 0; padding: 4px 0; font: inherit; font-size: .95rem; font-weight: 800; color: var(--accent-deep); cursor: pointer; }
.profile-groups__who { display: flex; align-items: center; gap: 10px; padding: 12px 0 10px; font-size: .92rem; font-weight: 600; color: var(--ink-2); }
.profile-groups__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.profile-groups__stats div { display: grid; gap: 3px; }
.profile-groups__stats span { font-size: .75rem; color: var(--muted); }
.profile-groups__stats b { font-size: 1.05rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }

.profile-rows { display: grid; gap: 12px; }
.profile-row {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 14px 16px; min-height: 72px; text-align: left; cursor: pointer;
  font: inherit; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-mid);
}
.profile-row:active { transform: scale(.99); }
.profile-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.profile-row__icon { flex: none; width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; }
.profile-row__icon svg { width: 20px; height: 20px; }
.profile-row__icon--brand { background: var(--accent-wash); color: var(--accent-deep); }
.profile-row__icon--warn  { background: var(--warn-wash); color: var(--warn); }
.profile-row__icon--ok    { background: var(--ok-wash); color: var(--ok); }
.profile-row__icon--ink   { background: var(--surface-2); color: var(--title); }
.profile-row__text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.profile-row__title { font-size: 1rem; font-weight: 600; color: var(--ink); }
.profile-row__hint { font-size: .78rem; color: var(--muted); }
.profile-row__chev { flex: none; color: var(--faint); display: grid; }
.profile-row__chev svg { width: 18px; height: 18px; }
.topbar__title--plain h1 { font-size: 1.6rem; letter-spacing: -.03em; }
a.profile-row { text-decoration: none; }
.profile-row__icon--nav    { background: color-mix(in srgb, var(--title) 12%, transparent); color: var(--title); }
.profile-row__icon--danger { background: var(--danger-wash); color: var(--danger); }

/* Label/value pairs in a card: Plan & billing's members, renewal and price. */
.kv { display: grid; gap: 0; background: var(--bg); border-radius: 14px; padding: 4px 14px; }
.kv div { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 9px 0; border-top: 1px solid var(--line); }
.kv div:first-child { border-top: 0; }
.kv span { font-size: .8rem; color: var(--muted); }
.kv b { font-size: .88rem; font-weight: 700; color: var(--ink); text-align: right; }

/* An on/off switch with its label, a whole row to tap. */
.switchrow { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 14px; background: var(--bg); cursor: pointer; }
.switchrow__text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.switch {
  appearance: none; -webkit-appearance: none; flex: none; position: relative; cursor: pointer;
  width: 50px; height: 30px; min-height: 0; margin: 0; padding: 0; border: 0; border-radius: var(--r-pill);
  background: var(--surface-3); transition: background .18s;
}
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(18, 33, 28, .3); transition: transform .18s;
}
.switch:checked { background: var(--ok); }
.switch:checked::after { transform: translateX(20px); }
.switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch:disabled { opacity: .6; }
