/* ============================================================================
   components.css — DESIGN.md §4. Every component carries its full state set:
   default / hover / active / focus-visible / disabled.
   ========================================================================== */

/* ── 4.1 Buttons ────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 48px; padding: 0 18px; width: 100%;
  border: 1.5px solid transparent; border-radius: var(--r-md);
  font: 700 var(--fs-body)/1 var(--font-ui);
  cursor: pointer; position: relative; overflow: hidden;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--t-hover) var(--ease-out),
              color var(--t-hover) var(--ease-out),
              border-color var(--t-hover) var(--ease-out),
              transform var(--t-tap) var(--ease-out);
}
.btn:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.btn:active { transform: scale(.972); }
.btn[disabled], .btn[aria-disabled="true"] {
  cursor: not-allowed; transform: none;
  background: var(--surface-sunk); color: var(--text-mute); border-color: var(--line);
}
.btn--sm  { min-height: 44px; padding: 0 var(--sp-4); font-size: var(--fs-body-s); width: auto; }
.btn--auto{ width: auto; }

.btn--primary { background: var(--brand-accent); color: var(--brand-accent-fg); }
.btn--ink     { background: var(--ink); color: var(--text-on-ink); }
.btn--ghost   { background: var(--surface); color: var(--ink); border-color: var(--line); }
.btn--on-ink  { background: var(--sky); color: var(--ink); }

.btn--primary:active { background: var(--sky-ink); color: var(--text-on-ink); }
.btn--ink:active     { background: var(--ink-soft); }
.btn--ghost:active   { background: var(--mist); }
.btn--on-ink:focus-visible { outline-color: rgba(var(--surface-rgb), .75); }

@media (hover: hover) {
  .btn--primary:hover { background: var(--sky-ink); color: var(--text-on-ink); }
  .btn--ink:hover     { background: var(--ink-soft); }
  .btn--ghost:hover   { background: var(--surface-hover); border-color: var(--line-strong); }
  .btn--on-ink:hover  { background: var(--sky-lift); }
  .btn[disabled]:hover, .btn[aria-disabled="true"]:hover {
    background: var(--surface-sunk); color: var(--text-mute); border-color: var(--line);
  }
}

/* One-shot CTA sheen on screen entry (DESIGN.md §7.6) — never loops */
.btn--primary.is-sheened::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg,
    rgba(var(--surface-rgb), 0)   30%,
    rgba(var(--surface-rgb), .38) 50%,
    rgba(var(--surface-rgb), 0)   70%);
  background-size: 260% 100%;
  animation: sheen 700ms var(--ease-out) 1 both;
  pointer-events: none;
}
@keyframes sheen { from { background-position: 180% 0; } to { background-position: -80% 0; } }

/* ── 4.2 Cards ──────────────────────────────────────────────────────────── */
.card {
  position: relative;
  /* Glass. .62 lets roughly 60% more of the ground's colour through than the
     .76 this started at — rgb(238,226,241) over the violet end instead of
     rgb(244,237,246). It is only affordable because --text-3, --sky-ink and
     --ok were darkened to match; at .62 with the old values they read
     4.4 / 4.4 / 4.3. */
  background: rgba(var(--surface-rgb), .62);
  /* No backdrop-filter here, deliberately. Behind every card is only .aura —
     a pure linear ramp — and a symmetric blur of a linear ramp returns the
     same ramp. No card overlaps another or the hero, so there is no edge to
     soften. Verified by rendering with and against: the two frames are
     identical. It would have been ~8 blurred backdrops per screen inside a
     scroll container, which §8 rules out anyway.
     The glass here is the translucency (cards take the ground's tint), the
     lit rim, and the pale border. */
  border: 1px solid rgba(var(--surface-rgb), .72);
  border-radius: var(--r-lg);
  padding: var(--sp-4);
  /* The inset top edge is what actually reads as glass — a lit rim where the
     pane catches light. It costs nothing and does not touch contrast. */
  box-shadow: var(--e1), inset 0 1px 0 rgba(var(--surface-rgb), .85);
  transition: box-shadow var(--t-hover) var(--ease-out),
              border-color var(--t-hover) var(--ease-out),
              transform var(--t-tap) var(--ease-out);
}
.card--flat     { box-shadow: var(--e0); }
.card--pad-5    { padding: var(--sp-5); }
.card--tappable { cursor: pointer; text-align: left; width: 100%; display: block; }
.card--tappable:active { transform: scale(.985); box-shadow: var(--e1); }
.card--tappable:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
@media (hover: hover) {
  /* Apply the same lift to informative cards as well as tappable ones. This
     keeps panels such as “My plans” from looking flatter than the cards on
     the rest of the app when a pointer is over them. */
  .card:not(.card--hero):hover {
    z-index: 1;
    border-color: var(--line-strong);
    box-shadow: var(--e-hover), inset 0 1px 0 rgba(var(--surface-rgb), .9);
  }
  .card--tappable:hover { box-shadow: var(--e-hover), inset 0 1px 0 rgba(var(--surface-rgb), .9); }
}

