/* ==========================================================================
   Jade Eye — Package B styles: Today, the Circle, contact detail, triage.

   Every class here is `je-` prefixed and self-contained, so this sheet cannot
   collide with Package A's src/style.css or Package C's card.css. It consumes
   A's design tokens (--jade, --ink, --color-*, --radius, --gutter, …) and
   falls back to a literal wherever a token might be missing.

   Mobile-first. Jake uses this on an iPhone, one-handed, in the field: every
   tappable thing clears 44px and the primary actions sit low on the card.

   OWNER: Package B. Do not edit src/style.css.
   ========================================================================== */

.je-muted { color: var(--color-text-2, #5C6B75); font-size: 0.85rem; }

/* --------------------------------------------------------------------------
   Today — the morning screen
   -------------------------------------------------------------------------- */

.je-today-head { margin-bottom: 18px; }

.je-eyebrow {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--jade-dark, #00775F);
}

/* Size/weight/tracking/leading come from the single .screen-title rule in
   style.css — see the "ONE page title" note there. */
.je-today-title { margin-top: 2px; }

.je-energy-row { display: flex; align-items: center; gap: 10px; margin-top: 14px; }

.je-energy-label {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-3, #8B98A1);
}

/* The battery is the one control Jake touches every morning, and it was a
   26x26 target. The bar he SEES is still 20x10; the box his thumb HITS is now
   44 tall and as wide as the row can spare.
   The pips share the leftover width instead of taking a fixed 31px, because
   the label on the right runs from "Okay" to "Running on empty" — a fixed
   44px x5 fits the short word and overflows the long one. */
.je-energy { display: flex; gap: 0; flex: 1 1 auto; min-width: 0; }

.je-energy-pip {
  position: relative;
  flex: 1 1 0;
  min-width: 32px;
  max-width: 52px;
  height: 44px;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
}
.je-energy-pip::after {
  content: '';
  position: absolute;
  top: 17px;
  bottom: 17px;
  left: 50%;
  width: 20px;
  transform: translateX(-50%);
  border-radius: 3px;
  background: var(--color-border, #E4E0D8);
  transition: background var(--transition, 180ms ease);
}
.je-energy-pip.is-on::after { background: var(--jade, #00D4AA); }

.je-energy-word {
  font-size: 0.8rem;
  color: var(--color-text-2, #5C6B75);
  margin-left: auto;
  flex-shrink: 0;      /* the pips give up width for this, not the other way round */
}

/* --- the headline card: ONE name, big --- */

.je-headline {
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, #E4E0D8);
  border-top: 3px solid var(--bucket-color, var(--jade, #00D4AA));
  border-radius: var(--radius-lg, 28px);
  box-shadow: var(--shadow-lg, 0 10px 36px rgba(13, 27, 42, 0.14));
  padding: 18px 18px 14px;
  margin-bottom: 26px;
}

.je-headline-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 14px;
}

.je-bucket-tag {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  padding: 4px 10px;
  border-radius: 99px;
  color: var(--bucket-color, var(--jade-dark, #00775F));
  background: color-mix(in srgb, var(--bucket-color, #00D4AA) 12%, transparent);
}

.je-headline-face {
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  text-align: left;
  cursor: pointer;
}

.je-headline-names { flex: 1; min-width: 0; }

.je-headline-name {
  font-size: 1.85rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
  overflow-wrap: anywhere;
}

.je-headline-nick { font-size: 0.9rem; color: var(--color-text-2, #5C6B75); margin-top: 2px; }
.je-headline-sub  { font-size: 0.82rem; color: var(--color-text-3, #8B98A1); margin-top: 4px; }

/* THE WHY LINE. Mandatory on every surfaced name. */
.je-why {
  margin: 16px 0 4px;
  font-size: 1rem;
  line-height: 1.45;
  color: var(--color-text, #16242E);
}

.je-why-proximity {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--jade-dark, #00775F);
}
.je-why-proximity .material-symbols-rounded { font-size: 18px; }

/* --- one-tap actions --- */

.je-actions {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-top: 16px;
}

.je-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 62px;
  padding: 8px 4px;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius-sm, 10px);
  background: var(--color-surface-2, #F2EFE9);
  color: var(--color-text, #16242E);
  font: inherit;
  font-size: 0.7rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform 120ms ease, background var(--transition, 180ms ease);
  -webkit-tap-highlight-color: transparent;
}
.je-action:active { transform: scale(0.95); }
.je-action:disabled { opacity: 0.35; pointer-events: none; }
.je-action .material-symbols-rounded { font-size: 22px; }
.je-action-label { line-height: 1.15; text-align: center; }

/* "Talked to them" is the one that matters. It should look like it. */
.je-action-log {
  background: var(--jade, #00D4AA);
  border-color: var(--jade, #00D4AA);
  color: #062018;
}

.je-low-energy-note {
  margin: 4px 0 20px;
  padding: 14px 16px;
  border-radius: var(--radius, 18px);
  background: var(--color-surface-2, #F2EFE9);
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--color-text-2, #5C6B75);
}

/* --- the two smaller names --- */

.je-section-title {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-text-3, #8B98A1);
  margin: 22px 0 10px;
}

.je-mini-list { display: flex; flex-direction: column; gap: 8px; }

.je-mini {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 10px 10px 12px;
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, #E4E0D8);
  border-left: 3px solid var(--bucket-color, var(--jade, #00D4AA));
  border-radius: var(--radius, 18px);
}

.je-mini-main {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
  min-height: 44px;   /* compact rows came in at 39 — one row, one thumb */
  min-width: 0;
  padding: 0;
  border: none;
  background: none;
  text-align: left;
  cursor: pointer;
}

.je-mini-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.je-mini-name { font-size: 1rem; font-weight: 650; line-height: 1.2; overflow-wrap: anywhere; }

.je-mini-why {
  font-size: 0.78rem;
  line-height: 1.35;
  color: var(--color-text-2, #5C6B75);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.je-mini.is-compact .je-mini-name { font-size: 0.92rem; }
.je-mini.is-compact .je-mini-why { -webkit-line-clamp: 1; line-clamp: 1; }

.je-mini-log,
.je-row-log {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--jade-dark, #00775F);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.je-mini-log:active,
.je-row-log:active { background: color-mix(in srgb, var(--jade, #00D4AA) 18%, transparent); }
.je-mini-log .material-symbols-rounded,
.je-row-log .material-symbols-rounded { font-size: 26px; }

.je-see-all { margin-top: 22px; }

/* --------------------------------------------------------------------------
   The urgency ring
   -------------------------------------------------------------------------- */

.je-ring-avatar { position: relative; flex-shrink: 0; }
.je-ring-avatar .je-ring { position: absolute; inset: 0; color: var(--color-text-3, #8B98A1); }

.je-ring-avatar-inner {
  position: absolute;
  inset: 5px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  overflow: hidden;
  background: var(--color-surface-2, #F2EFE9);
}
.je-ring-avatar-inner img { width: 100%; height: 100%; object-fit: cover; }

.je-initials { font-weight: 700; font-size: 0.9em; letter-spacing: 0.02em; color: var(--jade-dark, #00775F); }

/* --------------------------------------------------------------------------
   Circle — search, chips, buckets, rows
   -------------------------------------------------------------------------- */

.je-screen-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

/* Typography from .screen-title in style.css — see the "ONE page title" note. */
.je-head-actions { display: flex; gap: 8px; }

.je-icon-btn {
  flex-shrink: 0;
  width: 44px;         /* 42 -> 44: matches the shell's .icon-btn */
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: 50%;
  background: var(--color-surface, #fff);
  color: var(--color-text, #16242E);
  cursor: pointer;
}
.je-icon-btn-primary { background: var(--jade, #00D4AA); border-color: var(--jade, #00D4AA); color: #062018; }
.je-icon-btn:active { transform: scale(0.94); }

.je-search-wrap { position: relative; margin-bottom: 12px; }
.je-search-icon {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 20px;
  color: var(--color-text-3, #8B98A1);
  pointer-events: none;
}

.je-input {
  width: 100%;
  padding: 12px 14px;
  font: inherit;
  font-size: 1rem;                 /* 16px — stops iOS zooming the page on focus */
  color: var(--color-text, #16242E);
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius-sm, 10px);
}
.je-input:focus { outline: 2px solid var(--jade, #00D4AA); outline-offset: 1px; }
.je-search { padding-left: 40px; }
.je-textarea { resize: vertical; line-height: 1.5; }

.je-chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.je-chip-scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.je-chip-scroll::-webkit-scrollbar { display: none; }

.je-chip,
.je-choice {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;      /* was 38 — filter chips are a primary Circle gesture */
  padding: 8px 12px;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  white-space: nowrap;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: 99px;
  background: var(--color-surface, #fff);
  color: var(--color-text-2, #5C6B75);
  cursor: pointer;
}
.je-chip.is-on,
.je-choice.is-on {
  background: var(--ink, #0D1B2A);
  border-color: var(--ink, #0D1B2A);
  /* `--ink` flips light in night mode, so the foreground has to flip with it.
     `--color-bg` is its exact inverse in both themes. See the "Inverted
     surfaces" note in style.css. */
  color: var(--color-bg, #FAF9F6);
}
.je-choice .material-symbols-rounded { font-size: 18px; }
.je-chip-count { opacity: 0.6; font-variant-numeric: tabular-nums; }
/* Icon + number only (Starred, Hide Orbit) — no text label, so tighten the
   padding and gap into a compact pill. The count sits right of the glyph. */
.je-chip-iconic { gap: 5px; padding: 8px 12px 8px 10px; }
.je-chip-iconic .je-chip-count { opacity: 0.75; }

.je-tier-dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--tier-color, var(--jade, #00D4AA));
}

.je-tier-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  font: inherit;
  font-size: 0.72rem;
  font-weight: 650;
  white-space: nowrap;
  border-radius: 99px;
  border: 1px solid color-mix(in srgb, var(--tier-color, #00D4AA) 40%, transparent);
  background: color-mix(in srgb, var(--tier-color, #00D4AA) 12%, transparent);
  color: var(--color-text, #16242E);
}
.je-tier-chip.is-interactive { cursor: pointer; position: relative; }
.je-tier-chip.is-interactive:active { transform: scale(0.95); }
/* The chip must stay a small badge visually — it sits beside a name and any
   bigger would shout. So the badge keeps its 29px look and gets an invisible
   44px-tall hit layer instead. Purely a touch affordance; nothing moves. */
.je-tier-chip.is-interactive::before {
  content: '';
  position: absolute;
  inset: -8px -6px;
}
/* ── The stacked-controls squeeze on a circle row ────────────────────────────
   .je-row-side is a column of THREE controls: this chip (29px drawn), the
   "+ Circle" pill (24px drawn), and the star/check actions row (a real 44px).
   Measured, that column was 100px tall inside a 121px row — and three 44px
   touch bands need 132px. The two invisible overlays were therefore fighting
   over the same pixels: growing the pill's overlay upward shrank the chip's,
   and the check passed only because one of them was always being measured
   through the other.

   The pills keep their exact drawn size. The COLUMN grows instead, via
   transparent margins that reserve each pill's band, paid for partly by
   tightening the row's own vertical padding (10px -> 6px). Row height goes
   121 -> 145px; nothing changes shape, and the three bands stop overlapping. */
.je-tier-chip.is-interactive { margin: 8px 0; }
/* Caret so an interactive chip clearly reads as a control that opens the picker. */
.je-tier-caret { font-size: 15px; opacity: 0.5; margin: 0 -3px 0 -1px; }

/* Row-level "+ Add circle" — opens the named-circles picker (Family, PBF Clients,
   Fitness…) with create-new, WITHOUT leaving the Circle list. Sits under the
   closeness (tier) chip so the two axes stay visually distinct. */
.je-row-addcircle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.68rem;
  font-weight: 650;
  padding: 3px 9px 3px 6px;
  border-radius: 99px;
  border: 1px dashed color-mix(in srgb, var(--jade) 50%, transparent);
  background: color-mix(in srgb, var(--jade) 8%, transparent);
  color: var(--jade-dark);
  cursor: pointer;
  white-space: nowrap;
}
.je-row-addcircle .material-symbols-rounded { font-size: 15px; }
.je-row-addcircle:active { transform: scale(0.95); }
/* Same trick as .je-tier-chip above, and for the same reason: the pill has to
   stay a small dashed badge beside a name, but it measured 66x24 against a
   44px floor. An invisible overlay grows the THUMB target to 66x44 without
   moving a pixel of the pill. Nothing here reshapes the row Jake validated. */
/* Same trick, same reason as the tier chip: the pill stays a 66x24 dashed
   badge and gets a transparent 44px band around it. See the squeeze note above
   for why the margin is needed as well as the overlay. */
.je-row-addcircle { position: relative; margin: 12px 0; }
.je-row-addcircle::before {
  content: '';
  position: absolute;
  /* 24 + 24 = 48, not 44: the band is flanked on both sides by the chip above
     and the actions row below, and a probe that walks outward from the centre
     stops one pixel short at each shared edge. 48 leaves the margin the
     measurement needs. */
  inset: -12px -2px;
}

/* --- buckets --- */

.je-bucket-list { display: flex; flex-direction: column; gap: 14px; }

.je-bucket {
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius, 18px);
  background: var(--color-surface, #fff);
  overflow: hidden;
}

.je-bucket-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 13px 14px;
  border: none;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.je-bucket-dot {
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--bucket-color, var(--jade, #00D4AA));
}
.je-bucket-label { font-weight: 700; font-size: 0.95rem; }
.je-bucket-count {
  font-size: 0.72rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 2px 8px;
  border-radius: 99px;
  background: color-mix(in srgb, var(--bucket-color, #00D4AA) 15%, transparent);
  color: var(--bucket-color, var(--jade-dark, #00775F));
}
.je-bucket-blurb {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--color-text-3, #8B98A1);
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.je-bucket-chev { flex-shrink: 0; color: var(--color-text-3, #8B98A1); }

.je-rows { display: flex; flex-direction: column; }

.je-row {
  display: flex;
  align-items: center;
  gap: 6px;
  /* 10px -> 6px: the side column needs the height for three legal touch bands
     (see the squeeze note near .je-tier-chip.is-interactive). */
  padding: 6px 12px;
  border-top: 1px solid var(--color-border, #E4E0D8);
}

.je-row-main {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
  min-width: 0;
  padding: 0;
  border: none;
  background: none;
  text-align: left;
  cursor: pointer;
}

.je-row-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.je-row-name-line { display: flex; align-items: center; gap: 5px; min-width: 0; }
.je-row-name {
  font-size: 0.95rem;
  font-weight: 650;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.je-row-flag { flex-shrink: 0; font-size: 15px; color: var(--jade-dark, #00775F); }
.je-row-why {
  font-size: 0.74rem;
  line-height: 1.35;
  color: var(--color-text-2, #5C6B75);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.je-row-score {
  flex-shrink: 0;
  font-size: 0.78rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-3, #8B98A1);
}
/* gap 2 -> 0: the two pills now reserve their own touch bands with transparent
   margins (see the squeeze note near .je-tier-chip.is-interactive), so a gap on
   top of that would only make the row taller for nothing. */
.je-row-side { display: flex; flex-direction: column; align-items: flex-end; gap: 0; flex-shrink: 0; }

.je-show-more { margin: 8px 12px 12px; }
.je-list-footer { text-align: center; padding: 18px 0 6px; }

/* --------------------------------------------------------------------------
   Buttons shared across B's screens
   -------------------------------------------------------------------------- */

.je-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 46px;
  padding: 11px 18px;
  font: inherit;
  font-size: 0.92rem;
  font-weight: 650;
  border: 1px solid transparent;
  border-radius: 99px;
  cursor: pointer;
  transition: transform 120ms ease;
  -webkit-tap-highlight-color: transparent;
}
.je-btn:active { transform: scale(0.97); }
.je-btn-primary { background: var(--jade, #00D4AA); color: #062018; }
.je-btn-ghost   { background: transparent; border-color: var(--color-border, #E4E0D8); color: var(--color-text-2, #5C6B75); }
.je-btn-danger  { background: var(--color-error, #D4726A); color: #fff; }
.je-btn-block   { display: flex; width: 100%; margin-top: 10px; }

.je-link-btn {
  margin-left: auto;
  padding: 4px 2px;
  border: none;
  background: none;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 650;
  color: var(--jade-dark, #00775F);
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   Empty states
   -------------------------------------------------------------------------- */

.je-empty { text-align: center; padding: 54px 18px; }
.je-empty-icon {
  display: block;
  margin: 0 auto 12px;
  font-size: 46px !important;
  color: var(--color-text-3, #8B98A1);
}
.je-empty h2 { font-size: 1.15rem; font-weight: 700; margin-bottom: 6px; }
.je-empty p {
  max-width: 34ch;
  margin: 0 auto 16px;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--color-text-2, #5C6B75);
}
.je-empty .je-btn + .je-btn { margin-top: 8px; }

/* --------------------------------------------------------------------------
   Contact detail
   -------------------------------------------------------------------------- */

.je-topbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.je-topbar-title { font-size: 0.85rem; font-weight: 650; color: var(--color-text-2, #5C6B75); }

.je-detail-hero { text-align: center; padding: 6px 0 18px; }
.je-detail-hero .je-ring-avatar { margin: 0 auto 14px; }

/* Phase 2, 2026-08 — the hero avatar is now a button (tap to add/change a
   photo). Reset to plain button chrome; the 104px ring avatar it wraps is
   already well past the 44px minimum tap target. */
.je-detail-avatar-btn {
  display: block; margin: 0 auto; padding: 0; border: none; background: none;
  cursor: pointer; border-radius: 50%;
}
.je-detail-avatar-btn:focus-visible { outline: 2px solid var(--jade, #00D4AA); outline-offset: 2px; }
.je-detail-avatar-btn .je-ring-avatar { margin: 0 auto 14px; }
.je-detail-name { font-size: 1.7rem; font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; overflow-wrap: anywhere; }
.je-detail-nick { font-size: 0.92rem; color: var(--color-text-2, #5C6B75); margin-top: 3px; }
.je-detail-badges { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 12px; }

.je-why-panel {
  margin-bottom: 16px;
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, #E4E0D8);
  border-left: 3px solid var(--bucket-color, var(--jade, #00D4AA));
  border-radius: var(--radius, 18px);
  overflow: hidden;
}

.je-why-line {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  padding: 14px;
  border: none;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.je-why-text { flex: 1; font-size: 0.92rem; line-height: 1.5; }
.je-why-chev { color: var(--color-text-3, #8B98A1); transition: transform var(--transition, 180ms ease); }
.je-why-panel.is-open .je-why-chev { transform: rotate(180deg); }

/* The arithmetic, in the open. Nobody else in this market shows it. */
.je-math { display: none; padding: 0 14px 12px; }
.je-why-panel.is-open .je-math { display: block; }

.je-math-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 10px;
  padding: 7px 0;
  border-top: 1px dashed var(--color-border, #E4E0D8);
  font-size: 0.82rem;
}
.je-math-label { font-weight: 600; }
.je-math-value { font-weight: 700; font-variant-numeric: tabular-nums; }
.je-math-note { grid-column: 1 / -1; font-size: 0.74rem; color: var(--color-text-3, #8B98A1); }
.je-math-row.is-total {
  margin-top: 4px;
  padding-top: 10px;
  border-top: 2px solid var(--bucket-color, var(--jade, #00D4AA));
}
.je-math-row.is-total .je-math-value { font-size: 1.1rem; color: var(--bucket-color, var(--jade-dark, #00775F)); }

.je-notice {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  margin: 14px 0;
  border-radius: var(--radius-sm, 10px);
  background: var(--color-surface-2, #F2EFE9);
  font-size: 0.85rem;
}

.je-section { margin-top: 22px; }
.je-section-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.je-section-icon { font-size: 18px !important; color: var(--color-text-3, #8B98A1); }
.je-section-head .je-section-title { margin: 0; }
.je-section-body {
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius, 18px);
  overflow: hidden;
}

.je-info-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
  padding: 12px 14px;
  color: inherit;
  text-decoration: none;
  border-top: 1px solid var(--color-border, #E4E0D8);
}
.je-section-body > .je-info-row:first-child { border-top: none; }
.je-info-icon { flex-shrink: 0; font-size: 20px !important; color: var(--jade-dark, #00775F); }
.je-info-stack { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.je-info-label {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-3, #8B98A1);
}
.je-info-text { font-size: 0.92rem; overflow-wrap: anywhere; }
.je-info-chev { margin-left: auto; flex-shrink: 0; color: var(--color-text-3, #8B98A1); }

.je-tag-row { padding: 12px 14px; margin: 0; }
.je-tag {
  padding: 4px 10px;
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: 99px;
  background: var(--color-surface-2, #F2EFE9);
  color: var(--color-text-2, #5C6B75);
}

.je-note-blob, .je-note { padding: 12px 14px; font-size: 0.9rem; line-height: 1.55; }
.je-note { border-top: 1px solid var(--color-border, #E4E0D8); }
.je-note-date { display: block; margin-top: 4px; font-size: 0.72rem; }

.je-dial {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 50px;
  padding: 13px 14px;
  border: none;
  border-top: 1px solid var(--color-border, #E4E0D8);
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.je-section-body > .je-dial:first-child { border-top: none; }
.je-dial-label { font-size: 0.9rem; font-weight: 650; }
.je-dial-value { margin-left: auto; font-size: 0.85rem; text-align: right; color: var(--color-text-2, #5C6B75); }
.je-dial-chev { flex-shrink: 0; color: var(--color-text-3, #8B98A1); }

/* --- the timeline --- */

.je-timeline { display: flex; flex-direction: column; }
.je-timeline-empty { padding: 16px 14px; line-height: 1.55; }
.je-timeline-more { padding: 10px 14px; }

.je-touch {
  display: flex;
  gap: 12px;
  padding: 12px 14px;
  border-top: 1px solid var(--color-border, #E4E0D8);
}
.je-timeline > .je-touch:first-child { border-top: none; }
.je-touch-icon {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: color-mix(in srgb, var(--jade, #00D4AA) 14%, transparent);
  color: var(--jade-dark, #00775F);
}
.je-touch-icon .material-symbols-rounded { font-size: 17px; }
.je-touch-body { flex: 1; min-width: 0; }
.je-touch-head { display: flex; align-items: baseline; gap: 8px; }
.je-touch-verb { font-size: 0.88rem; font-weight: 650; }
.je-touch-date { margin-left: auto; font-size: 0.74rem; white-space: nowrap; color: var(--color-text-3, #8B98A1); }
.je-touch-note { margin-top: 3px; font-size: 0.84rem; line-height: 1.45; color: var(--color-text-2, #5C6B75); }

/* --------------------------------------------------------------------------
   Bottom sheet — tier picker, cadence, priority, touch logger
   -------------------------------------------------------------------------- */

.je-sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(13, 27, 42, 0);
  transition: background 180ms ease;
}
.je-sheet-overlay.je-sheet-in { background: rgba(13, 27, 42, 0.45); }
.je-sheet-overlay.je-sheet-closing { background: rgba(13, 27, 42, 0); }

.je-sheet {
  width: 100%;
  max-width: var(--page-max, 520px);
  max-height: 88vh;
  overflow-y: auto;
  padding: 8px 18px calc(24px + env(safe-area-inset-bottom, 0px));
  background: var(--color-bg, #FAF9F6);
  border-radius: 26px 26px 0 0;
  transform: translateY(100%);
  transition: transform 200ms cubic-bezier(0.2, 0, 0, 1);
}
.je-sheet-overlay.je-sheet-in .je-sheet { transform: translateY(0); }
.je-sheet-overlay.je-sheet-closing .je-sheet { transform: translateY(100%); }

.je-sheet-handle {
  width: 42px;
  height: 5px;
  margin: 6px auto 14px;
  border-radius: 99px;
  background: var(--color-border, #E4E0D8);
  cursor: pointer;
}
.je-sheet-title { font-size: 1.15rem; font-weight: 700; letter-spacing: -0.02em; }
.je-sheet-sub { margin: 4px 0 14px; font-size: 0.85rem; line-height: 1.45; color: var(--color-text-2, #5C6B75); }

body.je-sheet-open { overflow: hidden; }

.je-tier-list { display: flex; flex-direction: column; gap: 8px; }

.je-tier-option {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 62px;
  padding: 12px 16px;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius, 18px);
  background: var(--color-surface, #fff);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.je-tier-option.is-current {
  border-color: var(--tier-color, var(--jade, #00D4AA));
  background: color-mix(in srgb, var(--tier-color, #00D4AA) 8%, var(--color-surface, #fff));
}
.je-tier-option .je-tier-dot { width: 12px; height: 12px; }
.je-tier-icon { color: var(--jade-dark, #00775F); }
.je-tier-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.je-tier-label { font-size: 0.98rem; font-weight: 650; }
.je-tier-cadence { font-size: 0.78rem; color: var(--color-text-2, #5C6B75); }
.je-tier-check { flex-shrink: 0; color: var(--jade-dark, #00775F); }

.je-logger { display: flex; flex-direction: column; }
.je-field-label {
  display: block;
  margin: 14px 0 7px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-3, #8B98A1);
}
.je-logger .je-chip-row { margin-bottom: 0; }
.je-confirm p { margin-bottom: 8px; font-size: 0.9rem; line-height: 1.55; }

/* --------------------------------------------------------------------------
   Contact form
   -------------------------------------------------------------------------- */

.je-form { display: flex; flex-direction: column; padding-bottom: 12px; }
.je-form .je-field-label:first-child { margin-top: 4px; }
.je-form-error { margin-top: 10px; min-height: 1.2em; font-size: 0.85rem; color: var(--color-error, #D4726A); }

/* Photo picker (Phase 2, 2026-08) — the tappable avatar at the top of
   Add/Edit. 88px is well past the 44px minimum; the whole circle is the
   tap target, not a small icon inside it. */
.je-form-photo { display: flex; flex-direction: column; align-items: center; gap: 6px; margin: 4px 0 8px; }
.je-form-photo-avatar {
  position: relative;
  width: 88px; height: 88px;
  border-radius: 50%;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--jade-tint, #E3F7F1);
  border: 2px solid var(--color-border, #E4E7E9);
}
.je-form-photo-avatar img { width: 100%; height: 100%; object-fit: cover; }
.je-form-photo-avatar .je-initials { font-size: 1.4rem; }
.je-form-photo-add-icon {
  position: absolute; right: -2px; bottom: -2px;
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--jade, #00D4AA);
  color: #fff;
  font-size: 16px !important;
  border: 2px solid var(--color-surface, #FFFFFF);
}
.je-form-photo-label { font-size: 0.8rem; font-weight: 600; color: var(--color-text-2, #5C6B75); }

.je-tier-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.je-tier-big {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-height: 72px;
  padding: 12px;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius-sm, 10px);
  background: var(--color-surface, #fff);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.je-tier-big.is-on {
  border-width: 2px;
  border-color: var(--tier-color, var(--jade, #00D4AA));
  background: color-mix(in srgb, var(--tier-color, #00D4AA) 9%, var(--color-surface, #fff));
}
.je-tier-big-label { font-size: 0.92rem; font-weight: 650; }
.je-tier-big-cadence { font-size: 0.74rem; color: var(--color-text-2, #5C6B75); }

/* --------------------------------------------------------------------------
   Triage sprint
   -------------------------------------------------------------------------- */

.je-triage { display: flex; flex-direction: column; }

.je-triage-progress { margin-bottom: 12px; }
.je-progress-track {
  height: 7px;
  border-radius: 99px;
  background: var(--color-surface-2, #F2EFE9);
  overflow: hidden;
}
.je-progress-fill {
  height: 100%;
  border-radius: 99px;
  background: var(--jade, #00D4AA);
  transition: width 260ms cubic-bezier(0.2, 0, 0, 1);
}
.je-triage-progress p { margin-top: 7px; text-align: center; }

.je-triage-card {
  padding: 14px 16px;
  text-align: center;
  background: var(--color-surface, #fff);
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius-lg, 28px);
  box-shadow: var(--shadow, 0 2px 14px rgba(13, 27, 42, 0.07));
}
.je-triage-card .je-ring-avatar { margin: 0 auto 12px; }
.je-triage-name { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.15; overflow-wrap: anywhere; }
.je-triage-context { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.je-triage-bit { font-size: 0.83rem; color: var(--color-text-2, #5C6B75); overflow-wrap: anywhere; }

.je-triage-question {
  margin: 20px 0 10px;
  text-align: center;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-text-3, #8B98A1);
}

/* The triage sprint's two questions (rebuilt 2026-08-11 — one page, circles
   then closeness, "tap tap next"). Spacing between the two blocks; the
   controls themselves are borrowed wholesale — circlePicker()'s own
   .je-circle-picker/.je-circle-grid/.je-circle-chip for circles, circle.js's
   .je-chip-row/.je-chip fast-path idiom for closeness — deliberately NOT
   .je-chip-scroll (see triage.js: that class hid Acquaintances, Extended
   and Orbit off-screen with the scrollbar suppressed and no hint they
   existed). */
.je-triage-circles-q { margin-bottom: 10px; }
.je-triage-circles-q .je-triage-question,
.je-triage-closeness-q .je-triage-question { margin: 10px 0 8px; }
.je-triage-closeness-q .je-chip-row { margin-bottom: 0; }

/* 2026-08-11 fix — this grid used to be capped at max-height:96px with an
   internal scroll ("one page, tap tap next" honored by shrinking the
   list). That cap is exactly what made Jake's own custom circles (Flow,
   Fire, College, ...) invisible on the one screen built to show them: past
   two rows they sat inside a scroll region he had no reason to know
   existed. The actual intent behind "one page" was no multi-step wizard,
   not "never scroll a pixel" — seeing every circle wins. The cap is gone:
   every circle in the vocabulary renders, and the PAGE scrolls if the list
   runs long (that's fine — see .je-triage-sticky-foot below, which is what
   keeps closeness + Next reachable regardless). Chips are denser instead,
   so more fit before any scrolling starts.
   circle-picker.js's component itself is untouched; this only reshapes its
   footprint on this one screen. */
.je-triage-circles-q .je-circle-grid { gap: 6px; }
.je-triage-circles-q .je-circle-chip {
  /* 44px is the tap-target floor and does not move; padding/gap/font
     tighten around it. */
  min-height: 44px;
  padding: 7px 10px;
  gap: 5px;
  font-size: 0.78rem;
}
.je-triage-circles-q .je-circle-chip-name { max-width: 9em; }

/* Closeness + Next/Skip, pinned so they're reachable no matter how long the
   circle grid above them runs (the actual fix for "one page, tap tap
   next" once the page itself is allowed to scroll).
   FIXED, not sticky — deliberately. .screen has no internal overflow
   container in this app shell; the whole document/body scrolls. A
   position:sticky element that is the LAST child of a tall flex column
   only "catches" once you scroll far enough to reach its natural flow
   position — with an 18-circle grid taller than one viewport, that means
   it would NOT be visible on first paint, exactly failing "always
   reachable." position:fixed is what .bottom-nav/.quick-add-fab/
   .vault-banner already use for this same reason (see style.css) — this
   follows that same pattern. triage.js measures its own rendered height
   and pads the content above it so nothing sits underneath, unmeasured. */
.je-triage-sticky-foot {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(var(--nav-height) + var(--safe-bottom));
  z-index: 55; /* above normal content, below .bottom-nav (60) and the FAB (70) */
  padding: 10px var(--gutter) 12px;
  background: var(--color-bg, #FAF9F6);
  border-top: 1px solid var(--color-border, #E4E0D8);
  box-shadow: 0 -8px 20px rgba(13, 27, 42, 0.14);
}
.je-triage-sticky-foot .je-triage-closeness-q { margin-bottom: 0; }

@media (min-width: 720px) {
  /* Match .bottom-nav's own centring at this breakpoint (style.css) — the
     app shell itself becomes a centred, max-width column here. */
  .je-triage-sticky-foot { max-width: var(--page-max); left: 50%; transform: translateX(-50%); }
}

.je-triage-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.je-triage-btn {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 3px;
  min-height: 84px;
  padding: 14px;
  border: 2px solid color-mix(in srgb, var(--tier-color, #00D4AA) 45%, transparent);
  border-radius: var(--radius, 18px);
  background: color-mix(in srgb, var(--tier-color, #00D4AA) 8%, var(--color-surface, #fff));
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: transform 120ms ease;
}
.je-triage-btn:active { transform: scale(0.96); }
.je-triage-key {
  position: absolute;
  top: 8px;
  right: 10px;
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--color-text-3, #8B98A1);
}
.je-triage-label { font-size: 1rem; font-weight: 700; }
.je-triage-cadence { font-size: 0.75rem; color: var(--color-text-2, #5C6B75); }

.je-triage-foot { display: flex; justify-content: center; gap: 10px; margin-top: 10px; }

/* --- score tuning panel (components/tuning-panel.js) --- */

.je-tuning-grid { display: flex; flex-direction: column; gap: 8px; margin-bottom: 4px; }
.je-tuning-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.je-tuning-tier { flex: 1 1 auto; min-width: 0; font-size: 0.85rem; font-weight: 650; overflow-wrap: anywhere; }
.je-tuning-field {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
}
.je-tuning-field-stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  flex: 1 1 0;
}
.je-tuning-field-stacked .je-tuning-unit { text-align: center; font-size: 0.72rem; font-weight: 700; }
.je-tuning-num {
  width: 64px;
  min-height: 40px;
  padding: 6px 8px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.je-tuning-field-stacked .je-tuning-num { width: 100%; }
.je-tuning-unit { font-size: 0.74rem; color: var(--color-text-3, #8B98A1); white-space: nowrap; }

.je-tuning-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px;
  margin-bottom: 4px;
  border-radius: var(--radius, 18px);
  background: var(--color-surface-2, #F2EFE9);
}
.je-tuning-bucket {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 99px;
  background: var(--color-surface, #fff);
  font-size: 0.78rem;
}
.je-tuning-bucket-label { font-weight: 650; }
.je-tuning-bucket-count { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--color-text-2, #5C6B75); }

/* --------------------------------------------------------------------------
   Narrow phones and reduced motion
   -------------------------------------------------------------------------- */

@media (max-width: 360px) {
  .je-headline-name { font-size: 1.55rem; }
  .je-action { min-height: 56px; font-size: 0.64rem; }
  .je-action .material-symbols-rounded { font-size: 20px; }
  .je-triage-grid { grid-template-columns: 1fr; }
  .je-tuning-num { width: 54px; }
}

@media (prefers-reduced-motion: reduce) {
  .je-sheet, .je-sheet-overlay, .je-progress-fill, .je-btn, .je-action { transition: none; }
}

/* ==========================================================================
   Tags, filters, and the ask-me gender triage.

   Everything below is additive: nothing above it changed. Same `je-` prefix,
   same tokens, same 44px thumb rule.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Tag editor — contact detail and Quick Add share this component
   -------------------------------------------------------------------------- */

.je-tag-editor { padding: 12px 14px; }
.je-form .je-tag-editor { padding: 0; }

.je-tag-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 10px; }
.je-tag-empty { font-size: 0.83rem; color: var(--color-text-3, #8B98A1); margin: 0 0 8px; }

.je-tag-removable {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 0 4px 0 11px;
  min-height: 34px;
  background: color-mix(in srgb, var(--jade, #00D4AA) 14%, var(--color-surface, #fff));
  color: var(--jade-dark, #00775F);
  border: 1px solid color-mix(in srgb, var(--jade, #00D4AA) 32%, transparent);
}
.je-tag-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  color: inherit;
  opacity: 0.6;
}
.je-tag-x:active { opacity: 1; background: color-mix(in srgb, var(--jade, #00D4AA) 22%, transparent); }
.je-tag-x .material-symbols-rounded { font-size: 17px; }

.je-tag-input-row { display: flex; gap: 8px; align-items: stretch; }
.je-tag-input { flex: 1; min-width: 0; }
.je-tag-add {
  flex: 0 0 auto;
  width: 46px;
  border-radius: var(--radius-sm, 10px);
  background: var(--jade, #00D4AA);
  color: #062018;
  display: grid;
  place-items: center;
}
.je-tag-add:active { transform: scale(0.94); }

.je-tag-suggest {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 9px;
}
.je-tag-suggestion {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid var(--color-border, #E4E0D8);
  background: var(--color-surface, #fff);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--color-text-2, #5C6B75);
}
.je-tag-suggestion:active { background: var(--color-surface-2, #F2EFE9); }
.je-tag-suggestion.is-new { border-style: dashed; color: var(--jade-dark, #00775F); }
.je-tag-suggestion-count { opacity: 0.55; font-variant-numeric: tabular-nums; }
.je-tag-suggestion-icon { font-size: 17px; }

/* --------------------------------------------------------------------------
   Tag browser
   -------------------------------------------------------------------------- */

.je-tag-browser {
  border-radius: var(--radius, 18px);
  overflow: hidden;
  border: 1px solid var(--color-border, #E4E0D8);
  background: var(--color-surface, #fff);
}
.je-tag-browse-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 52px;
  padding: 8px 12px;
  text-align: left;
  border-bottom: 1px solid var(--color-border, #E4E0D8);
}
.je-tag-browse-row:last-child { border-bottom: 0; }
.je-tag-browse-row:active { background: var(--color-surface-2, #F2EFE9); }
.je-tag-browse-name {
  font-weight: 650;
  font-size: 0.94rem;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 45%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.je-tag-browse-bar {
  flex: 1 1 auto;
  min-width: 20px;
  height: 6px;
  border-radius: 999px;
  background: var(--color-surface-2, #F2EFE9);
  overflow: hidden;
}
.je-tag-browse-fill { display: block; height: 100%; background: var(--jade, #00D4AA); border-radius: 999px; }
.je-tag-browse-count {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 0.84rem;
  color: var(--color-text-2, #5C6B75);
}
.je-tag-people { border-radius: var(--radius, 18px); overflow: hidden; border: 1px solid var(--color-border, #E4E0D8); margin-top: 14px; }

/* --------------------------------------------------------------------------
   Active filters — nothing narrows the list invisibly
   -------------------------------------------------------------------------- */

.je-active-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  margin: -4px 0 14px;
}
.je-active-filters[hidden] { display: none; }

.je-active-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 34px;
  padding: 0 6px 0 12px;
  border-radius: 999px;
  background: var(--ink, #0D1B2A);
  color: var(--color-bg, #FAF9F6);   /* inverted surface — flips with --ink */
  font-size: 0.8rem;
  font-weight: 650;
  max-width: 100%;
}
.je-active-chip > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.je-active-chip:active { transform: scale(0.96); }
.je-active-chip-x { font-size: 17px; opacity: 0.75; flex-shrink: 0; }
.je-active-chip.is-sort {
  background: var(--color-surface, #fff);
  color: var(--color-text-2, #5C6B75);
  border: 1px solid var(--color-border, #E4E0D8);
  padding: 0 12px 0 8px;
}

.je-active-clear {
  min-height: 34px;
  padding: 0 6px;
  font-size: 0.8rem;
  font-weight: 650;
  color: var(--jade-dark, #00775F);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* --------------------------------------------------------------------------
   The filter pill — bottom-left, mirroring Package A's Quick Add FAB so both
   thumbs have something to reach. Fixed, not in the scroll flow, because a
   2,354-row list means "scroll back to the top to change a filter" is not a
   real affordance.
   -------------------------------------------------------------------------- */

.je-filter-pill {
  position: fixed;
  left: calc(var(--gutter, 18px) - 2px);
  /* Above the tab bar, not inside it: the Quick Add FAB already owns the
     nav's own footprint on the right, and a second control docked there
     would sit on top of two real tabs. */
  bottom: calc(var(--nav-height, 64px) + var(--safe-bottom, 0px) + 12px);
  z-index: 65;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 48px;
  padding: 0 17px;
  border-radius: 999px;
  background: var(--ink, #0D1B2A);
  color: var(--color-bg, #FAF9F6);   /* inverted surface — flips with --ink */
  font-size: 0.88rem;
  font-weight: 650;
  box-shadow: var(--shadow-lg, 0 10px 36px rgba(13, 27, 42, 0.14));
  transition: transform var(--transition, 180ms ease);
}
.je-filter-pill:active { transform: scale(0.94); }
.je-filter-pill .material-symbols-rounded { font-size: 22px; }
.je-filter-pill.is-on { background: var(--jade, #00D4AA); color: #062018; }
.je-filter-pill-badge {
  min-width: 21px;
  height: 21px;
  padding: 0 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.22);
  display: grid;
  place-items: center;
  font-size: 0.72rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.je-filter-pill.is-on .je-filter-pill-badge { background: rgba(6, 32, 24, 0.18); }
.je-filter-pill-badge[hidden] { display: none; }

@media (min-width: 720px) {
  .je-filter-pill { left: calc(50% - (var(--page-max, 520px) / 2) + var(--gutter, 18px) - 2px); }
}

/* --------------------------------------------------------------------------
   Filter sheet
   -------------------------------------------------------------------------- */

.je-filter-sheet { padding-bottom: 4px; }
.je-filter-group { margin-bottom: 18px; }
.je-filter-group-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 8px;
}
.je-filter-group-title {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-3, #8B98A1);
}
.je-filter-group-note { font-size: 0.75rem; color: var(--color-text-3, #8B98A1); font-style: italic; }
.je-filter-group-head .je-link-btn { margin-left: auto; }
.je-filter-chips { margin-bottom: 0; max-height: 168px; overflow-y: auto; }
.je-filter-triage { margin-top: 10px; }

/* --------------------------------------------------------------------------
   Gender triage — three big targets, same shape as the tier sprint
   -------------------------------------------------------------------------- */

.je-gender-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 18px;
}
.je-gender-btn {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 96px;
  padding: 12px;
  border-radius: var(--radius, 18px);
  border: 2px solid var(--tier-color, var(--color-border, #E4E0D8));
  background: color-mix(in srgb, var(--tier-color, #7A8B99) 8%, var(--color-surface, #fff));
  color: var(--color-text, #16242E);
  transition: transform var(--transition, 180ms ease);
}
.je-gender-btn:active { transform: scale(0.96); }
.je-gender-btn.is-skip { grid-column: 1 / -1; min-height: 60px; flex-direction: row; gap: 8px; }
.je-gender-icon { font-size: 30px; color: var(--tier-color, #7A8B99); }
.je-gender-btn.is-skip .je-gender-icon { font-size: 22px; }
.je-gender-label { font-weight: 700; font-size: 1rem; }
.je-gender-btn .je-triage-key {
  position: absolute;
  top: 8px; right: 10px;
  font-size: 0.68rem;
  font-weight: 700;
  opacity: 0.4;
}

/* A dial holding a guess rather than an answer says so at a glance. */
.je-dial.is-guess .je-dial-value {
  font-style: italic;
  color: var(--color-warning, #E8A87C);
}

.je-bucket-flat { border: 0; background: transparent; padding: 0; }
.je-bucket-flat .je-rows {
  border-radius: var(--radius, 18px);
  overflow: hidden;
  border: 1px solid var(--color-border, #E4E0D8);
  background: var(--color-surface, #fff);
}

@media (max-width: 360px) {
  .je-filter-pill { padding: 0 14px; }
  .je-filter-pill-label { display: none; }
}

/* ==========================================================================
   THE TWO AXES, FAVORITES, AND THE SIX-RUNG LADDER  (2026-07-29)
   ==========================================================================
   Visual rule this whole block exists to enforce: a CIRCLE and a TAG must
   never be mistaken for each other, and a STAR must never be mistaken for
   either. So circles are coloured lozenges with a dot and a plain name; tags
   keep their jade '#hashtag' pill; the star is the only warm-gold thing in the
   app and appears nowhere else.
   ========================================================================== */

/* --- the star ------------------------------------------------------------ */

.je-star {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--color-text-3, #8B98A1);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 120ms ease, color 120ms ease;
}
.je-star:active { transform: scale(0.88); }
.je-star.is-on { color: var(--star, #E8B33C); }
/* Every size is a 44px TARGET; only the glyph inside changes. A star small
   enough to look right in a dense list row is not a star small enough to hit,
   and the app's own layout audit (tools/integration-verify.mjs) enforces the
   44px floor — it caught exactly this on the first pass. */
.je-star-sm,
.je-star-md,
.je-star-lg { width: 44px; height: 44px; }
.je-star-sm .je-star-icon { font-size: 20px; }
.je-star-md .je-star-icon { font-size: 23px; }
.je-star-lg .je-star-icon { font-size: 26px; }
/* Filled stars get the optical weight the outline version lacks. */
.je-star.is-on .je-star-icon { font-variation-settings: 'FILL' 1; }

/* Row-level: two 44px targets side by side under the tier chip, so the row
   keeps the height it always had (chip + one 44px control) instead of growing
   a third stacked row. Padding is trimmed inward so the two 44px boxes do not
   push the row's content narrower than it was. */
.je-row-side-actions { display: flex; align-items: center; gap: 0; margin-right: -6px; }
.je-mini-side { display: flex; align-items: center; gap: 0; flex-shrink: 0; margin-right: -4px; }

/* The bigger, labelled form used in the filter sheet and Quick Add. */
.je-star-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  padding: 10px 14px;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  text-align: left;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: var(--radius-sm, 10px);
  background: var(--color-surface, #fff);
  color: var(--color-text-2, #5C6B75);
  cursor: pointer;
}
.je-star-toggle .je-star-icon { font-size: 22px; color: var(--color-text-3, #8B98A1); }
.je-star-toggle-text { flex: 1; min-width: 0; }
.je-star-toggle.is-on {
  border-color: var(--star, #E8B33C);
  background: color-mix(in srgb, var(--star, #E8B33C) 12%, var(--color-surface, #fff));
  color: var(--color-text, #16242E);
}
.je-star-toggle.is-on .je-star-icon {
  color: var(--star, #E8B33C);
  font-variation-settings: 'FILL' 1;
}
.je-form .je-star-toggle { margin-top: 4px; }

/* Star chip in the Circle's fast-path chip row. */
.je-chip-star.is-on {
  background: var(--star, #E8B33C);
  border-color: var(--star, #E8B33C);
  color: #2A1F06;
}
.je-chip-star-icon { font-size: 18px; }
.je-chip-star.is-on .je-chip-star-icon { font-variation-settings: 'FILL' 1; }

/* "Hide Orbit" chip, same row. Deliberately NOT given its own colour: the
   inherited .je-chip.is-on ink treatment is this row's one word for "this
   toggle is on", and inventing a second one here would make the row read as
   two different controls. Only the icon and the label change state. */
.je-chip-hide-icon { font-size: 18px; }
.je-chip-hide.is-on .je-chip-hide-icon { font-variation-settings: 'FILL' 1; }
.je-active-chip-hide { font-size: 15px; }

/* Triage: top-right of the card, deliberately out of the thumb arc that the
   tier buttons occupy. */
.je-triage-star { position: absolute; top: 8px; right: 8px; }
.je-triage-card { position: relative; }

/* --- circles: AXIS 2 ---------------------------------------------------- */

.je-circle-dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--circle-color, #8B98A1);
}
.je-circle-dot-lg { width: 13px; height: 13px; display: inline-block; margin-right: 8px; }

/* The editable grid (contact detail, Quick Add) and the filter sheet's row
   share one chip so membership looks the same wherever it is set. */
/* Inside a detail-screen section the picker owns its own gutter, matching
   .je-tag-editor; inside a form it inherits the form's. */
.je-circle-picker { padding: 0; }
.je-section-body > .je-circle-picker { padding: 0 14px 12px; }
.je-section-body > .je-section-note { padding: 12px 14px 0; margin: 0 0 4px; }
.je-circle-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.je-circle-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding: 9px 13px;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  white-space: nowrap;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: 99px;
  background: var(--color-surface, #fff);
  color: var(--color-text-2, #5C6B75);
  cursor: pointer;
  transition: transform 120ms ease;
}
.je-circle-chip:active { transform: scale(0.96); }
.je-circle-chip.is-on {
  border-color: var(--circle-color, #8B98A1);
  background: color-mix(in srgb, var(--circle-color, #8B98A1) 16%, var(--color-surface, #fff));
  color: var(--color-text, #16242E);
}
.je-circle-chip.is-orphan { border-style: dashed; }
.je-circle-chip-check { font-size: 17px; color: var(--circle-color, #8B98A1); }
.je-circle-chip-name { overflow: hidden; text-overflow: ellipsis; max-width: 12em; }

/* ── the filter sheet's circle row: name + eye, two buttons ────────────────
   Jake, 2026-08-30: "a little eyeball next to each one for visibility ... so I
   can just hide all my college friends."

   They LOOK like one lozenge and they ARE two tap targets. The seam between
   them is a real 1px border, not a hover affordance — on a phone there is no
   hover, so the only thing telling a thumb that this half does something
   different from that half is the line and the icon. Both halves clear 44px in
   both directions; the eye is square so it cannot shrink under its own icon.

   Only the filter sheet composes the chip this way — .je-circle-chip on its own
   (contact detail, Quick Add, triage) is untouched, which is why every rule
   here is scoped under .je-circle-filter. */
.je-circle-filter { display: inline-flex; align-items: stretch; }
.je-circle-filter .je-circle-chip {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: 0;
}
.je-circle-eye {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  font: inherit;
  border: 1px solid var(--color-border, #E4E0D8);
  border-radius: 0 99px 99px 0;
  background: var(--color-surface, #fff);
  color: var(--color-text-3, #8B98A1);
  cursor: pointer;
  transition: transform 120ms ease;
}
.je-circle-eye:active { transform: scale(0.96); }
.je-circle-eye-icon { font-size: 19px; }
/* Lit means "this circle is off the list right now". Filled icon + the circle's
   own colour, matching .je-chip-hide.is-on on the Circle screen. */
.je-circle-eye.is-on {
  border-color: var(--circle-color, #8B98A1);
  background: color-mix(in srgb, var(--circle-color, #8B98A1) 16%, var(--color-surface, #fff));
  color: var(--circle-color, #8B98A1);
}
.je-circle-eye.is-on .je-circle-eye-icon { font-variation-settings: 'FILL' 1; }
/* The name goes struck through and quiet, so a glance down the list reads which
   circles are off WITHOUT decoding six eye icons one at a time. */
.je-circle-filter.is-hidden .je-circle-chip { opacity: 0.55; }
.je-circle-filter.is-hidden .je-circle-chip-name { text-decoration: line-through; }

.je-circle-foot { display: flex; flex-direction: column; gap: 8px; }
.je-circle-new-input { flex: 1; min-width: 0; }

/* Read-only lozenges under a name in a list row. Smaller and quieter than the
   editable chip — this is information, not a control. */
.je-circle-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 3px; }
.je-circle-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px 2px 6px;
  font-size: 0.68rem;
  font-weight: 650;
  line-height: 1.5;
  white-space: nowrap;
  border-radius: 99px;
  border: 1px solid color-mix(in srgb, var(--circle-color, #8B98A1) 40%, transparent);
  background: color-mix(in srgb, var(--circle-color, #8B98A1) 13%, transparent);
  color: var(--color-text-2, #5C6B75);
}
.je-circle-tag .je-circle-dot { width: 6px; height: 6px; }
.je-circle-tag.is-more { border-style: dashed; color: var(--color-text-3, #8B98A1); }

/* --- the Circles screen ------------------------------------------------- */

.je-circle-row { gap: 8px; }
/* This button wraps the name, the bar and the count, but it hugged its content
   at 22px tall inside a 52px row — so most of a row that LOOKS tappable was
   dead space, and it failed the 44px floor. Stretching it to the row's full
   height (and holding a 44px floor, which grows the row to 60) makes the whole
   left side of the row the target it already appeared to be. */
.je-circle-row-main {
  display: flex;
  align-items: center;
  align-self: stretch;
  min-height: 44px;
  gap: 10px;
  flex: 1;
  min-width: 0;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.je-circle-browse-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--circle-color, #8B98A1);
}
/* 38 -> 44: the icon still draws at 21px, only the tap box grew. */
.je-icon-btn-sm { width: 44px; height: 44px; border: none; background: transparent; }
.je-icon-btn-sm .material-symbols-rounded { font-size: 21px; }
.je-circle-new { margin-top: 22px; }
/* Kind badge on a circle row (decision §9) — quiet on purpose: shown only
   when Jake has typed a kind, absent (not a placeholder) when he hasn't. */
.je-circle-kind-icon { font-size: 16px; color: var(--color-text-3, #8B98A1); flex-shrink: 0; }
.je-kind-row { margin-top: 8px; margin-bottom: 0; }
.je-gutter-p { margin: 0 2px 10px; }
.je-section-note { margin: 0 0 10px; font-size: 0.78rem; }

/* The one sentence that keeps the two axes from being confused, wherever it
   appears. Reads as a note, not a warning. */
.je-axis-note {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  margin: 0 0 16px;
  padding: 11px 13px;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--color-text-2, #5C6B75);
  background: var(--color-surface-2, #F2EFE9);
  border-radius: var(--radius-sm, 10px);
}
.je-axis-note-icon { font-size: 18px; flex-shrink: 0; color: var(--color-text-3, #8B98A1); }

.je-swatch-row { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 6px; }
.je-swatch {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(13, 27, 42, 0.12);
}
.je-swatch.is-on { border-color: var(--color-text, #16242E); transform: scale(1.06); }

/* --- active-filter chips: circles get their colour back ------------------ */

.je-active-chip.has-dot { padding-left: 9px; }
.je-active-chip-dot {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--chip-color, currentColor);
}
.je-active-chip-star { font-size: 15px; color: var(--star, #E8B33C); font-variation-settings: 'FILL' 1; }

/* --- Triage Sprint: coarse pass, then refine ---------------------------- */

/* Three coarse targets: one full-width row each, so the thumb never has to
   aim sideways and the labels have room to be sentences. */
.je-triage-grid-coarse { grid-template-columns: 1fr; gap: 9px; }
.je-triage-grid-coarse .je-triage-btn {
  flex-direction: row;
  align-items: center;
  gap: 12px;
  min-height: 68px;
  padding: 12px 44px 12px 16px;
}
.je-triage-grid-coarse .je-triage-icon { font-size: 26px; color: var(--tier-color, #00D4AA); flex-shrink: 0; }
.je-triage-grid-coarse .je-triage-label,
.je-triage-grid-coarse .je-triage-cadence { display: block; }
.je-triage-grid-coarse .je-triage-btn > span:nth-child(3) { margin-left: 0; }

/* Two or three refine targets: one column too, because a three-row column of
   full-width buttons is faster to hit than a 2x2 grid with an orphan. */
.je-triage-grid-refine { grid-template-columns: 1fr; gap: 9px; }
.je-triage-grid-refine .je-triage-btn { min-height: 64px; padding: 12px 44px 12px 16px; }

/* --- every rung in the tuning panel: the rows got denser ---------------- */

.je-tuning-hint { margin: -4px 0 10px; font-size: 0.76rem; }

/* --- four header actions at 390px --------------------------------------- */

.je-screen-head > div:first-child { min-width: 0; }
.je-head-actions { flex-shrink: 0; }
@media (max-width: 400px) {
  .je-head-actions { gap: 5px; }
  /* The 1.35rem shrink that used to live here is gone: it fired at exactly the
     390px target, which is what made `circle`'s heading render two steps
     smaller than `nearby`'s. Measured at 390px, "My Circle" is ~118px wide at
     the unified size against four 44px actions starting at x=181 — it fits,
     and longer headings on this class have no actions beside them. */
}

/* ── DENSITY ────────────────────────────────────────────────────────────────
   Three row sizes on one list, cycled by .je-chip-density. Standard is the
   default and is deliberately untouched by everything below — Jake likes the
   current view and this feature is additive to it, never a replacement.

   All three keep every person on the list. Density hides nobody; it only
   changes how much of each person a row spends space on. That is why the
   control is not lit like a filter chip and carries no count.
   -------------------------------------------------------------------------- */

.je-chip-density { gap: 4px; }
.je-chip-density .je-chip-density-icon { font-size: 17px; opacity: 0.75; }

/* ── COMPACT ── the ring survives at 28px because it encodes the score, which
   is why the list is ordered the way it is. The score NUMBER goes, though: the
   ring already says it, and two of the same fact is what makes a row tall.

   THE ROW'S HEIGHT WAS NEVER THE TEXT. Measured on a real row: 149px total, of
   which .je-row-side is 136px and the entire main column is 52px. The side
   column stacks three controls VERTICALLY, so shrinking the avatar or clamping
   the why line moves the number by single-digit pixels — the first cut of this
   feature did exactly that and bought 6px.

   So Compact turns that column on its side. Same controls, same targets,
   nothing removed: laid in a row they occupy one band instead of three, and
   the row collapses to roughly the height of its own content. */
.je-rows.is-compact .je-row { padding: 3px 12px; }
.je-rows.is-compact .je-row-main { gap: 8px; }
.je-rows.is-compact .je-row-why { -webkit-line-clamp: 1; line-clamp: 1; }
.je-rows.is-compact .je-row-score { display: none; }
.je-rows.is-compact .je-row-name { font-size: 0.92rem; }
.je-rows.is-compact .je-row-side {
  flex-direction: row;
  align-items: center;
  gap: 2px;
}
.je-rows.is-compact .je-row-side-actions { flex-direction: row; align-items: center; gap: 2px; }
/* The add-to-circle button carries a text label ("Circle") that only earns its
   width in a vertical stack. Side by side it is the widest control for the
   least-used action, so it sheds the word and keeps the glyph. */
/* Add-to-circle comes off entirely at Compact. Measured, the name column was
   still truncating at 145px with it present; it is the least-reached control
   of the four, and it lives on the contact's own page and at Standard. Its
   32px plus gaps goes back to the name, which is the thing Compact exists to
   show more of. */
.je-rows.is-compact .je-row-addcircle { display: none; }

/* THE FIRST HORIZONTAL VERSION BROKE THE ROW, and the measurement says why.
   Laid on its side the tier chip is 120px wide — it carries a text label
   ("Inner Circle") that costs nothing stacked but a third of the row beside
   the name. Measured: side column 246px of a 390px row, leaving the name
   column FORTY-SIX PIXELS. Names truncated to nothing and the chips had
   nowhere to sit, which is the overlap Jake reported.

   So at Compact the tier chip sheds its label and caret and keeps its dot.
   The colour is the signal; the word was never the reason it is there. The
   same tier colour also rides the row as --tier-color, so nothing is lost.
   The 44px invisible hit layer on .is-interactive is untouched — the badge
   shrinks, the touch target does not. */
.je-rows.is-compact .je-tier-chip span:not(.je-tier-dot) { display: none; }
.je-rows.is-compact .je-tier-chip .je-tier-caret { display: none; }
.je-rows.is-compact .je-tier-chip { padding: 5px; gap: 0; }

/* Circle chips are a second, wrapping row of pills inside the text column.
   At Compact the why line already carries the context and the pills are what
   push the name into an ellipsis, so they come off. They are still on the
   contact, on their page, and at Standard. */
.je-rows.is-compact .je-row-text > *:not(.je-row-name-line):not(.je-row-why) { display: none; }

/* Belt and braces: whatever the side column costs, the name column must be
   allowed to shrink rather than force a horizontal overflow. */
.je-rows.is-compact .je-row-main,
.je-rows.is-compact .je-row-text { min-width: 0; }
.je-rows.is-compact .je-row-side { flex-shrink: 0; }

/* ── NAMES ── name only. The side column is not hidden here; circle.js never
   builds it at this density, so there are no invisible tap targets stacked
   under the row. The whole row is one button that opens the contact.

   36px is under the 44px one-row-one-thumb rule that governs Standard, and
   that is a deliberate, bounded exception: 44px protects a row carrying THREE
   adjacent targets, where a stray tap logs a touch or restacks a tier. This
   row has exactly one target spanning its full width, so the failure mode a
   44px band exists to prevent cannot occur — the worst case is opening the
   person you were already pointing at. */
.je-rows.is-names .je-row { padding: 0; }
.je-rows.is-names .je-row-main {
  min-height: 36px;
  gap: 0;
  padding: 0 12px;
  border-left: 3px solid var(--tier-color, var(--color-border, #E4E0D8));
}
.je-rows.is-names .je-row-text { gap: 0; }
.je-rows.is-names .je-row-name { font-size: 0.95rem; font-weight: 600; }
.je-rows.is-names .je-row-main:active { background: var(--color-surface-2, #F4F1EA); }

/* Denser lists mean more rows behind one "show more"; the separator earns its
   contrast back by getting lighter as the rows get shorter. */
.je-rows.is-names .je-row + .je-row { border-top-color: color-mix(in srgb, var(--color-border, #E4E0D8) 55%, transparent); }

/* ── A–Z INDEX RAIL ─────────────────────────────────────────────────────────
   The alphabet strip down the right edge, and the room the list gives up for
   it. Behaviour lives in components/az-rail.js; this file owns the geometry,
   and the geometry is the whole reason the feature is safe to ship.

   THE COLLISION IT HAS TO AVOID. Every row carries .je-row-side, a column of
   real tap targets — the tier chip, add-to-circle, the star, the touch log —
   that runs to the right edge of .screen. Measured at 390x844 it is 107px wide
   at Compact. A rail floating over that edge would put a scroll gesture on top
   of four buttons, and every drag would end in an accidental touch-log.

   So the rail does NOT float over the rows: while it exists, the content
   column gives up its width, exactly as `body[data-route="me"] .screen` gives
   up the FAB's column. Measured at 390px: content now ends at x=338, the
   rail's hit area starts at x=356, the letters at x=362. Eighteen clear pixels
   between the last button and the first pixel the rail will answer to.

   THE OTHER COLLISION. Package A's Quick Add FAB occupies [320, 712, 54, 54].
   The rail's bottom is pinned above it (nav + safe area + 76px = y≤704) rather
   than to the viewport, so the two never share a pixel and the last letters of
   the alphabet stay reachable. Derived from the FAB's own geometry, like
   --fab-clear, so it moves if the FAB does.

   The class is toggled by circle.js and removed on teardown — it must never
   outlive the screen, or every other route would render 34px narrower.
   -------------------------------------------------------------------------- */

:root { --az-rail-w: 34px; }

body.je-az-on .screen { padding-right: calc(var(--gutter, 18px) + var(--az-rail-w)); }

.je-az-rail {
  position: fixed;
  right: 0;
  /* Below the header, search box and chip rows on a fresh screen — those
     scroll away, but starting the rail under them keeps it from reading as
     part of the header chrome. */
  top: calc(var(--safe-top, 0px) + 168px);
  bottom: calc(var(--nav-height, 64px) + var(--safe-bottom, 0px) + 76px);
  width: var(--az-rail-w);
  z-index: 65;              /* with the filter pill: above content, below the FAB */
  display: flex;
  align-items: center;
  justify-content: flex-end;
  /* The gesture is ours. Without this the browser claims a vertical drag as a
     page scroll and the rail moves the list a second time, fighting itself. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.je-az-strip {
  width: 22px;
  height: 100%;
  /* A very tall window would otherwise spread 27 letters over 900px, which
     turns a thumb-flick into an arm movement. Capped and centred instead. */
  max-height: 560px;
  margin-right: 6px;
  display: flex;
  flex-direction: column;
  border-radius: 999px;
  transition: background var(--transition, 180ms ease);
}
.je-az-rail.is-dragging .je-az-strip {
  background: color-mix(in srgb, var(--color-surface-2, #F4F1EA) 88%, transparent);
  box-shadow: var(--shadow, 0 6px 20px rgba(13, 27, 42, 0.08));
}

/* `flex: 1` and nothing else is load-bearing: az-rail.js finds the letter under
   a finger by dividing the strip's height into equal bands, and that arithmetic
   is only exact while every letter really is the same height. Do not give these
   padding, a min-height, or a different font-size for '#'. */
.je-az-letter {
  flex: 1 1 0;
  min-height: 0;
  padding: 0;
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  color: var(--color-text-2, #6B6B6B);
}
/* A letter nobody is filed under. Dimmed, never removed and never disabled:
   the drag still passes through it and it still resolves forward to the next
   letter that has people (circle.js azTargetIndex). */
.je-az-letter.is-empty { opacity: 0.3; }
.je-az-letter.is-current { color: var(--jade, #00D4AA); }

/* The floating readout. At 10px, under a thumb, the letter you are on is the
   one thing you cannot see — which is why iOS has had this bubble since 2007.
   Positioned by az-rail.js against the letter's own box, so it snaps letter to
   letter rather than sliding with the finger. */
.je-az-bubble {
  position: absolute;
  right: calc(var(--az-rail-w) + 6px);
  transform: translateY(-50%);
  width: 58px;
  height: 58px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--ink, #0D1B2A);
  color: var(--color-bg, #FAF9F6);
  font-size: 1.6rem;
  font-weight: 750;
  box-shadow: var(--shadow-lg, 0 10px 36px rgba(13, 27, 42, 0.14));
  pointer-events: none;
}
.je-az-bubble[hidden] { display: none; }

/* Desktop / tablet: #app is centred at --page-max, so the viewport's right
   edge is not the app's. Follows the Quick Add FAB and the filter pill. */
@media (min-width: 720px) {
  .je-az-rail { right: calc(50% - (var(--page-max, 520px) / 2)); }
}

/* ── the filter sheet's "How you read it" section ───────────────────────────
   Two sub-controls under one heading — page size and the A–Z basis. They get
   their own smaller heading level because they are settings inside a section,
   not two more filter axes; styling them like .je-filter-group-title would put
   them on the same visual footing as Tags and Circles, which is exactly the
   confusion the section exists to avoid. */
.je-filter-sub { margin-top: 12px; }
.je-filter-sub-title {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--color-text-2, #6B6B6B);
  margin-bottom: 6px;
}
.je-filter-sub-note {
  font-size: 0.76rem;
  line-height: 1.4;
  color: var(--color-text-2, #6B6B6B);
  margin-top: 6px;
}