/* The one hero surface per screen */
.card--hero {
  /* Opaque by design: §4.1a's veil arithmetic assumes a solid Deep Navy base,
     and letting the ground show through would move every measurement. */
  background: var(--ink);
  background-image: var(--grad-deep-veil);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  border-color: transparent;
  color: var(--text-on-ink); box-shadow: var(--e-hero);
  padding: var(--sp-5); overflow: hidden;
}
.card--hero .meta, .card--hero .body, .card--hero .body-s { color: var(--text-on-ink-2); }
.card--hero .track--on-ink { background: rgba(var(--ink-rgb), .55); }
.card--hero .eyebrow { color: var(--text-on-ink-2); }
.card--hero .divider { background: var(--ink-soft); }
.card--hero > * { position: relative; }

/* A washed surface: two corner tints over White. Both are background-legal
   accents (§2.6), so this adds depth without spending an accent colour. */
.card--wash {
  /* Layered over the glass fill rather than replacing it: `background` as a
     shorthand would reset background-color and take the translucency with it. */
  background-image:
    radial-gradient(120% 96% at 100% 100%, rgba(var(--sky-rgb), .17) 0%, rgba(var(--sky-rgb), 0) 58%),
    radial-gradient(88% 78% at 0% 0%,      rgba(var(--lav-rgb), .20) 0%, rgba(var(--lav-rgb), 0) 62%);
}

/* Gradient hairline — fades out rather than stopping, so it separates without
   drawing a hard line across the card. */
.rule-grad {
  height: 1px; border: 0; margin: var(--sp-3) 0;
  background: linear-gradient(90deg,
    var(--sky) 0%, rgba(var(--sky-rgb), .22) 55%, rgba(var(--sky-rgb), 0) 100%);
}

.card--selected { border-color: var(--sky); box-shadow: 0 0 0 1.5px var(--sky), var(--e1); }

/* ── 4.10 Notched card — inverted corner in the top-right ────────────────
   The shape is a clip-path built by js/shape.js. Two consequences:
   1. clip-path clips box-shadow, so the elevation moves to a drop-shadow on
      the wrapper, which follows the clipped alpha instead of the box.
   2. clip-path also clips the border, so the notched card draws no border and
      relies on its own fill. --nw/--nh/--ni/--nc are read by shape.js. */
.notchcard {
  --nw: 132px; --nh: 48px; --ngap: 12px;
  position: relative;
  filter: drop-shadow(0 14px 22px rgba(var(--ink-rgb), .34));
  transition: filter var(--t-hover) var(--ease-out);
}
.card--notched {
  --ni: 16px;    /* inverted radius — the concave one */
  --nc: 16px;    /* convex radius on the notch's outer corners */
  border: 0;
  box-shadow: none;              /* replaced by the wrapper's drop-shadow */
  border-radius: var(--r-lg);    /* fallback shape before shape.js runs */
}
/* The badge that sits in the bite. Deliberately NOT a button: gold is
   content-only (DESIGN.md §2.5), and a gold button would break that rule.
   It carries the deadline, which is the one fact the notch exists to show. */
.notchcard__badge {
  position: absolute; top: 0; right: 0; z-index: 1;
  width: calc(var(--nw, 128px) - var(--ngap, 12px));
  min-height: calc(var(--nh, 46px) - var(--ngap, 12px));
  display: flex; align-items: center; justify-content: center; gap: 6px;
  border-radius: var(--r-pill);
  background: var(--gold); color: var(--ink);
  font: 700 var(--fs-micro)/1 var(--font-ui);
  white-space: nowrap;
}
.notchcard__badge .chip__dot { background: var(--ink); opacity: .55; }

/* Neutral variant. Gold means attention (a deadline); an eCard being valid is
   reassurance, not urgency, so this one is White with an --ok status dot —
   colour paired with a word, never colour alone (§2.6). White also keeps the
   badge off the accent, which the card's own CTA is already using. */
.notchcard__badge--plain {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line);
}
.notchcard__badge--plain .chip__dot { background: var(--ok); opacity: 1; }
@media (hover: hover) {
  .notchcard:hover { filter: drop-shadow(0 22px 38px rgba(var(--ink-rgb), .42)); }
}

/* ── 4.3 Bottom tab bar — glass pill with a gradient outline ─────────────
   The active indicator is not a filled pill but a single continuous stroke:
   it runs the bar's bottom edge, rises into a hump that cradles the active
   tab, and falls back down. js/shape.js generates the path; the stroke carries
   the brand Deep Gradient, fading to nothing at both ends so it never
   terminates abruptly against the pill's edge.

   The bar is glass like the sheet, and for the same reason it is more opaque
   than a card: content scrolls behind it, including the dark hero, so its
   backdrop is unknown. At .88 its labels clear AA over the darkest thing the
   app can put behind them (--text-3 reads 4.66:1 there). */
.tabbar {
  position: absolute; z-index: 40;
  /* Match .screen's horizontal padding so the pill, cards, and section
     borders all share the same 348px content grid inside the phone frame. */
  left: var(--sp-5); right: var(--sp-5);
  bottom: calc(var(--sp-3) + env(safe-area-inset-bottom));
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  padding: 6px 6px 4px;
  background: rgba(var(--surface-rgb), .88);
  -webkit-backdrop-filter: blur(16px) saturate(1.6);
          backdrop-filter: blur(16px) saturate(1.6);
  border: 1px solid rgba(var(--surface-rgb), .72);
  border-radius: var(--r-pill);
  /* Cast some elevation upward as well: this bar sits above scrolling
     content, so a downward-only shadow mostly falls into its own safe area. */
  /* Three broad, low-contrast layers make the bar feel lifted without a
     hard dark edge: a soft halo above, a stronger contact shadow below, and
     a long falloff into the page. */
  box-shadow: 0 -10px 26px -14px rgba(var(--ink-rgb), .38),
              0 18px 42px -12px rgba(var(--ink-rgb), .34),
              0 30px 64px -18px rgba(var(--ink-rgb), .20),
              0 3px 8px -3px rgba(var(--ink-rgb), .14),
              inset 0 1px 0 rgba(var(--surface-rgb), .9);
}
.tabbar[hidden] { display: none; }

/* The outline sits behind the tabs but above the bar's own fill. */
.tabbar__outline {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none; overflow: visible;
}
.tabbar__outline path {
  fill: none; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round;
  transition: d var(--t-screen) var(--ease-spring);
}

.tab {
  position: relative; min-height: 48px;
  display: grid; place-items: center; align-content: center; gap: 3px;
  border-radius: var(--r-pill);
  font: 600 11px/1.2 var(--font-ui); color: var(--text-3);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: color var(--t-hover) var(--ease-out);
}
.tab svg { stroke: currentColor; transition: stroke var(--t-hover) var(--ease-out); }
.tab:active svg { transform: scale(.9); }

/* The icon lifts as its tab becomes active. A CSS animation rather than a
   scripted one: the rule only starts matching at the moment aria-selected
   flips, so it fires on the change and not on every re-render — and the
   global reduced-motion block collapses it without any extra branch. */
@keyframes tab-pop {
  0%   { transform: translateY(5px) scale(.82); }
  55%  { transform: translateY(-1.5px) scale(1.08); }
  100% { transform: translateY(0) scale(1); }
}
.tab[aria-selected="true"] svg {
  animation: tab-pop 400ms var(--ease-out) both;
}
.tab:focus-visible { outline: var(--focus-ring); outline-offset: -2px; }
.tab[aria-selected="true"] { color: var(--sky-ink); }
@media (hover: hover) {
  .tab:not([aria-selected="true"]):hover { color: var(--ink); }
}

/* ── 4.4 Bottom sheet ───────────────────────────────────────────────────── */
.sheet-scrim {
  position: absolute; inset: 0; z-index: 50;
  background: rgba(var(--ink-rgb), .38);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  opacity: 0; transition: opacity var(--t-sheet) var(--ease-out);
  cursor: pointer;
}
.sheet-scrim[hidden] { display: none; }
.sheet-scrim[data-open="true"] { opacity: 1; }

.sheet {
  position: absolute; inset: auto 0 0 0; z-index: 51;
  max-height: 88%; display: flex; flex-direction: column;
  /* Sheets are more opaque than cards, and deliberately so: a sheet overlaps
     whatever is beneath it, including the dark hero card, so its backdrop is
     not the ground but an unknown — measured here as hero + scrim. At .82 its
     body text fell to ~3.9:1 over that. .88 clears AA against the darkest
     backdrop the app can put behind it. */
  background: rgba(var(--surface-rgb), .88);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
          backdrop-filter: blur(20px) saturate(1.5);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--e-sheet), inset 0 1px 0 rgba(var(--surface-rgb), .9);
  transform: translateY(100%);
  transition: transform var(--t-sheet) var(--ease-out);
}
.sheet[hidden] { display: none; }
.sheet[data-open="true"] { transform: translateY(0); }
.sheet__head { padding: var(--sp-2) var(--sp-5) 0; flex: 0 0 auto; }
.sheet__grab { width: 40px; height: 4px; border-radius: var(--r-pill); background: var(--line-strong); margin: 0 auto var(--sp-4); }
.sheet__body {
  padding: 0 var(--sp-5) calc(var(--sp-5) + env(safe-area-inset-bottom));
  overflow-y: auto; overscroll-behavior: contain; flex: 1 1 auto;
  scrollbar-width: none;
}
.sheet__body::-webkit-scrollbar { display: none; }
.sheet__foot {
  position: sticky; bottom: 0; flex: 0 0 auto;
  padding: var(--sp-3) var(--sp-5) calc(var(--sp-5) + env(safe-area-inset-bottom));
  background: linear-gradient(to top,
    rgba(var(--surface-rgb), .92) 68%, rgba(var(--surface-rgb), 0));
}
.sheet p, .sheet li { max-width: 62ch; }

/* ── 4.5 Chips / badges ─────────────────────────────────────────────────── */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 10px; border-radius: var(--r-pill);
  font: 600 var(--fs-micro)/var(--lh-micro) var(--font-ui);
  background: var(--mist); color: var(--text-2);
  border: 1px solid transparent; white-space: nowrap;
}
.chip--info   { background: var(--info-bg);   color: var(--sky-ink); }
.chip--ok     { background: var(--ok-bg);     color: var(--ok); }
.chip--warn   { background: var(--warn-bg);   color: var(--warn); }
.chip--danger { background: var(--danger-bg); color: var(--danger); }
.chip--on-ink { background: var(--ink-2);     color: var(--text-on-ink-2); }
.chip__dot    { width: 6px; height: 6px; border-radius: var(--r-pill); background: currentColor; flex: 0 0 6px; }
.chip--warn .chip__dot, .chip--on-ink .chip__dot { background: var(--gold); }  /* sanctioned gold */

.chip--filter {
  cursor: pointer; border-color: var(--line); background: var(--surface);
  min-height: 44px; padding: 0 var(--sp-3);
  transition: background var(--t-hover) var(--ease-out),
              border-color var(--t-hover) var(--ease-out),
              color var(--t-hover) var(--ease-out);
}
.chip--filter:active { transform: scale(.96); }
.chip--filter:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.chip--filter[aria-pressed="true"] { background: var(--info-bg); border-color: var(--sky); color: var(--sky-ink); }
@media (hover: hover) {
  .chip--filter:hover { background: var(--surface-hover); border-color: var(--line-strong); }
}

.chiprow {
  display: flex; gap: var(--sp-2); overflow-x: auto;
  scroll-snap-type: x proximity; scrollbar-width: none;
  margin: 0 calc(-1 * var(--sp-5)); padding: 2px var(--sp-5);
}
.chiprow::-webkit-scrollbar { display: none; }
.chiprow > * { scroll-snap-align: start; flex: 0 0 auto; }

/* ── 4.6 List row ───────────────────────────────────────────────────────── */
.row {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: 56px; padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--line);
  width: 100%; text-align: left; cursor: pointer;
  transition: background var(--t-hover) var(--ease-out),
              border-color var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out);
}
/* Interactive rows get a small surface around their content. The negative
   margin keeps labels aligned with the section heading while the hover/focus
   background gains 12px of breathing room on each side. Static rows retain
   their compact, table-like alignment. */
.row:not(.row--static) {
  position: relative;
  width: calc(100% + var(--sp-6));
  margin-inline: calc(var(--sp-3) * -1);
  padding-inline: var(--sp-3);
  border-radius: var(--r-sm);
}
.row:last-child    { border-bottom: 0; }
.row:not(.row--static):active {
  z-index: 1;
  background: rgba(var(--surface-rgb), .68);
  border-bottom-color: transparent;
  box-shadow: 0 10px 20px -16px rgba(var(--ink-rgb), .20),
              var(--e1),
              inset 0 1px 0 rgba(var(--surface-rgb), .9),
              0 0 0 1px rgba(var(--surface-rgb), .7);
}
.row:focus-visible { outline: var(--focus-ring); outline-offset: -2px; border-radius: var(--r-sm); }
.row--static       { cursor: default; }
@media (hover: hover) {
  .row:not(.row--static):hover {
    z-index: 1;
    background: rgba(var(--surface-rgb), .56);
    border-bottom-color: transparent;
    box-shadow: var(--e-hover),
                inset 0 1px 0 rgba(var(--surface-rgb), .88),
                0 0 0 1px rgba(var(--surface-rgb), .66);
  }
}
/* Plan name — its own class rather than an inline display:block, which is how
   the `display:block truncate` bug got in. */
.row__name {
  display: block;
  font: 600 var(--fs-body)/1.35 var(--font-ui); color: var(--text);
}
/* Yearly price: figure font for the amount, sans for the unit. A serif "/yr"
   reads as part of the number, which it is not. */
.row__yearly { display: flex; align-items: baseline; gap: 1px; flex: 0 0 auto; }
.row__per    { font: 400 var(--fs-body-s)/1 var(--font-ui); color: var(--text-3); }
.row__amount {
  margin-left: auto; text-align: right;
  font: 500 var(--fs-figure-m)/var(--lh-figure-m) var(--font-fig);
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}

/* ── 4.7 Field ──────────────────────────────────────────────────────────── */
.field {
  width: 100%; min-height: 48px; padding: 13px var(--sp-4);
  background: var(--surface); border: 1.5px solid var(--line);
  border-radius: var(--r-md); color: var(--text);
  font: 400 var(--fs-body)/1.4 var(--font-ui);
  transition: border-color var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out);
}
.field::placeholder { color: var(--text-mute); }
.field:focus { outline: none; border-color: var(--sky); box-shadow: 0 0 0 3px rgba(var(--sky-rgb), .28); }
.field[disabled] { background: var(--surface-sunk); color: var(--text-mute); cursor: not-allowed; }
.field[aria-invalid="true"] { border-color: var(--danger); box-shadow: 0 0 0 3px rgba(var(--danger-rgb), .18); }
@media (hover: hover) { .field:hover:not(:focus) { border-color: var(--line-strong); } }
.field__label {
  display: block; margin-bottom: var(--sp-1);
  font: 700 var(--fs-label)/var(--lh-label) var(--font-ui);
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-3);
}
.field-search { position: relative; }
.field-search .field { padding-left: 42px; }
.field-search svg { position: absolute; left: var(--sp-4); top: 50%; transform: translateY(-50%); stroke: var(--text-3); }

/* ── 4.8 Progress & ring ────────────────────────────────────────────────── */
.track { height: 8px; border-radius: var(--r-pill); background: var(--surface-sunk); overflow: hidden; }
.track--on-ink { background: var(--ink-soft); }
.track--thin   { height: 6px; }
.track__fill {
  display: block; height: 100%; border-radius: var(--r-pill);
  background: var(--grad-progress); width: 0;
  transition: width var(--t-figure) var(--ease-out);
}
.ring        { transform: rotate(-90deg); }
.ring__track { fill: none; stroke: var(--surface-sunk); }
.ring__value { fill: none; stroke: var(--brand-accent); stroke-linecap: round;
               transition: stroke-dashoffset var(--t-figure) var(--ease-out); }
.ring__grad  { fill: none; stroke-linecap: round;
               transition: stroke-dashoffset var(--t-figure) var(--ease-out); }
/* Marker at the arc's end. Fades in once the arc has finished drawing; under
   reduced motion the global duration collapse makes it appear immediately. */
.ring__marker circle       { fill: var(--surface); }
.ring__marker-dot          { fill: var(--sky-deep); }
.ring__marker {
  opacity: 0;
  animation: marker-in 240ms var(--ease-out) var(--t-figure) forwards;
  filter: drop-shadow(0 1px 3px rgba(var(--ink-rgb), .28));
}
@keyframes marker-in { to { opacity: 1; } }

.ring__own   { fill: none; stroke: var(--gold); stroke-linecap: butt;
               transition: stroke-dashoffset var(--t-figure) var(--ease-out); }
.ring__ink   { fill: none; stroke: var(--ink); stroke-linecap: butt;
               transition: stroke-dashoffset var(--t-figure) var(--ease-out); }
.ring-wrap   { position: relative; display: grid; place-items: center; }
.ring-wrap__center { position: absolute; text-align: center; }
.ring-wrap__center--stack { display: grid; justify-items: center; gap: 1px; }
.ring-cap {
  font: 600 10px/1.3 var(--font-ui); letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-3);
}
.ring-fig {
  font-size: 30px; line-height: 1.1; letter-spacing: -.015em; color: var(--text);
}
/* A date is not a label — uppercasing it makes it shout. */
.ring-cap--date { text-transform: none; letter-spacing: 0; font-weight: 500; }
/* Centre disc — keeps the figure legible over a heavy stroke, and matches
   the reference dashboard's treatment of its donut centre. */
.ring-wrap--disc .ring-wrap__center {
  width: 176px; height: 176px; border-radius: var(--r-pill);
  display: grid; place-content: center; gap: 2px;
  background: var(--surface); box-shadow: var(--e1);
}
.ring-wrap--disc .fig-xl { font-size: 42px; }

/* ── 4.9 Carrier mark ───────────────────────────────────────────────────── */
.mark {
  width: 34px; height: 34px; flex: 0 0 34px;
  display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font: 700 12px/1 var(--font-ui); letter-spacing: .02em; color: var(--ink);
}
.mark--brand { background: var(--brand-mark-bg); color: var(--brand-accent-fg); border-color: transparent; }
.mark--lg    { width: 56px; height: 56px; flex-basis: 56px; border-radius: var(--r-md); font-size: 19px; }
.mark--tint  { background: var(--info-bg); border-color: transparent; color: var(--sky-ink); }

/* ── Discs (circular actions) ───────────────────────────────────────────── */
.disc {
  width: 44px; height: 44px; flex: 0 0 44px;
  display: grid; place-items: center; border-radius: var(--r-pill);
  background: var(--brand-accent); color: var(--brand-accent-fg); cursor: pointer;
  transition: transform var(--t-tap) var(--ease-out), background var(--t-hover) var(--ease-out);
}
.disc svg { stroke: currentColor; }
.disc:active { transform: scale(.92); }
.disc:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.disc--sm { width: 34px; height: 34px; flex-basis: 34px; }
.disc--ghost { background: var(--surface); color: var(--ink); border: 1.5px solid var(--line); }
@media (hover: hover) {
  .disc:hover { background: var(--sky-ink); color: var(--text-on-ink); }
  .disc--ghost:hover { background: var(--surface-hover); color: var(--ink); border-color: var(--line-strong); }
}

/* ── Avatar ─────────────────────────────────────────────────────────────── */
.avatar {
  width: 34px; height: 34px; flex: 0 0 34px;
  display: grid; place-items: center; border-radius: var(--r-pill);
  background: var(--lav); color: var(--ink);
  font: 700 12px/1 var(--font-ui);
}

/* ── Segmented control ──────────────────────────────────────────────────── */
.seg {
  display: flex; gap: 2px; padding: 3px;
  background: var(--surface-sunk); border-radius: var(--r-md);
}
.seg__opt {
  flex: 1; min-height: 44px; border-radius: var(--r-sm);
  font: 600 var(--fs-body-s)/1 var(--font-ui); color: var(--text-2);
  cursor: pointer;
  transition: background var(--t-hover) var(--ease-out), color var(--t-hover) var(--ease-out);
}
.seg__opt:focus-visible { outline: var(--focus-ring); outline-offset: -2px; }
.seg__opt[aria-selected="true"] { background: var(--surface); color: var(--ink); box-shadow: var(--e1); }
@media (hover: hover) { .seg__opt:not([aria-selected="true"]):hover { color: var(--ink); } }

/* ── Choice card (radio-like, enrollment) ───────────────────────────────── */
.choice {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  width: 100%; text-align: left; cursor: pointer;
  padding: var(--sp-4); border-radius: var(--r-md);
  border: 1.5px solid var(--line); background: var(--surface);
  transition: border-color var(--t-hover) var(--ease-out),
              background var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out),
              transform var(--t-tap) var(--ease-out);
}
.choice:active { transform: scale(.985); }
.choice:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.choice[aria-checked="true"] { border-color: var(--sky); background: var(--info-bg); }
@media (hover: hover) {
  .choice:hover { border-color: var(--line-strong); box-shadow: var(--e-hover); }
}
.choice__tick {
  width: 20px; height: 20px; flex: 0 0 20px; margin-top: 2px;
  border-radius: var(--r-pill); border: 1.5px solid var(--line-strong);
  display: grid; place-items: center;
  transition: background var(--t-hover) var(--ease-out), border-color var(--t-hover) var(--ease-out);
}
.choice[aria-checked="true"] .choice__tick { background: var(--sky); border-color: var(--sky); }
.choice__tick svg { opacity: 0; stroke: var(--ink); transition: opacity var(--t-hover) var(--ease-out); }
.choice[aria-checked="true"] .choice__tick svg { opacity: 1; }

/* ── Timeline ───────────────────────────────────────────────────────────── */
.timeline { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
.timeline__item {
  display: grid; grid-template-columns: 24px 1fr; gap: var(--sp-3);
  padding-bottom: var(--sp-4); position: relative;
}
.timeline__item:not(:last-child)::before {
  content: ""; position: absolute; left: 11px; top: 22px; bottom: 0;
  width: 2px; background: var(--line);
}
.timeline__dot {
  width: 24px; height: 24px; border-radius: var(--r-pill);
  display: grid; place-items: center; position: relative; z-index: 1;
  background: var(--surface-sunk); color: var(--text-3);
}
.timeline__dot--done    { background: var(--ok-bg);   color: var(--ok); }
.timeline__dot--active  { background: var(--info-bg); color: var(--sky-ink); }
.timeline__dot svg { stroke: currentColor; }

/* ── Step dots (enrollment / claim progress) ────────────────────────────── */
.steps { display: flex; align-items: center; gap: 5px; }
.steps__dot { width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--line-strong); }
.steps__dot[data-on="true"] { background: var(--ink); }

/* ── Icon grid (Home — "every job one tap away") ────────────────────────── */
.icongrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-2); }
.icongrid__item {
  display: grid; grid-template-columns: minmax(0, 1fr);
  justify-items: center; gap: 6px; cursor: pointer;
  min-height: 48px; padding: var(--sp-1) 0; border-radius: var(--r-md);
  font: 600 var(--fs-micro)/1.25 var(--font-ui); color: var(--text-2); text-align: center;
  transition: background var(--t-hover) var(--ease-out), color var(--t-hover) var(--ease-out),
              transform var(--t-tap) var(--ease-out);
}
.icongrid__item:active { transform: scale(.94); }
.icongrid__item:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
.icongrid__tile {
  width: 46px; height: 46px; display: grid; place-items: center;
  border-radius: var(--r-md); background: var(--info-bg); color: var(--sky-ink);
  transition: background var(--t-hover) var(--ease-out);
}
.icongrid__tile svg { stroke: currentColor; }
@media (hover: hover) {
  .icongrid__item:hover { color: var(--ink); }
  .icongrid__item:hover .icongrid__tile { background: var(--surface-sunk); }
}

/* ── Bento ──────────────────────────────────────────────────────────────── */
.bento { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); align-items: start; }
.bento > .span-2 { grid-column: 1 / -1; }
