/* The cardholder app — the Business Central grammar on a driver's phone.
   ═══════════════════════════════════════════════════════════════════════════

   Its own stylesheet. `/me` used to borrow `terminal.css` on the reasoning
   that a second sheet is a second thing to keep in step — but the two
   products want opposite things. The forecourt handheld is operated by an
   attendant serving a queue: every control the same weight because any of
   them might be next. A driver's own phone is read, not operated. It answers
   one question — how much have I got — and offers one action.

   Both now speak the same language, and it is Business Central's: flat
   panes with a hairline border and no shadow, a near-black app bar, section
   headings underlined in the accent, tinted sentence-case group headers,
   fields that focus with an underline, one filled primary action and flat
   commands otherwise. Status pills stay round — the one curve the reference
   keeps. The balance is the reference's headline tile: filled in the accent,
   one figure, nothing else on it.

   Every colour is a token (see the `[data-portal="me"]` block in tokens.css,
   which carries sage and cream and their dark-mode lift — the Business
   Central teal went on 2026-10-02; the desk portals and the terminal keep
   it, a driver's phone does not sit beside a Dynamics window). Nothing
   here hard-codes one, so a re-tint stays a single-file change. Scoped under
   `.me-app` so it cannot reach a desk portal even if the sheet is loaded
   there by accident.

   The shell fills the device. No cap, no centred column: on a phone the
   screen stacks, and past 720px it lays out in as many columns as fit, with
   the balance and the primary action spanning them. */

/* The reset. `app.css` carried this and the app no longer loads it, so every
   `width: 100%` element with padding was overflowing its column by the width
   of its own padding and border — invisibly, because the cards clipped it. */
.me-app *,
.me-app *::before,
.me-app *::after { box-sizing: border-box; }

/* `hidden` is a `display: none` in the user-agent stylesheet, which any author
   rule setting `display` outranks — so a component styled `display: flex` is
   visible while carrying the attribute, and the markup swears it is hidden.
   The platform has met this before on `dialog`. Two classes of specificity so
   it beats the components below without `!important`. */
.me-app [hidden] { display: none; }

/* Icons are sized by their own width/height attributes; this only stops a
   flex parent stretching one and keeps it on the text's baseline. */
.me-app .ico { flex: none; vertical-align: -0.125em; }

/* ─────────────────────────────────────────────────────────────────── shell */

/* The dashboard's two faces (2026-09-16), bundled: Sora carries every
   figure and heading, DM Sans everything read. Variable files, one each,
   latin only — 60KB for both, cached by the worker like any static asset. */
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/static/fonts/sora-latin.woff2") format("woff2");
}
@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/dmsans-latin.woff2") format("woff2");
}

.me-app {
  margin: 0;
  background: var(--me-ground);
  color: var(--me-ink);
  font-family: var(--me-font-body);
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  /* A driver reading a balance should never trigger the browser's
     pull-to-refresh by scrolling up on a short screen. */
  overscroll-behavior-y: contain;
}

.me-shell {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  width: 100%;
  background: var(--me-ground);
}

/* The app bar: the page's own surface, carrying where you are and the two
   things reachable from anywhere — what needs your attention, and how to get
   help. It stays put because a driver scrolling a year of fills should not
   have to scroll back to leave the screen. A hairline appears under it once
   the page has scrolled, so content passing beneath reads as beneath. */
.me-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--s-1);
  min-height: 52px;
  padding: 0 var(--s-1) 0 var(--me-gutter);
  padding-top: env(safe-area-inset-top);
  background: var(--me-bar);
  color: var(--me-bar-ink);
  border-bottom: 1px solid transparent;
}
.me-bar.is-scrolled { box-shadow: none; border-bottom-color: var(--me-line); }

.me-bar-title {
  font-size: var(--fs-18);
  font-weight: var(--fw-semibold);
  letter-spacing: 0;
  margin: 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.me-bar .spacer { flex: 1; }

.me-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--me-tap);
  height: var(--me-tap);
  border: 0;
  border-radius: var(--me-r-pill);
  background: transparent;
  color: var(--me-bar-ink);
  cursor: pointer;
  position: relative;
  flex: none;
}
.me-iconbtn:hover { background: var(--me-bar-hover); color: var(--me-bar-ink); }

/* A count, not a naked dot: "3 waiting" is actionable, "something happened"
   is an errand. */
.me-dot {
  position: absolute;
  top: 5px;
  right: 3px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: var(--me-r-pill);
  background: var(--me-accent);
  color: var(--me-accent-ink);
  font-size: 10px;
  font-weight: var(--fw-bold);
  line-height: 17px;
  text-align: center;
}

.me-back {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-height: var(--me-tap);
  padding-right: var(--s-2);
  margin-left: calc(var(--me-gutter) * -1 + var(--s-1));
  padding-left: var(--s-2);
  border-radius: var(--me-r-sm);
  color: var(--me-accent-deep);
  text-decoration: none;
  font-size: var(--fs-16);
}
.me-back:hover { background: var(--me-bar-hover); }

.me-main {
  flex: 1;
  padding: var(--s-3) var(--me-gutter) var(--s-8);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
/* Room for the tab bar plus the phone's own home indicator. */
.me-shell:has(.me-tabs) .me-main {
  padding-bottom: calc(76px + env(safe-area-inset-bottom) + var(--s-6));
}

/* ─────────────────────────────────────────────────────────────── typography */

/* Display size, tight (2026-10-02). This used to be large and *light* — the
   old reference set a headline figure in the regular weight and let what sat
   beside it carry the emphasis. The editorial reference does the opposite:
   the heading is the heaviest thing on the screen and everything else gets
   quieter around it, which on a phone is what tells a driver which screen
   they are on without reading a word.

   Tracking goes negative because it has to: at 34px the default spacing of a
   grotesk reads as a gap between letters rather than a word. */
.me-h1 {
  font-size: clamp(1.75rem, 8vw, 2.125rem);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.021em;
  line-height: 1.05;
  margin: 0;
  text-wrap: balance;
  font-variant-numeric: tabular-nums;
}
/* A section heading sits a long way below the screen's title now, so it can
   afford to be read rather than scanned past. */
.me-h2 {
  font-size: var(--fs-16);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.006em;
  margin: 0;
}
.me-lede { color: var(--me-ink-2); font-size: var(--fs-14); margin: 0; }
.me-note { color: var(--me-ink-3); font-size: var(--fs-13); margin: 0; }
/* Sentence case. Uppercase tracking is the consumer-dashboard voice; the
   reference names a figure the way a sentence would. */
.me-eyebrow {
  font-size: var(--fs-12);
  font-weight: var(--fw-regular);
  color: var(--me-ink-3);
  margin: 0;
}
.me-num { font-variant-numeric: tabular-nums; }

/* A screen's own title (2026-10-02), in the content rather than the bar.

   The bar keeps what you *do* from here — back, alerts, help — and gives up
   the title, because a 17px label in a 48px strip is the weakest way to say
   which screen somebody is on. The heading below it is the strongest, and it
   scrolls away with the content, so the bar is not carrying it twice.

   `me-page-sub` is one line and optional: the screens that need it are the
   ones where the title alone would leave a driver guessing what the figures
   are counting. */
.me-page-head {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-2) 0 var(--s-5);
}
.me-page-sub {
  margin: 0;
  max-width: 34ch;
  color: var(--me-ink-2);
  font-size: var(--fs-14);
  line-height: 1.45;
}

/* ────────────────────────────────────────────────────────── the front door */

/* The sign-in landing (2026-10-02): a column that fills the screen, the brand
   at the top of it and the actions pinned to the bottom. A hero since
   2026-10-05: the accent to every edge, as the fuel-brand apps open.

   `flex: 1`, not a height. `.me-shell` is already `min-height: 100dvh` and
   `.me-main` already grows inside it, so the room exists — the door only has
   to claim it. A percentage height would have needed every ancestor to have a
   definite one and quietly collapsed to content when they did not, and a
   viewport unit would have measured the screen *without* subtracting iOS's
   browser chrome, putting the button under the address bar on a page with
   nothing to scroll.

   The negative margins cancel `.me-main`'s own padding, so the colour reaches
   the glass; the safe-area insets go back on as padding, so the mark clears
   the status bar and the build line clears the home indicator.

   The gradient runs from `--me-door-from` at the top to `--me-door-to` by
   the lower half, so the buttons and the small print sit on the deeper end.
   The door has its own tokens: in the light theme they are the balance's
   green and its ink, and in the dark theme a deep green falling to the
   page's ground — the dark accent is a light green, and edge to edge it was
   the brightest screen in the app. Every pair is measured in
   test_handheld_skin. No colour here is a literal. */
.me-door {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  flex: 1;
  margin: calc(-1 * var(--s-3)) calc(-1 * var(--me-gutter)) calc(-1 * var(--s-8));
  padding: calc(var(--s-8) + env(safe-area-inset-top, 0px)) var(--s-5)
           calc(var(--s-5) + env(safe-area-inset-bottom, 0px));
  background-color: var(--me-door-to);
  background-image: linear-gradient(165deg, var(--me-door-from) 0%, var(--me-door-to) 58%);
  color: var(--me-door-ink);
}
/* Two lights on the door (2026-10-08). The first is the panel's own spill:
   it is the only lit thing on the screen, so the green around it should know
   that. The second sits high and to the left and is there for a duller
   reason — a single linear ramp across a whole phone of one green is what
   bands visibly on a cheap OLED, and a second light breaks the ramp. Both
   are decorative and sit behind everything. */
.me-door::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(72% 38% at 50% 30%, var(--me-door-spill) 0%, transparent 70%),
    radial-gradient(90% 55% at 12% -8%, var(--me-door-lift) 0%, transparent 60%);
}
.me-door-brand { display: flex; align-items: center; gap: var(--s-3); }
.me-door-name {
  font-family: var(--me-font-display);
  font-size: var(--fs-18);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.01em;
}
.me-door .me-mark { background: var(--me-door-in); color: var(--me-door-in-ink); }
/* The pitch takes whatever room is left and sits at the bottom of it, so on
   a short phone it is the gap above it that shrinks, never the buttons. */
.me-door-pitch { margin-top: auto; padding: var(--s-6) 0; }
.me-door-title { margin: 0; }
.me-door-lede {
  margin: var(--s-3) 0 0;
  max-width: 28ch;
  color: var(--me-door-ink);
  font-size: var(--fs-16);
  line-height: 1.45;
}
/* What the app is, as three things rather than one sentence (2026-10-08).
   A driver on this screen is often at a pump with one hand on the phone;
   three marks they take in at a glance beat a line they have to read. The
   marks are glass, like Sign up below them and the chips on a wallet tile —
   there is a lit panel and a green ground behind them to refract. */
.me-door-says {
  display: flex;
  justify-content: space-between;
  gap: var(--s-2);
  margin: var(--s-6) 0 0;
  padding: 0;
  list-style: none;
}
.me-door-says li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-2);
  flex: 1;
  min-width: 0;
  text-align: center;
  font-size: var(--fs-13);
  font-weight: var(--fw-medium);
  color: var(--me-door-ink);
}
.me-door-say-mark {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--me-door-up);
  box-shadow: inset 0 0 0 1px var(--me-door-up-edge);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .me-door-say-mark {
    -webkit-backdrop-filter: var(--me-glass-blur);
    backdrop-filter: var(--me-glass-blur);
  }
}

.me-door-actions {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

/* A short phone. The door's rule is that the pitch gives way before the
   buttons do; the three marks and the panel are the next to give, in that
   order, because the panel is the decorative one and the build line at the
   foot is not — support's first question is which version a driver is on,
   and they cannot answer it from a line below the fold. Adding the marks
   put it there on a 360x640, which is what this block takes back. */
@media (max-height: 720px) {
  .me-door-says { margin-top: var(--s-3); gap: var(--s-1); }
  .me-door-says li { font-size: var(--fs-12); gap: 6px; }
  .me-door-say-mark { width: 34px; height: 34px; }
  .me-lcd { padding: var(--s-2) var(--s-3) var(--s-3); }
  .me-lcd-head { margin-bottom: var(--s-2); }
  .me-lcd-panel { padding: var(--s-3); gap: 6px; }
  .me-lcd-row { font-size: 1.1rem; }
  .me-lcd-row.is-total { font-size: 1.55rem; }
  .me-door-pitch { padding: var(--s-3) 0; }
  .me-door-lede { font-size: var(--fs-14); }
  .me-door-actions { gap: var(--s-2); }
  /* 44px is the floor `--me-tap` sets and nothing here goes under it. */
  .me-door-quiet { min-height: var(--me-tap); }
}

/* Shorter still, and something has to go. The order is the door's own: the
   decoration first, then what is read, and never the controls. So the panel
   goes — it is an emblem, and the three marks under it carry what the app
   actually does. A driver on a 360x640 with a passkey button in the stack
   keeps both ways in, the help button and the build line, which is the
   whole job of this screen. */
@media (max-height: 680px) {
  .me-door .me-lcd { display: none; }
}
.me-door-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.me-door-in { background: var(--me-door-in); color: var(--me-door-in-ink); }
/* Glass, with the edge doing the work: the fill alone is 1.3:1 on the door
   and a button nobody can find is not a secondary action, it is a missing
   one. */
/* The edge is an inset shadow and not a border, because `.me-btn` sets
   `border: 1px solid transparent` six hundred lines further down this sheet
   at the same specificity and wins — which is how the first attempt at this
   fix shipped looking exactly like the bug. The marks below use the same
   idiom for the same reason. */
.me-door-up {
  background: var(--me-door-up);
  box-shadow: inset 0 0 0 1px var(--me-door-up-edge);
  color: var(--me-door-up-ink);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .me-door-up {
    -webkit-backdrop-filter: var(--me-glass-blur);
    backdrop-filter: var(--me-glass-blur);
  }
}
.me-door-quiet { background: transparent; color: var(--me-door-ink); }
.me-door :focus-visible { outline-color: var(--me-door-ink); }
/* ---- guided capture (2026-10-08) ----

   A stepped form's chrome: which step this is, what was said on the steps
   before it, and the way on. All of it is filled by `me.js` once it has
   grouped the sections — without that file the form is one page of fields
   with no steps to count, so these stay empty and `:empty` keeps them out
   of the way rather than leaving a stray label on a working form. */
/* ---- a collapsible group (2026-10-08) ----

   `<details>` and nothing else: it opens with a tap, a keyboard and a
   screen reader, it prints open, and it needs no script — which matters on
   the Account screen, where a driver reaches for "freeze my card" when
   something has already gone wrong. The marker is drawn here because the
   browsers' own differ, and it turns rather than swapping glyph.

   `.me-fold` and not `.me-group`: that name is already the day heading in a
   list — a statement, Activity, the loyalty ledger. Caught by
   `test_no_two_components_share_a_class_name`, which exists because six
   earlier name clashes in this sheet were not. */
.me-fold { margin-top: var(--s-4); }
/* A row you press, not a heading that happens to be clickable: it carries
   `.me-menu-head`'s type and none of its margins, which on a closed group
   left the title floating in forty pixels of nothing. */
.me-fold > summary {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: var(--me-tap);
  margin: 0;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--me-r-xl);
  background: var(--me-surface);
  box-shadow: inset 0 1px 0 var(--me-glass-edge);
  cursor: pointer;
  list-style: none;
}
.me-fold > summary:hover { background: var(--me-surface-2); }
/* Open, the summary is the lid of what is under it. */
.me-fold[open] > summary {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.me-fold[open] > .me-fold-body > :first-child {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  margin-top: 0;
}
.me-fold > summary::-webkit-details-marker { display: none; }
.me-fold > summary::after {
  content: "";
  width: 9px;
  height: 9px;
  margin-left: auto;
  border: 2px solid var(--me-ink-3);
  border-left: 0;
  border-top: 0;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur-fast) var(--ease);
}
.me-fold[open] > summary::after { transform: rotate(-135deg) translate(-3px, -3px); }
.me-fold > summary:hover::after { border-color: var(--me-ink); }
.me-fold :focus-visible { outline-color: var(--me-accent); }
@media (prefers-reduced-motion: reduce) {
  .me-fold > summary::after { transition: none; }
}

.me-step-count {
  margin: 0 0 var(--s-3);
  /* Sentence case: uppercase tracking is the consumer-dashboard voice and
     this app does not use it — see `.me-eyebrow`. */
  font-size: var(--fs-12);
  font-weight: var(--fw-medium);
  color: var(--me-ink-3);
}
.me-step-count:empty { display: none; }

/* What is already entered, kept where it can be checked rather than
   remembered. A prefilled wallet is the whole reason this is here: a figure
   you cannot see is a figure you cannot check, and the PIN is spent next. */
.me-step-recap {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px var(--s-3);
  margin: 0 0 var(--s-4);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--me-r);
  background: var(--me-surface-2);
  font-size: var(--fs-13);
}
.me-step-recap dt { color: var(--me-ink-3); }
.me-step-recap dd { margin: 0; font-weight: var(--fw-medium); text-align: right; }

.me-step-nav { display: flex; gap: var(--s-3); margin-top: var(--s-5); }
.me-step-nav .me-btn-secondary { flex: none; min-width: 96px; }
.me-step-back { margin-top: var(--s-3); }

/* ---- the pump display, the door's emblem (2026-10-07) ----

   The door held the brand mark, the pitch and the buttons, and four hundred
   pixels of nothing between them; its own note said there was no photograph
   of ours to put there. So the object itself: a forecourt pump's LCD,
   backlit cyan behind a dark bezel, with the two figures every pump in the
   world shows — what the fill cost and how much went in.

   It is a picture, not a reading. Nobody is signed in on this screen, so
   there is no balance to show and nothing here is anyone's: it is
   `aria-hidden`, the words on it are the pump's own, and the pitch beside
   it is what actually says what the app does.

   The seven-segment look is one trick and no font file: `.me-lcd-ghost` is
   a full `888.888` sitting behind the figure at the contrast of an unlit
   segment. A mono face alone reads as a receipt; a mono face over its own
   ghost reads as a panel with segments that did not light. */
.me-lcd {
  /* `margin: auto` in the column takes the room the pitch leaves, so the
     panel floats in the middle of the door rather than hanging off the
     mark. The pitch keeps its own `margin-top: auto`, so on a short phone
     the two share what is left and the buttons never move. */
  align-self: center;
  margin: auto 0;
  width: min(100%, 320px);
  padding: var(--s-4) var(--s-4) var(--s-5);
  border-radius: 18px;
  background: var(--me-lcd-bezel);
  color: var(--me-lcd-bezel-ink);
  /* The bezel is a moulding: lit along its top lip, shadowed below. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .10),
    0 18px 40px -20px rgba(0, 0, 0, .75);
}
.me-lcd-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--s-3);
  font-size: var(--fs-12);
  font-weight: var(--fw-semibold);
  letter-spacing: .14em;
  text-transform: uppercase;
  opacity: .75;
}
/* The lit panel. The glow is the backlight bleeding at the edges, which is
   the thing that says a panel is lit rather than printed. */
.me-lcd-panel {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-4);
  border-radius: 10px;
  background: var(--me-lcd);
  color: var(--me-lcd-ink);
  box-shadow:
    inset 0 0 22px var(--me-lcd-glow),
    inset 0 0 0 1px rgba(0, 0, 0, .18);
}
.me-lcd-row { display: flex; align-items: baseline; gap: var(--s-2); }
.me-lcd-label {
  flex: none;
  width: 3.4em;
  font-size: var(--fs-12);
  font-weight: var(--fw-semibold);
  letter-spacing: .1em;
  text-transform: uppercase;
  opacity: .8;
}
/* Right-aligned and positioned, so the ghost can sit exactly under the
   figure however many digits the figure has. */
.me-lcd-figure {
  position: relative;
  flex: 1;
  text-align: right;
  font-family: var(--font-mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  line-height: 1;
}
.me-lcd-ghost {
  position: absolute;
  inset: 0;
  color: var(--me-lcd-ghost);
}
.me-lcd-value { position: relative; }
/* The self-test: every segment lit at once, which is what a pump shows when
   it is switched on so the attendant can see none of them is dead. The
   ghost is already a full `888.888`, so the test is that ghost at the ink's
   own weight with the figure out of the way. */
.me-lcd.is-testing .me-lcd-ghost { color: var(--me-lcd-ink); }
/* Every row, not only the two that count: a pump lights the whole panel,
   and leaving the price showing puts its figure under the test's eights. */
.me-lcd.is-testing .me-lcd-value { visibility: hidden; }
/* The backlight coming up. Only the panel, and only where motion is wanted:
   the script checks the same preference before it counts anything. */
@media (prefers-reduced-motion: no-preference) {
  .me-lcd[data-pump] .me-lcd-panel { animation: me-lcd-wake 700ms ease-out both; }
}
@keyframes me-lcd-wake {
  from { filter: brightness(.5) saturate(.45); }
  to   { filter: none; }
}
.me-lcd-row { font-size: 1.5rem; }
.me-lcd-row.is-total { font-size: 2.25rem; }
.me-lcd-row.is-total .me-lcd-label { font-size: var(--fs-12); }
.me-lcd-unit {
  flex: none;
  width: 2.2em;
  font-size: var(--fs-12);
  font-weight: var(--fw-semibold);
  letter-spacing: .08em;
  opacity: .8;
}

/* The door arrives in the order it is read: the mark, then the panel, then
   what the app is, then the ways in. Only inside `no-preference`, and the
   rule outside this block is the settled state — so a phone that wants less
   motion, or a browser that never runs the animation, gets the finished
   screen rather than an empty one waiting to be told to appear. */
@media (prefers-reduced-motion: no-preference) {
  .me-door-brand,
  .me-door .me-lcd,
  .me-door-pitch,
  .me-door-actions {
    animation: me-door-in 620ms cubic-bezier(.2, .7, .3, 1) both;
  }
  .me-door-brand   { animation-delay:  60ms; }
  .me-door .me-lcd { animation-delay: 150ms; }
  .me-door-pitch   { animation-delay: 260ms; }
  .me-door-actions { animation-delay: 340ms; }
}
@keyframes me-door-in {
  from { opacity: 0; transform: translateY(14px); }
}

/* The quietest thing on the screen, and the first thing support asks for. */
.me-door-build {
  margin: var(--s-2) 0 0;
  text-align: center;
  color: var(--me-door-ink);
  font-size: var(--fs-12);
  font-variant-numeric: tabular-nums;
}

/* ──────────────────────────────────────────────────────── the wallet tiles */

/* One tile per wallet, each in its own colour, standing on the page's own
   ground (2026-10-07). They used to sit on a dark green sheet; the sheet
   ends after the greeting now and the balances stand on the same cream as
   everything below them.

   Why a colour each: on a forecourt a grade is a colour before it is a word
   — the collar on the nozzle, the plate on the pump face. A driver holding
   a Diesel wallet and a cash wallet is doing that same reading, so each
   wallet keeps its colour wherever it sits in the track, and wears a badge
   of what it buys. Those two are what they recognise before the name.

   The six are the ones promotions already use: measured in both themes,
   damped to the warm palette, far enough apart that a glance tells them
   apart. Every word on a tile is the tone's measured ink on its measured
   soft ground. The strong step appears only where nothing has to be read on
   it — the badge and the ring — so `test_every_promotion_tone_reads` still
   covers the whole tile.

   Scroll-snap and nothing else: no script, so it swipes from the worker's
   cache on one bar. The track scrolls, never the page. */
.me-wallets {
  display: flex;
  gap: var(--s-3);
  /* Room at the foot for the card's own lift. */
  padding: var(--s-1) 0 var(--s-4);
  flex-direction: column;
}


/* ── the wallet strip ─────────────────────────────────────────────────────
   One tab per wallet, the one in use filled. It replaced a deck (2026-10-13
   → 2026-10-14) in which every idle wallet was a band tucked behind the
   front card: one row, but each balance hidden behind a sliver of itself.
   The strip keeps the row and says all of them at once.

   It scrolls sideways when a card holds more wallets than fit, and the page
   never does — the track is the only thing that moves. A tab is a link, so
   none of this needs script. */
.me-section-label {
  margin: var(--s-4) 0 var(--s-2);
  color: var(--me-ink-3);
  font-size: var(--fs-13);
  font-weight: var(--fw-semibold);
}
.me-wswitch {
  display: flex;
  gap: var(--s-1);
  padding: var(--s-1);
  overflow-x: auto;
  scrollbar-width: none;
  background: var(--me-surface);
  border-radius: var(--me-r-lg);
  /* No lift: only the things a driver *holds* are lifted on this app, and
     a strip of tabs is a control on the ground, not a card. */
}
.me-wswitch::-webkit-scrollbar { display: none; }
.me-wswitch-tab {
  flex: 1 0 auto;
  min-width: 0;
  display: grid;
  gap: 2px;
  justify-items: center;
  align-content: center;
  /* 44px is the floor a thumb needs and the floor WCAG asks for. A tab
     sized to its two short lines came out 27px tall. */
  min-height: 44px;
  padding: var(--s-2) var(--s-4);
  border-radius: calc(var(--me-r-lg) - var(--s-1));
  color: var(--me-ink-2);
  text-decoration: none;
  text-align: center;
  white-space: nowrap;
}
/* The one in use is a filled pill, not a tinted one: a tint on a pane this
   pale is a difference a forecourt in sunlight does not carry. It takes the
   *wallet's* deep ground, so diesel is graphite and a money wallet is
   slate — the grade follows the wallet onto the strip. */
/* Scoped past `.me-fuel-*`, which sits further down this sheet and paints a
   *soft* ground on anything wearing it — an idle tab would have come out
   tinted. Two class names here beats one there; it is the fourth time this
   sheet's ordering has needed saying. The tab wants the grade's custom
   properties, not its surface. */
.me-wswitch .me-wswitch-tab {
  background: transparent;
  color: var(--me-ink-2);
}
.me-wswitch .me-wswitch-tab.is-on {
  background: var(--me-tile-deep);
  color: var(--me-fuel-deep-ink);
}
.me-wswitch-name {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-12);
  opacity: .85;
}
/* An idle tab says its grade with a dot. Decorative — the wallet's name is
   beside it and its unit is under it — so it carries no meaning alone. */
.me-wswitch-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--me-tile-strong);
}
.me-wswitch-tab.is-on .me-wswitch-dot { background: currentColor; opacity: .8; }
.me-wswitch-figure {
  font-family: var(--me-font-display);
  font-size: var(--fs-15);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}
.me-wswitch-unit { font-size: var(--fs-12); opacity: .8; }

.me-wallet-card {
  position: relative;
  overflow: hidden;
  flex: 1 1 100%;
  min-width: 0;
  padding: var(--s-5);
  border-radius: var(--me-r-xl);
  /* A tile is a thing you hold and a track of them is a stack, so a lift is
     what says the next one is *behind* this one rather than printed beside
     it. The hero's old "no lift on this screen" rule went with the sheet it
     was written for. The edge is a hairline, because a pale tone on cream
     otherwise has no boundary at all. */
  /* The deep step (2026-10-08): a balance is a card, so it has a card's
     weight — a saturated ground with white on it rather than a tint with
     ink. The grade still picks the hue, so a diesel wallet is graphite and
     an unleaded one is green; what changed is the weight, not the idea.
     `.me-fuel-*` publishes all three steps. */
  box-shadow:
    var(--me-tile-lift),
    /* The lip. A pane laid on a colour catches the light along its top edge
       and nowhere else, and that one line is most of what tells the eye a
       surface is a surface. It costs no composite. */
    inset 0 1px 0 var(--me-fuel-deep-edge);
}
/* The deep ground, scoped past `.me-fuel-*`. Those classes sit further down
   this sheet and set the *pale* tint a hero and a dot wear, so at equal
   specificity they repaint the card — which is the third time this sheet's
   ordering has done that. Two class names here beats one there. */
.me-wallets .me-wallet-card {
  background: var(--me-tile-deep);
  color: var(--me-fuel-deep-ink);
}


/* The engraving: fine ruled lines in the grade's own colour, raked across
   the top corner and fading out. A fuel card and a banknote are printed the
   same way and for the same reason, so this is the card's own texture rather
   than a decoration borrowed from somewhere.

   It is also the answer to a flat tile that a watermark was not. A wallet
   glyph was tried behind the figure first (2026-10-07) and at any opacity
   that showed, its strokes crossed the tile as a crease — the eye reads a
   big soft *shape* as a fold in the surface. A regular rule reads as
   texture, which is what a surface is made of.

   Decorative, and under everything: `> *` lifts the content back above it. */
/* `.me-engraved` puts this on any surface that wants it; a tile and a hero
   are already positioned and clipped, and this makes the opt-in so too. */
.me-engraved { position: relative; overflow: hidden; }
/* Lighter on a white pane than on a tinted one: the lines are drawn in the
   surface's own ink, and near-black at a tile's weight reads as grey hatching
   on white rather than as a pressed line. */
.me-card.me-engraved::before { opacity: .04; }
.me-wallet-card::before,
.me-hero::before,
.me-engraved::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(102deg,
    currentColor 0 1px, transparent 1px 7px);
  opacity: .07;
  /* A mask reads alpha and throws the colour away, so this is `rgba()` for
     the same reason a scrim is: it is an opacity over an unknown backdrop,
     not a colour, and a token would be the wrong shape for it. */
  -webkit-mask-image: radial-gradient(125% 95% at 100% 0%, rgba(0, 0, 0, 1) 0%, transparent 62%);
  mask-image: radial-gradient(125% 95% at 100% 0%, rgba(0, 0, 0, 1) 0%, transparent 62%);
}
.me-wallet-card > *,
.me-engraved > * { position: relative; }

/* The tile in use wears a ring in its wallet's colour rather than the others
   being dimmed: dimming would take their figures under the contrast floor
   the suite measures. */
/* The tile in use wears a ring in its own light rather than the others
   being dimmed, which on seven deep grounds would take their figures under
   the floor. */
.me-wallet-card.is-live {
  box-shadow:
    var(--me-tile-lift),
    inset 0 0 0 1.5px var(--me-fuel-deep-edge),
    inset 0 1px 0 var(--me-fuel-deep-edge);
}

/* What kind of wallet this is, as the object it buys: a pump for a Volume
   wallet, a wallet for a Value one. A fleet card is one card and several
   wallets, and the thing a driver needs first is not the name but whether
   this one is litres or money — the same reading a forecourt asks for, where
   the grade is a colour and a shape before it is a word.

   Reversed out of the tone's strong step. That pair is 3.80:1 at worst in
   light and 4.95:1 in dark, which is the non-text floor and not the text
   one — nothing is written here, and nothing may be: the kind is also in the
   wallet's name and in the unit beside every balance, so the badge is
   `aria-hidden` and carries no meaning a reader would miss. */
.me-wallet-kind {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 10px;
  background: var(--me-fuel-deep-wash);
  color: var(--me-fuel-deep-ink);
  /* A glyph on a filled chip wants the stroke, not the duotone fill under
     it: the fill is the same colour as the stroke and only muddies it. */
  --me-duo: 0;
}
.me-wallet-card .me-wallet-label {
  /* Sentence case, like every other label on this app: see `.me-eyebrow`. */
  margin: var(--s-4) 0 0;
  font-size: var(--fs-13);
  color: var(--me-fuel-deep-dim);
}
.me-wallet-card .me-wallet-balance {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 2px 0 0;
  font-family: var(--me-font-display);
  font-size: clamp(2.25rem, 11vw, 3rem);
  font-weight: var(--fw-bold);
  letter-spacing: -0.035em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.me-wallet-card .me-wallet-unit {
  font-size: var(--fs-16);
  font-weight: var(--fw-semibold);
  letter-spacing: 0;
  opacity: .8;
}
.me-wallet-card .me-wallet-value {
  margin: var(--s-2) 0 0;
  font-size: var(--fs-13);
  color: var(--me-fuel-deep-dim);
}

/* The status the card is in, said in a word beside its name. A frozen card
   never shows it: the alert above the track is what says that, and a card
   cannot be both. */
.me-wallet-state {
  flex: none;
  padding: 3px 10px;
  border-radius: var(--me-r-pill);
  background: var(--me-fuel-deep-wash);
  box-shadow: inset 0 0 0 1px var(--me-fuel-deep-edge);
  font-size: var(--fs-12);
  font-weight: var(--fw-medium);
}

/* The card's own foot, the way a bank card carries its number along the
   bottom: which card this balance belongs to, and when it last drew. Ruled
   off, because it is printed on the card rather than part of the figure. */
.me-wallet-foot {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  margin: var(--s-5) 0 0;
  padding-top: var(--s-4);
  border-top: 1px solid var(--me-fuel-deep-edge);
}
.me-wallet-foot > .is-end { text-align: right; }
.me-wallet-foot dt {
  font-size: var(--fs-12);
  color: var(--me-fuel-deep-dim);
}
.me-wallet-foot dd {
  margin: 2px 0 0;
  font-size: var(--fs-13);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}

/* The eye takes its own size rather than whatever its container happens to
   give it. It had none until 2026-10-14 — it was 44px because the row it
   sat in was, and when the card gained a panel for the product the button
   came out 36x27, under the thumb floor. A control that masks every figure
   on the screen is not a control to have to aim at. */
.me-eye {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  margin: -8px -8px -8px 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

/* Frosted, where frosting means something: these three sit on the grade's
   own colour, so a blur behind them refracts that colour and the chip reads
   as a piece of glass lying on the tile rather than a lighter rectangle
   painted on it. The lip along the top is the part that does the work.

   Gated, and the opaque wash above is the fallback — a phone that cannot
   blur must not be left with a transparent chip it cannot separate from the
   tile. Nothing on the flat ground is frosted: a blur of flat cream is flat
   cream, and a composite for it. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  /* The eye is a bare glyph at rest and a chip only under the finger: one
     frosted pill beside a wallet's name would read as the thing to press. */
  .me-eye:hover,
  .me-eye:focus-visible {
    background: var(--me-glass);
    -webkit-backdrop-filter: var(--me-glass-blur);
    backdrop-filter: var(--me-glass-blur);
    box-shadow: inset 0 1px 0 var(--me-glass-edge);
  }
}

/* Focus has to be visible on six different grounds, so it takes the tile's
   own ink rather than the accent's green. A tab in the strip is a link on a
   pale pane, so it keeps the ordinary outline. */
.me-wallet-card :focus-visible { outline-color: currentColor; }

/* ---- the action bar (2026-10-08) ----

   The four things a driver does at a pump, on one dark bar. They were a
   filled button and a separate pane of three below it, which reads as one
   important action and three lesser ones — and at a forecourt they are four
   ways to pay for fuel. Only Scan ranks, because it is the one the attendant
   is waiting for, so it keeps a filled mark and the other three sit level
   with it on the same ground.

   Dark, because this is the one block on the screen that is *controls* and
   not figures, and because a bar of four tinted tiles under seven possible
   card colours is a colour fight nobody wins. */
.me-acts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s-1);
  padding: var(--s-3) var(--s-2);
  border-radius: var(--me-r-xl);
  /* `--me-ink` and not `--me-bar`: the app bar is white in the light theme,
     and this block is meant to be the dark one on the screen. */
  background: var(--me-ink);
  color: var(--me-ground);
}
.me-act {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-height: var(--me-tap);
  padding: var(--s-2) 2px;
  border-radius: var(--me-r);
  color: inherit;
  font-size: var(--fs-12);
  font-weight: var(--fw-medium);
  text-align: center;
  text-decoration: none;
}
.me-act:hover { background: rgba(255, 255, 255, .08); }
.me-act-mark {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .10);
}
/* The common case, filled in the brand's own accent. */
.me-act.is-lead .me-act-mark {
  background: var(--me-accent);
  color: var(--me-accent-ink);
}
.me-acts :focus-visible { outline-color: var(--me-ground); }

/* ---- the two figures under the balance ----

   What is out in coupons, and what fuel costs today. They were pills on the
   balance card; they are facts about *today* rather than parts of the
   balance, so they stand on their own under it, each in the tone its kind
   already wears in a row list.

   `.me-facts` and not `.me-stats`: that name is already the three-figure
   month summary inside Recent fills, further down this sheet, and taking it
   would have re-gridded that row from three columns to two. */
.me-facts {
  display: grid;
  /* Two explicit columns rather than `auto-fit`, which sized itself off the
     content and left a lone tile a third of the row wide. A lone tile spans
     both. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-3);
}
.me-fact {
  /* Positioned for the chevron on the tiles that are links. */
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  padding: var(--s-4);
  border-radius: var(--me-r-xl);
  text-decoration: none;
  box-shadow: inset 0 1px 0 var(--me-glass-edge);
}
.me-fact-mark {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-bottom: var(--s-1);
  border-radius: 10px;
  background: var(--me-tile-strong);
  color: var(--me-tile-ground);
  --me-duo: 0;
}
.me-fact-figure {
  font-family: var(--me-font-display);
  font-size: var(--fs-22);
  font-weight: var(--fw-bold);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.me-fact-figure small { font-size: var(--fs-13); font-weight: var(--fw-semibold); }
.me-fact-note { font-size: var(--fs-12); opacity: .9; }
.me-fact:only-child { grid-column: 1 / -1; }

/* Dots are links, so this is a real control: a 44px hit area around a 9px
   mark, because `--me-tap` is measured on every control on this screen. Each
   wears its wallet's colour, so the row reads as the set of tiles. */
/* Scoped past `.me-fuel-*`, which the dot wears only to pick up its wallet's
   strong step: left alone, the grade class would also paint the 44px hit
   area with the tile's ground and ink it with the tile's text colour. */

@media (prefers-reduced-motion: reduce) {
}

/* ─────────────────────────────────────────────────────────────────── menus */

/* A settings menu (2026-10-02), the one on the Account screen.

   A pane with a heading bar inside it says "here is a thing"; a menu says
   "here are the places you can go". So the heading comes out of the pane and
   sits on the ground, plain, and the destinations group under it — which is
   how every phone's settings app has done it for fifteen years, and what the
   reference does.

   These rows keep a rule between them, and the records in `.me-list` do not.
   That is not an inconsistency: a record is one of many of the same thing and
   the eye groups them by rhythm, while a destination is its own object, and
   with no pane edge to end at a rule is the only thing saying where one stops
   and the next begins. The rule is inset past the icon so it separates the
   labels rather than cutting the group in half. */
/* Sentence case, and inked rather than grey. Uppercase tracking is the
   consumer-dashboard voice this sheet already rejected once, and the
   reference does not use it either — its groups are named the way a sentence
   would name them. */
.me-menu-head {
  margin: var(--s-6) 0 var(--s-2);
  padding: 0 var(--s-2);
  font-size: var(--fs-16);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.006em;
  color: var(--me-ink);
}
.me-menu {
  background: var(--me-surface);
  border-radius: var(--me-r-xl);
  overflow: hidden;
}
/* Drawn as a pseudo-element rather than a border, so it can start past the
   icon: a rule that runs the full width cuts the group in half, where one
   that begins at the label separates the labels. The offset is the row's own
   padding plus the 44px icon plus the gap after it. */
.me-menu .me-list > li + li { position: relative; }
.me-menu .me-list > li + li::before {
  content: "";
  position: absolute;
  top: 0;
  left: calc(var(--s-5) + 44px + var(--s-3));
  right: 0;
  height: 1px;
  background: var(--me-line);
}
.me-menu .me-row { min-height: 60px; }

/* ────────────────────────────────────────────────────────────────── surfaces */

/* A pane: rounded, filled, no stroke and no lift (2026-10-02). It carried a
   hairline, which on a white ground was the only thing saying where the pane
   ended. The ground is no longer white — cream against a near-white pane —
   so the fill does that work itself, and the border was drawing a box around
   something already separated. The one lifted thing is still the balance. */
.me-card {
  background: var(--me-surface);
  border: 0;
  border-radius: var(--me-r-xl);
  padding: var(--s-5);
  /* The same lip the wallet tiles carry (2026-10-07): a surface laid on the
     ground catches the light along its top edge, and one line of it is what
     separates a pane from a patch of paler ground. No lift — a pane is laid
     on the page, not stacked on it; the lift belongs to the tiles, which
     are a stack, and to a hero. */
  box-shadow: inset 0 1px 0 var(--me-glass-edge);
}
.me-card-flush { padding: 0; overflow: hidden; }
/* A section heading: quiet, so the rows beneath it are what the eye lands
   on. The accent underline was the desk product's mark; on a phone it made
   every section shout as loudly as the balance. */
.me-card-head {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 48px;
  padding: var(--s-4) var(--s-5) var(--s-2);
  border-bottom: 0;
}
.me-card-head .spacer { flex: 1; }

/* The balance: the reference's headline tile. Filled in the accent, one
   figure as large as it can be without wrapping on a 320px phone, because it
   is the whole reason the app is opened. */
/* A hero is a tile (2026-10-07). It was a deep green gradient with a glow
   in the corner, which is what the home balance was until the wallet tiles
   landed on the page's own ground — leaving this the last green panel in
   the app, and the one thing that still looked like the old product.

   Same anatomy as a wallet tile now: a tinted ground, the ink measured on
   it, the engraving, the lip, the lift. The tint is the tone of whatever
   the hero is *about*, and every hero already said what that is with the
   glyph in its label — stations wear the teal their rows wear, points the
   amber theirs do, and the two pay screens and a fuel reward wear the grade
   of the fuel itself, which is the forecourt's own answer.

   The default below is the generic petroleum tone, so a hero with no class
   is quiet rather than wrong. */
.me-hero {
  position: relative;
  overflow: hidden;
  padding: var(--s-5);
  border-radius: var(--me-r-hero);
  /* The deep step (2026-10-08), so a hero is the same object as the home
     balance card rather than a pale cousin of it: a saturated ground with
     white on it. The tone or grade on the element picks the hue. */
  background: var(--me-tile-deep, var(--me-fuel-fuel-deep));
  color: var(--me-fuel-deep-ink);
  --me-tile-strong: var(--me-fuel-fuel);
  --me-tile-ground: var(--me-fuel-fuel-soft);
  box-shadow:
    var(--me-tile-lift),
    inset 0 1px 0 var(--me-fuel-deep-edge);
}
/* The loyalty app wears this skin with its own amber accent, and its heroes
   were the one place that accent was the whole surface. It keeps it. */
[data-app="loyalty"] .me-hero {
  background: var(--me-tone-amber-deep);
  --me-tile-strong: var(--me-tone-amber);
  --me-tile-ground: var(--me-tone-amber-soft);
}
.me-hero > * { position: relative; }
.me-hero-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-13);
  font-weight: var(--fw-medium);
  opacity: .88;
}
.me-hero-value {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-top: var(--s-2);
  font-size: clamp(2.25rem, 12vw, 2.9rem);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.02em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  color: inherit;
}
.me-hero-unit {
  font-size: var(--fs-18);
  font-weight: var(--fw-medium);
  opacity: .88;
  letter-spacing: 0;
}
.me-hero-sub { margin: 6px 0 0; font-size: var(--fs-13); opacity: .88; }

/* ─────────────────────────────────────────────────────────────────── buttons */

/* Rounded, the thumb's height, and the primary one taller still: on a
   phone a control looks tappable by its shape, and the main action on a
   screen is the one a driver is aiming for with a gloved hand. */
.me-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 48px;
  padding: 0 var(--s-4);
  border: 1px solid transparent;
  border-radius: var(--me-r);
  font: inherit;
  font-size: var(--fs-16);
  font-weight: var(--fw-medium);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.me-btn-block { width: 100%; }

/* The one filled control on any screen. */
.me-btn-primary { background: var(--me-accent); color: var(--me-accent-ink); min-height: 52px; }
.me-btn-primary:hover { background: var(--me-accent-deep); }

.me-btn-secondary {
  background: var(--me-surface);
  border-color: var(--me-line-strong);
  color: var(--me-ink);
}
.me-btn-secondary:hover { background: var(--me-accent-soft); color: var(--me-accent-deep); }
/* The glyph on a secondary action carries a colour; the label carries the
   meaning, so the strong step — not measured for text — is allowed here. */
.me-btn-secondary.is-amber .ico  { color: var(--me-tone-amber); }
.me-btn-secondary.is-plum .ico   { color: var(--me-tone-plum); }
.me-btn-secondary.is-indigo .ico { color: var(--me-tone-indigo); }
.me-btn-secondary.is-teal .ico   { color: var(--me-tone-teal); }

/* A command: flat until hovered. */
.me-btn-quiet { background: transparent; color: var(--me-ink-2); }
.me-btn-quiet:hover { background: var(--me-accent-soft); color: var(--me-accent-deep); }

.me-btn-danger { background: transparent; color: var(--me-bad); border-color: var(--me-line-strong); }
.me-btn-danger:hover { background: var(--me-bad-soft); }

.me-btn[disabled], .me-btn[aria-disabled="true"] {
  opacity: .5;
  pointer-events: none;
}

/* The one action a driver came to take, given its own weight and its own
   line. Everything else on the home screen is a row. */
.me-actions { display: flex; flex-direction: column; gap: var(--s-2); }
.me-actions-row { display: flex; gap: var(--s-2); }
.me-actions-row > * { flex: 1; }

/* ─────────────────────────────────────────────────────────────────── lists */

.me-list { list-style: none; margin: 0; padding: 0; }
/* No rule between rows (2026-10-02). A hairline every 56px turns a list into
   a ledger; the reference separates by space and lets the row's own icon tile
   mark where it starts. The rule stays only under a day heading, where it is
   carrying a break in meaning rather than a repeat. */
.me-list > li + li { border-top: 0; }

.me-row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  min-height: 64px;
  padding: var(--s-3) var(--s-5);
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.me-row:hover { background: var(--me-accent-soft); }
.me-row-static { cursor: default; }
.me-row-static:hover { background: none; }

.me-row-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: var(--me-r);
  background: var(--me-surface-2);
  color: var(--me-ink-2);
}
/* Inside a tinted square the fill is already the ground; the glyph goes
   a touch heavier instead so the pair reads as one mark. */
.me-row-icon { --me-duo: .22; }
.me-row-icon.is-ok { background: var(--me-ok-soft); color: var(--me-ok); }
.me-row-icon.is-bad { background: var(--me-bad-soft); color: var(--me-bad); }
.me-row-icon.is-warn { background: var(--me-warn-soft); color: var(--me-warn); }
/* Each kind of row its own colour, so a glance tells points from coupons
   from codes before a word is read. The same six tones a promotion picks.

   Each also publishes its own two colours — `--me-tile-strong` and
   `--me-tile-ground` — so a child can take them without naming the tone,
   which is what lets one rule dress six wallet tiles. The strong step is
   only ever used where nothing has to be *read* on it: a ring, or a glyph
   reversed out of it, which is a non-text mark and measured against 3:1
   rather than 4.5. Every word stays the measured ink on the
   measured soft ground. */
.me-row-icon.is-teal,   .me-tone-teal   { background: var(--me-tone-teal-soft); color: var(--me-tone-teal-ink); --me-tile-strong: var(--me-tone-teal); --me-tile-ground: var(--me-tone-teal-soft); --me-tile-deep: var(--me-tone-teal-deep); }
.me-row-icon.is-amber,  .me-tone-amber  { background: var(--me-tone-amber-soft); color: var(--me-tone-amber-ink); --me-tile-strong: var(--me-tone-amber); --me-tile-ground: var(--me-tone-amber-soft); --me-tile-deep: var(--me-tone-amber-deep); }
.me-row-icon.is-plum,   .me-tone-plum   { background: var(--me-tone-plum-soft); color: var(--me-tone-plum-ink); --me-tile-strong: var(--me-tone-plum); --me-tile-ground: var(--me-tone-plum-soft); --me-tile-deep: var(--me-tone-plum-deep); }
.me-row-icon.is-indigo, .me-tone-indigo { background: var(--me-tone-indigo-soft); color: var(--me-tone-indigo-ink); --me-tile-strong: var(--me-tone-indigo); --me-tile-ground: var(--me-tone-indigo-soft); --me-tile-deep: var(--me-tone-indigo-deep); }
.me-row-icon.is-lime,   .me-tone-lime   { background: var(--me-tone-lime-soft); color: var(--me-tone-lime-ink); --me-tile-strong: var(--me-tone-lime); --me-tile-ground: var(--me-tone-lime-soft); --me-tile-deep: var(--me-tone-lime-deep); }
.me-row-icon.is-coral,  .me-tone-coral  { background: var(--me-tone-coral-soft); color: var(--me-tone-coral-ink); --me-tile-strong: var(--me-tone-coral); --me-tile-ground: var(--me-tone-coral-soft); --me-tile-deep: var(--me-tone-coral-deep); }

/* The forecourt grades, for the wallet tiles. Same shape as the tones above
   — a ground, the ink measured on it, and a strong step — but the colour is
   the pump handle's rather than an operator's choice: `web.fuel_grade` reads
   it off the wallet. A promotion picks from the six tones; a wallet never
   does, and nothing picks from the grades.

   Each publishes its colours as `--me-tile-strong` / `--me-tile-ground` /
   `--me-tile-deep`, so every rule that dresses a surface names neither a
   grade nor a tone and one rule covers all seven. */
.me-fuel-petrol { background: var(--me-fuel-petrol-soft); color: var(--me-fuel-petrol-ink); --me-tile-strong: var(--me-fuel-petrol); --me-tile-ground: var(--me-fuel-petrol-soft); --me-tile-deep: var(--me-fuel-petrol-deep); }
.me-fuel-diesel { background: var(--me-fuel-diesel-soft); color: var(--me-fuel-diesel-ink); --me-tile-strong: var(--me-fuel-diesel); --me-tile-ground: var(--me-fuel-diesel-soft); --me-tile-deep: var(--me-fuel-diesel-deep); }
.me-fuel-premium { background: var(--me-fuel-premium-soft); color: var(--me-fuel-premium-ink); --me-tile-strong: var(--me-fuel-premium); --me-tile-ground: var(--me-fuel-premium-soft); --me-tile-deep: var(--me-fuel-premium-deep); }
.me-fuel-paraffin { background: var(--me-fuel-paraffin-soft); color: var(--me-fuel-paraffin-ink); --me-tile-strong: var(--me-fuel-paraffin); --me-tile-ground: var(--me-fuel-paraffin-soft); --me-tile-deep: var(--me-fuel-paraffin-deep); }
.me-fuel-lubricant { background: var(--me-fuel-lubricant-soft); color: var(--me-fuel-lubricant-ink); --me-tile-strong: var(--me-fuel-lubricant); --me-tile-ground: var(--me-fuel-lubricant-soft); --me-tile-deep: var(--me-fuel-lubricant-deep); }
.me-fuel-fuel { background: var(--me-fuel-fuel-soft); color: var(--me-fuel-fuel-ink); --me-tile-strong: var(--me-fuel-fuel); --me-tile-ground: var(--me-fuel-fuel-soft); --me-tile-deep: var(--me-fuel-fuel-deep); }
.me-fuel-money { background: var(--me-fuel-money-soft); color: var(--me-fuel-money-ink); --me-tile-strong: var(--me-fuel-money); --me-tile-ground: var(--me-fuel-money-soft); --me-tile-deep: var(--me-fuel-money-deep); }

/* A surface that is a *thing you hold* rather than a pane the page prints
   on: the balance card, a hero, the card screen, the row that names whose
   card this is. The deep step of whatever tone or grade the element wears,
   which `.me-fuel-*` and `.me-tone-*` both publish as `--me-tile-deep`.

   Like the hero below it, this lives under the tone rules rather than beside
   the components it dresses: `.me-card` sets a pale surface at the same
   specificity and whichever comes last wins. */
/* A pane that wears a tone rather than the plain surface — an explainer
   that says what a screen is for before a word is read. Stated here for the
   same reason `.me-deep` is: `.me-card` sets its surface at equal
   specificity further up, and the last rule wins. */
.me-card.me-tone-teal, .me-card.me-tone-amber, .me-card.me-tone-plum,
.me-card.me-tone-indigo, .me-card.me-tone-lime, .me-card.me-tone-coral {
  background: var(--me-tile-ground);
  color: var(--me-tile-ink, inherit);
}

.me-deep {
  position: relative;
  overflow: hidden;
  background: var(--me-tile-deep, var(--me-fuel-fuel-deep));
  color: var(--me-fuel-deep-ink);
  box-shadow:
    var(--me-tile-lift),
    inset 0 1px 0 var(--me-fuel-deep-edge);
}
/* Whatever a component normally rules or tints inside itself reads off the
   deep ground instead. */
.me-deep .me-row,
.me-deep .me-list > li + li { border-color: var(--me-fuel-deep-edge); }
.me-deep .me-row-meta,
.me-deep .me-row-value small { color: var(--me-fuel-deep-dim); }
.me-deep .me-qr { border-color: var(--me-fuel-deep-edge); }
.me-deep :focus-visible { outline-color: var(--me-fuel-deep-ink); }

/* A hero takes the *deep* step of whatever tone or grade it wears, and this
   has to be said down here rather than up in `.me-hero`: the tone and grade
   rules above set the pale ground at the same specificity, and at equal
   specificity the later rule wins. That ordering has now caught four changes
   in this sheet — `.me-pump`, `.me-btn`'s border, the wallet card's ground,
   and this — so when a rule here looks ignored, check what is below it. */
.me-hero {
  background: var(--me-tile-deep, var(--me-fuel-fuel-deep));
  color: var(--me-fuel-deep-ink);
}

.me-row-body { flex: 1; min-width: 0; }
/* The face value beside what is left of it, quieter than the figure that
   matters: a coupon part-drawn reads "2 L of 10 L". */
.me-row-of { font-size: var(--fs-13); font-weight: var(--fw-regular); color: var(--me-ink-3); }
.me-row-title {
  display: block;
  font-size: var(--fs-16);
  font-weight: var(--fw-medium);
  letter-spacing: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.me-row-meta {
  display: block;
  font-size: var(--fs-13);
  color: var(--me-ink-3);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The figure a driver came to the row for (2026-10-02): a size up, tracked
   in, and in the accent. The reference's lists put the number in the brand
   colour at the end of the row and let everything else stay ink — which is
   what makes a list of them scannable without reading a single label. */
.me-row-value {
  display: block;
  flex: none;
  text-align: right;
  font-size: var(--fs-18);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.012em;
  color: var(--me-accent-link);
}
.me-row-value small {
  display: block;
  font-size: var(--fs-12);
  font-weight: var(--fw-regular);
  color: var(--me-ink-3);
}
.me-row-value.is-bad { color: var(--me-bad); }
/* Points earned by a fill, under its cost: the same small line as the rate,
   in the accent so it reads as a gain rather than a charge. */
.me-row-value .me-points { color: var(--me-accent-deep); font-weight: var(--fw-semibold); }
.me-row-chev { flex: none; color: var(--me-ink-3); }
/* The reference on its own line under the site and time: it matters in a
   dispute and nowhere else, so it is the smallest thing on the row. */
.me-row-ref { font-size: var(--fs-12); }
/* "All ›" at the head of a list: a link that says it goes somewhere, not a
   word that looked like a button and did nothing a button does. */
.me-more {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: var(--fs-14);
  font-weight: var(--fw-medium);
  color: var(--me-accent-deep);
  text-decoration: none;
  min-height: 44px;
  padding: 0 var(--s-2);
}
.me-more:hover { text-decoration: underline; }

/* A date heading inside a list — the reference's tinted header row, in
   sentence case rather than tracked capitals — so a year of fills reads as
   days rather than as one undifferentiated column of numbers. */
/* A day heading (2026-10-02). It is the one break in a list that means
   something, so it is the one place a rule survives — above it, where it
   separates days rather than rows. Sentence-size and tracked in, to read as
   a heading now that the rows beneath it have no rules of their own. */
.me-group {
  padding: var(--s-5) var(--s-5) var(--s-2);
  font-size: var(--fs-15);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.008em;
  color: var(--me-ink-2);
  background: var(--me-surface);
}
.me-list > li.me-group + li { border-top: 0; }
.me-list > li + li.me-group { border-top: 1px solid var(--me-line); }

/* ──────────────────────────────────────────────────────────────────── chips */

.me-pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: var(--me-r-pill);
  font-size: var(--fs-12);
  font-weight: var(--fw-semibold);
  background: var(--me-surface-2);
  color: var(--me-ink-2);
}
.me-pill.is-ok { background: var(--me-ok-soft); color: var(--me-ok); }
.me-pill.is-bad { background: var(--me-bad-soft); color: var(--me-bad); }
.me-pill.is-warn { background: var(--me-warn-soft); color: var(--me-warn); }
.me-pill.is-teal { background: var(--me-tone-teal-soft); color: var(--me-tone-teal-ink); }

/* Amount chips on the code screen and pump tiles on the pay screen
   (2026-10-05). Both are a tap in place of typing, so both keep the 44px
   floor; the chip is a pill because it is a choice among a few, the tile is
   a key because it is a number on a pad. Filled, like every other pane. */
.me-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-2); margin-top: var(--s-4); }
.me-chip {
  display: inline-flex;
  align-items: center;
  min-height: var(--me-tap);
  padding: 0 var(--s-4);
  border-radius: var(--me-r-pill);
  background: var(--me-surface-2);
  color: var(--me-ink);
  font-size: var(--fs-14);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}
.me-chip:hover { background: var(--me-sunk); }
.me-chip[aria-current="true"] { background: var(--me-accent); color: var(--me-accent-ink); }

/* "You're fuelling at" (2026-10-05): the station the pay screen opened on,
   as a filled row in the pane's second step. It reads the field beneath it
   and is not itself a control, so it has no hover and no pointer. */
.me-at {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--me-r);
  background: var(--me-surface-2);
}
.me-at-body { display: flex; flex-direction: column; min-width: 0; }
.me-at-label { font-size: var(--fs-12); color: var(--me-ink-3); }
.me-at-name { font-weight: var(--fw-semibold); overflow-wrap: anywhere; }
.me-at-where { font-size: var(--fs-13); color: var(--me-ink-3); }
.me-at-where:empty { display: none; }
/* A station's name in the list is the way to its page. */
.me-stn-link { color: var(--me-accent-link); text-decoration: none; }
.me-stn-link:hover { text-decoration: underline; }

.me-pump-group { display: flex; flex-direction: column; gap: var(--s-2); }
.me-pumps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-2); }
.me-pump {
  min-height: 56px;
  border: 0;
  border-radius: var(--me-r);
  background: var(--me-surface-2);
  color: var(--me-ink);
  font-family: var(--me-font-display);
  font-size: var(--fs-18);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.me-pump:hover { background: var(--me-sunk); }

/* ──────────────────────────────────────────────────────────── promotions */
/* The strip: cards side by side, one and a bit visible, snapping as the
   thumb flicks. Each card is its tone's soft ground; the title in the
   tone's ink, the line in body ink, so both read on the tint in either
   theme. The strong step used to be a left edge and the kicker was tracked
   capitals; both went on 2026-10-06 — a left-bordered card is the one
   shape every generated dashboard shares, and the kicker is a sentence. */
.me-promos {
  display: flex;
  gap: var(--s-3);
  margin: 0 calc(-1 * var(--me-gutter));
  padding: 2px var(--me-gutter) 6px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Snap to the gutter, not the edge: without this the first card snaps
     flush to the screen and the strip loses the margin everything else has. */
  scroll-padding-inline: var(--me-gutter);
  scrollbar-width: none;
}
.me-promos::-webkit-scrollbar { display: none; }
/* One card, or the full list: a column with the stack's own gap. */
.me-promos.is-one { flex-direction: column; margin: 0; padding: 0; overflow: visible; scroll-snap-type: none; }
.me-promo {
  flex: 0 0 min(78%, 300px);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--s-4);
  border-radius: var(--me-r-lg);
  text-decoration: none;
}
.me-promos.is-one .me-promo { flex-basis: auto; }
.me-promos-head { display: flex; align-items: center; padding: 0 0 var(--s-2); }
.me-promos-head .spacer { flex: 1; }
.me-promo:hover { text-decoration: none; filter: brightness(.98); }
.me-promo-kicker {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-12);
  font-weight: var(--fw-semibold);
}
.me-promo-title {
  font-size: var(--fs-18);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.me-promo-line { font-size: var(--fs-14); color: var(--me-ink); line-height: 1.4; }
.me-promo-until { font-size: var(--fs-12); color: var(--me-ink-2); margin-top: auto; }

/* The promotion's own screen: the card grown to a header, the story under
   it, the button — if there is one — in the tone. */
.me-promo-head {
  padding: var(--s-5) var(--s-4);
  border-radius: var(--me-r-lg);
}
.me-promo-head .me-promo-title { font-size: clamp(1.5rem, 7vw, 1.9rem); }
.me-promo-body { padding: var(--s-4) 0 0; }
.me-promo-body p { margin: 0 0 var(--s-3); font-size: var(--fs-16); line-height: 1.5; color: var(--me-ink); }
.me-btn.me-btn-tone { border-color: transparent; }
.me-btn.me-btn-tone:hover { filter: brightness(.96); }

/* ─────────────────────────────────────────────────────────────────── fields */

/* A phone's field: a quiet label, a rounded box, and focus is a ring in the
   accent — the treatment the driver's other apps use. */
.me-field { display: flex; flex-direction: column; gap: 6px; }
.me-field + .me-field { margin-top: var(--s-4); }
.me-label {
  font-size: var(--fs-12);
  font-weight: var(--fw-regular);
  color: var(--me-ink-2);
}
.me-input {
  width: 100%;
  min-height: 50px;
  padding: 0 var(--s-3);
  border: 1px solid var(--me-line-strong);
  border-radius: var(--me-r);
  background: var(--me-surface);
  color: var(--me-ink);
  font: inherit;
  /* 16px or larger, or iOS zooms the page on focus and the layout jumps. */
  font-size: 16px;
}
/* Same reason as the terminal's .pos-secret: a card PIN in a password field
   is a card PIN offered to the phone's keychain. Masked text instead. */
.me-input.me-secret { -webkit-text-security: disc; letter-spacing: .3em; }
.me-input::placeholder { color: var(--me-ink-3); }
.me-input:focus {
  outline: none;
  border-color: var(--me-accent);
  box-shadow: 0 0 0 3px var(--me-accent-soft);
}
.me-input[aria-invalid="true"] { border-color: var(--me-bad); }
.me-help { font-size: var(--fs-13); color: var(--me-ink-3); margin: 0; }
.me-error { font-size: var(--fs-13); color: var(--me-bad); font-weight: var(--fw-medium); margin: 0; }

/* One box per digit. A code typed into a single field is easy to lose your
   place in; six boxes show progress and let a paste fill them all. */
.me-otp {
  display: flex;
  gap: var(--s-2);
  justify-content: space-between;
}
.me-otp input {
  width: 100%;
  min-width: 0;
  height: 56px;
  padding: 0;
  text-align: center;
  font-size: var(--fs-22);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--me-line-strong);
  background: var(--me-surface);
  color: var(--me-ink);
}
.me-otp input:focus {
  outline: none;
  border-color: var(--me-accent);
  box-shadow: inset 0 -2px 0 var(--me-accent);
}

/* ────────────────────────────────────────────────────────────── the amount pad */

.me-amount {
  text-align: center;
  padding: var(--s-4) 0;
}
.me-amount-value {
  /* Inline, so the underline that marks focus hugs the figure and its unit
     rather than running the width of the card. */
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
  padding: 0 var(--s-2);
}
/* The figure IS the field. A display mirroring a hidden input is two pieces
   of state that can disagree, and the hidden one cannot be typed into. */
.me-amount-input {
  /* The field grows with what is typed, so a lone "0" sits in the middle of
     the card rather than parked at the right of a seven-character box.
     `field-sizing` is the modern answer; the width below is what browsers
     without it fall back to, chosen so the common case still looks centred. */
  width: 2.5ch;
  field-sizing: content;
  min-width: 1ch;
  max-width: 10ch;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: clamp(2.5rem, 14vw, 3.25rem);
  font-weight: var(--fw-regular);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  text-align: right;
}
.me-amount-input::placeholder { color: var(--me-ink-3); opacity: 1; }
/* The figure is the field, but it is not a box: focus is the unit turning
   accent and a hairline under the figure, not a ring drawn around a number
   at display size. The app-wide ring rule is restated away here because it
   matches `:focus-visible` at the same weight and would otherwise win. */
.me-amount-input:focus,
.me-app .me-amount-input:focus-visible { outline: none; }
.me-amount-value { border-bottom: 2px solid transparent; }
.me-amount:focus-within .me-amount-value { border-bottom-color: var(--me-accent); }
.me-amount:focus-within .me-amount-unit { color: var(--me-accent); }
.me-amount-unit { font-size: var(--fs-18); color: var(--me-ink-3); font-weight: var(--fw-medium); }
.me-amount-meta { margin-top: var(--s-2); font-size: var(--fs-13); color: var(--me-ink-3); }

/* The app's keypad: one sheet in the shell, over the tab bar, revealed by
   the script while a digit field has focus. Fixed rather than inline so it
   is where a phone's keyboard would be — the thumb already knows the way —
   and so the field it writes into stays in view above it. The main column
   takes the sheet's measured height as padding while it is up (the script
   sets `--me-keypad-h`), so the button at the foot of a form can be scrolled
   clear of it, the way the tab bar is handled. */
.me-keypad {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  background: var(--me-surface);
  border-top: 1px solid var(--me-line);
  padding: 0 var(--s-2) calc(var(--s-2) + env(safe-area-inset-bottom));
  box-shadow: 0 -8px 24px rgba(0, 0, 0, .08);
}
.me-keypad-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: 44px;
  padding: 0 var(--s-2);
}
.me-keypad-for {
  font-size: var(--fs-13);
  color: var(--me-ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.me-keypad-done {
  min-height: 44px;
  padding: 0 var(--s-3);
  border: 0;
  background: none;
  color: var(--me-accent-deep);
  font: inherit;
  font-weight: var(--fw-semibold);
  cursor: pointer;
}
.me-shell.is-keypad .me-main,
.me-shell.is-keypad:has(.me-tabs) .me-main {
  padding-bottom: calc(var(--me-keypad-h, 300px) + var(--s-6));
}

.me-pad {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-2);
}
.me-key {
  min-height: 56px;
  border: 0;
  border-radius: var(--me-r);
  background: var(--me-surface-2);
  color: var(--me-ink);
  font: inherit;
  font-size: var(--fs-22);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
/* The decimal point for a PIN: withheld, but its cell kept, so the zero
   stays under the eight where a thumb expects it. */
.me-key[data-void] { visibility: hidden; pointer-events: none; }
.me-key:hover { background: var(--me-accent-soft); }
.me-key:active { background: var(--me-surface-2); }

/* ──────────────────────────────────────────────────────────────────── codes */

/* The camera, for the pump's code. A dark frame with a white reticle, the
   status line beneath; falls to the typed reference when the browser has no
   detector or the camera is refused. */
.me-scanner {
  position: relative;
  aspect-ratio: 1 / 1;
  max-height: 60vh;
  background: var(--n-900);
  border-radius: var(--me-r-lg);
  overflow: hidden;
  display: grid;
  place-items: center;
}
.me-scanner-view { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.me-scanner-frame { position: relative; width: 62%; aspect-ratio: 1 / 1; border: 3px solid var(--n-0); border-radius: var(--me-r); opacity: .9; }
.me-scanner-status { position: absolute; left: 0; right: 0; bottom: 0; margin: 0; padding: var(--s-3); text-align: center; color: var(--n-0); background: rgba(22, 27, 34, .72); font-size: var(--fs-13); }

/* A wallet to pay with: a row that is a radio. The dot sits where the icon
   does on other rows, so the list reads the same. */
.me-choice { cursor: pointer; }
.me-choice input { width: 20px; height: 20px; margin: 0; accent-color: var(--me-accent); flex: 0 0 auto; }
.me-choice:has(input:disabled) { opacity: .55; cursor: not-allowed; }
.me-choice:has(input:checked) { background: var(--me-accent-soft); }

.me-qr {
  display: grid;
  place-items: center;
  padding: var(--s-4);
  /* Always the light surface, in both themes: a scanner reads black on
     white, and an inverted QR at a pump is a code that does not work. */
  background: var(--me-qr-ground);
  border: 1px solid var(--me-line);
  border-radius: var(--me-r);
}
.me-qr svg { width: min(240px, 62vw); height: auto; display: block; }

.me-code-text {
  font-family: var(--font-mono);
  font-size: var(--fs-22);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.06em;
  text-align: center;
  word-break: break-all;
  margin: 0;
}

/* A clock on a bearer instrument is the most important thing on the screen
   after the code itself. A pill: a status, so it keeps the curve. */
.me-countdown {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: var(--me-r-pill);
  background: var(--me-warn-soft);
  color: var(--me-warn);
  font-size: var(--fs-13);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}
.me-countdown.is-urgent { background: var(--me-bad-soft); color: var(--me-bad); }

/* ───────────────────────────────────────────────────────── security cues */

/* Said once, where the decision is: what this screen can and cannot give
   away. A flat pane with the accent rule on its leading edge, which is how the
   reference marks a note. */
.me-secure {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  padding: var(--s-3);
  background: var(--me-accent-soft);
  border-radius: var(--me-r-sm);
  color: var(--me-ink-2);
  font-size: var(--fs-13);
  line-height: 1.4;
  margin: 0;
}
.me-secure svg { flex: none; color: var(--me-accent); margin-top: 1px; }

/* ────────────────────────────────────────────────────────────── feedback */

.me-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  padding: var(--s-3);
  border-radius: var(--me-r-sm);
  font-size: var(--fs-14);
  line-height: 1.4;
}
.me-alert svg { flex: none; margin-top: 1px; }
/* A link inside an alert takes the alert's colour. Left to the browser it
   comes out default blue on a red wash — the one place in the app where a
   colour is carrying meaning. */
.me-alert a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.me-alert a:hover { text-decoration-thickness: 2px; }

/* Prose links elsewhere. The app is nearly all buttons and rows, so there are
   few — which is exactly why an unstyled one stands out as a mistake. */
.me-app a:not([class]) { color: var(--me-accent-deep); text-underline-offset: 2px; }
.me-alert-success { background: var(--me-ok-soft); color: var(--me-ok); }
.me-alert-error { background: var(--me-bad-soft); color: var(--me-bad); }
.me-alert-warning { background: var(--me-warn-soft); color: var(--me-warn); }
.me-alert-info { background: var(--me-surface-2); color: var(--me-ink-2); }

.me-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-8) var(--s-4);
  text-align: center;
  color: var(--me-ink-3);
}
.me-empty svg { color: var(--me-line-strong); }
.me-empty b { color: var(--me-ink); font-weight: var(--fw-semibold); font-size: var(--fs-16); }


/* ═══════════════════════════════════════════════════════ the install invite

   Server-rendered but `hidden`, and only ever revealed by script. That order
   matters: a browser that cannot install anything — a desktop, an in-app
   webview, a phone where the app is already on the home screen — shows
   nothing at all rather than an invitation it could not honour. */

.me-install {
  background: var(--me-surface);
  border: 1px solid var(--me-line);
  border-left: 3px solid var(--me-accent);
  padding: var(--s-4);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.me-install-lead { display: flex; gap: var(--s-3); align-items: flex-start; }
.me-install-lead .me-row-icon { background: var(--me-accent-soft); color: var(--me-accent-deep); }
.me-install-lead b {
  display: block;
  font-size: var(--fs-16);
  font-weight: var(--fw-semibold);
  color: var(--me-ink);
}
.me-install-lead p { margin: 2px 0 0; font-size: var(--fs-13); color: var(--me-ink-2); }

.me-install-actions { display: flex; gap: var(--s-2); }
.me-install-actions > * { flex: 1; }

/* iOS fires no install event at all, so the only honest thing to offer there
   is the sequence of taps that does it. Numbered, because it is a sequence. */
.me-install-steps {
  margin: 0;
  padding-left: 20px;
  display: grid;
  gap: 6px;
  font-size: var(--fs-13);
  color: var(--me-ink-2);
}
.me-install-steps b { color: var(--me-ink); font-weight: var(--fw-semibold); }
.me-install-body { padding: 12px 16px 16px; }
.me-gate-aside { margin: 12px 0 0; font-size: var(--fs-13); color: var(--me-ink-2); }
.me-gate-aside b { color: var(--me-ink); font-weight: var(--fw-semibold); }

/* The install gate (loyalty/_gate.html, 2026-09-19): the whole screen,
   over everything, until the app is opened from the home screen. `[hidden]`
   is restated because the block sets its own display. */
.me-gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-6) var(--s-5);
  background: var(--me-ground);
  overflow-y: auto;
}
.me-gate[hidden] { display: none; }
.me-gate-body {
  width: 100%;
  max-width: 420px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-4);
  text-align: center;
}
.me-gate-body > div { width: 100%; }
.me-gate-icon { border-radius: 18px; border: 1px solid var(--me-line); }
.me-gate-title {
  margin: 0;
  font-size: var(--fs-20);
  font-weight: var(--fw-semibold);
  color: var(--me-ink);
  text-wrap: balance;
}
.me-gate-lede { margin: 0; font-size: var(--fs-14); color: var(--me-ink-2); }
.me-gate-steps {
  text-align: left;
  padding: var(--s-4) var(--s-4) var(--s-4) 36px;
  background: var(--me-surface);
  border: 1px solid var(--me-line);
  border-radius: var(--me-r-lg);
}
.me-gate-done {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-14);
  font-weight: var(--fw-medium);
  color: var(--me-ok);
}
.me-gate-done[hidden] { display: none; }

/* ──────────────────────────────────────────────────────────────── tab bar */

/* Spans the screen, whatever the screen is. The current tab carries a 2px
   marker on the edge nearest the content — the reference's underline, turned
   over for a bar that sits at the bottom. */
.me-tabs {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  background: var(--me-nav-bg);
  border-top: 1px solid var(--me-line);
  padding-bottom: env(safe-area-inset-bottom);
}
.me-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 64px;
  padding: 8px 2px 8px;
  color: var(--me-ink-3);
  text-decoration: none;
  font-size: 11px;
  font-weight: var(--fw-medium);
}
/* The current tab: a 56×30 pill behind its icon, the way a phone's own bars
   mark it, rather than a line on the bar's edge. */
.me-tab svg { padding: 4px 17px; border-radius: var(--me-r-pill); box-sizing: content-box; }
/* The current tab's glyph fills harder as well as sitting on its pill —
   the two-tone sprite reads `--me-duo` for the weight of its fill. */
.me-tab[aria-current="page"] { --me-duo: .38; color: var(--me-accent-link); font-weight: var(--fw-semibold); }
.me-tab[aria-current="page"] svg { background: var(--me-accent-tint); }
.me-tab:hover { color: var(--me-ink); }
.me-tab span { line-height: 1; }

/* ───────────────────────────────────────────────────────────── onboarding */

/* Sign in (2026-10-02). The screen carries one question and one action, so
   it gets no pane: a card drawn around the only thing on the page tells the
   eye nothing. The form sits on the ground with room above it, which is also
   what puts the two fields and the button in the top two-thirds of a phone —
   reachable without the hand moving. */
.me-signin { padding: var(--s-7) 0 var(--s-5); }
.me-signin-title { margin-bottom: var(--s-1); }
.me-signin .me-lede { margin-bottom: var(--s-6); }
.me-signin-form { gap: var(--s-4); }
/* Beside the field it is about, not under the button, so the button is the
   last thing before the thumb. */
.me-signin-forgot {
  margin: calc(var(--s-1) * -1) 0 var(--s-2);
  text-align: right;
}
.me-signin-new {
  margin: var(--s-7) 0 0;
  color: var(--me-ink-3);
  font-size: var(--fs-14);
}

.me-intro {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: var(--s-5) 0 var(--s-2);
}
/* The product mark: a square tile in the accent. */
.me-mark {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  background: var(--me-accent);
  color: var(--me-accent-ink);
  border-radius: var(--me-r);
  font-weight: var(--fw-bold);
  font-size: var(--fs-18);
  letter-spacing: 0;
}
.me-points { display: flex; flex-direction: column; gap: var(--s-4); }
.me-point { display: flex; gap: var(--s-3); align-items: flex-start; }
.me-point .me-row-icon { background: var(--me-accent-soft); color: var(--me-accent-deep); }
.me-point b { display: block; font-weight: var(--fw-semibold); font-size: var(--fs-16); }
.me-point p { margin: 2px 0 0; font-size: var(--fs-14); color: var(--me-ink-2); }

/* ────────────────────────────────────────────────────────────────── utility */

.me-stack { display: flex; flex-direction: column; gap: var(--s-3); }
.me-stack-tight { display: flex; flex-direction: column; gap: var(--s-2); }
.me-between { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
/* Hidden from sight, NOT from a screen reader or the tab order. `display:
   none` on a form control means it cannot hold focus, so a hardware keyboard
   or an accessibility tool has nothing to type into — the exact bug the POS
   tap field was fixed for. */
.me-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Focus has to survive on every surface here, including the accent fill and
   the dark bar. */
.me-app :focus-visible {
  outline: 2px solid var(--me-accent);
  outline-offset: 2px;
}
.me-btn-primary:focus-visible { outline-color: var(--me-ink); }
/* Seven possible grounds, so focus takes the surface's own ink. */
.me-hero :focus-visible { outline-color: currentColor; }
.me-bar :focus-visible { outline-color: var(--me-accent); }

/* A very small phone (320px) still has to fit the tab bar and the balance. */
@media (max-width: 340px) {
  .me-app { font-size: 15px; --me-gutter: 12px; }
  .me-main { padding-left: 12px; padding-right: 12px; }
  .me-tab { font-size: 10px; }
}

/* ═══════════════════════════════════════════════════════════════════ wide

   Past a phone the screen lays out in as many columns as fit. The balance,
   the primary action, the alerts and the sign-in pitch span them all; every
   card and form takes a column. The primary action becomes a row of commands
   rather than a screen-wide button. */
@media (min-width: 720px) {
  .me-main {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    align-content: start;
    align-items: start;
    gap: var(--s-4);
    padding: var(--s-4) var(--s-6) var(--s-8);
  }
  .me-main > .me-hero,
  .me-main > .me-alert,
  .me-main > .me-actions,
  .me-main > .me-intro,
  .me-main > .me-note,
  .me-main > .me-install,
  .me-main > .me-btn,
  .me-main > form:not(.me-card):not(.me-stack) { grid-column: 1 / -1; }
  .me-main > .me-actions {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }
  .me-main > .me-actions > .me-btn-block { width: auto; min-width: 280px; }
  .me-main > .me-actions .me-actions-row { flex: 1; }
  .me-main > .me-btn { width: auto; min-width: 280px; justify-self: start; }
  .me-hero-value { font-size: 3.25rem; }
  .me-bar { padding-left: var(--s-6); padding-right: var(--s-3); }
  .me-back { margin-left: calc(var(--s-6) * -1 + var(--s-1)); }
  /* Past a phone the top band stops reaching for the edges: edge to edge in
     a column of a grid is a block that runs into its neighbours. The wallet
     track keeps its bleed — it is still a track, and a tile half off the
     right edge is how it says to swipe. */
  .me-home-top { margin: 0; }
}


/* ══════════════════════════════════════════════════════════ the dashboard

   Home as an insight dashboard and Insights as a screen of its own
   (2026-09-16, docs/DRIVER-DASHBOARD.md). Every figure below is derived
   by services.dashboard; nothing here computes. Sizes are the spec's:
   20px gutters, 20px section gap, 18px card padding, 44px targets. */

.me-dash { display: flex; flex-direction: column; gap: 20px; }

/* Headings and figures in the display face. */
.me-h2,
.me-wallet-balance,
.me-stat-value,
.me-kpi-value,
.me-row-value { font-family: var(--me-font-display); }

/* ---- header: who, and the two icon buttons ----
   The dashboard puts this in place of the app bar, so it has to carry what
   the bar carries: the phone's safe area, or the greeting renders under the
   status bar and a notch takes the top of the driver's name with it. The
   gutter is the same one `.me-main` uses, so the avatar starts where the
   wallet card below it starts. */
.me-top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: calc(env(safe-area-inset-top) + var(--s-3)) var(--me-gutter) var(--s-1);
}
.me-avatar {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: 50%;
  background: var(--me-accent-tint);
  color: var(--me-accent-link);
  font-family: var(--me-font-display);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-14);
  letter-spacing: .02em;
}
.me-greet { flex: 1; min-width: 0; line-height: 1.2; }
/* The greeting shares its line with which card this is (2026-10-07): a
   driver can hold more than one, and every figure below belongs to exactly
   one of them. The last four digits are what a card is called out loud; the
   way to the whole number is *My number*, one row down, because a caption
   this size cannot carry a 44px tap target. Masked by the same eye as the
   balances — it is the other thing on this screen you would not want read
   over your shoulder. */
.me-greet-top { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.me-greet-hi { display: block; font-size: 12px; color: var(--me-ink-3); }
/* A size up and tracked in (2026-10-02), so the one name on the home screen
   reads as the screen's heading rather than a caption on the avatar. */
.me-greet-name {
  display: block;
  font-family: var(--me-font-display);
  font-size: 21px;
  letter-spacing: -0.014em;
  font-weight: var(--fw-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The two icon buttons on the dashboard's own header: the bar's buttons
   with a surface and a border, the way the spec draws them. */
.me-top .me-iconbtn {
  border: 1px solid var(--me-line);
  border-radius: 14px;
  background: var(--me-surface);
  color: var(--me-ink);
}
.me-top .me-iconbtn:hover { background: var(--me-surface-2); }
.me-top .me-dot { top: -6px; right: -6px; min-width: 20px; height: 20px; line-height: 20px; font-size: 11px; }

/* Several wallets: chips to switch which one an Insights screen is about.
   The wallet *card* rules that used to sit here went with the balance when
   it moved onto tiles (2026-10-07) — they were shadowed by the tile block
   and had stopped applying. */
.me-wallet-switch { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.me-wallet-chip {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0 12px;
  border-radius: var(--me-r-pill);
  background: var(--me-accent-strong);
  color: inherit;
  font-size: 13px;
  font-weight: var(--fw-medium);
  text-decoration: none;
}
.me-wallet-chip[aria-current="true"] { background: var(--me-accent-ink); color: var(--me-accent); }

/* Hidden balance: the figures the eye masks read as dots. */
.me-app.is-hidden [data-secret] { visibility: hidden; position: relative; }
.me-app.is-hidden [data-secret]::after {
  content: "••••";
  visibility: visible;
  position: absolute;
  left: 0;
  top: 0;
  letter-spacing: .1em;
}

/* ---- actions ---- */
/* The filled call to action and the three-up pane below it were replaced by
   one dark bar of four on 2026-10-08 (`.me-acts`): at a forecourt they are
   four ways to pay for fuel, not one important action and three lesser
   ones. */

/* Hidden balance: the figures the eye masks read as dots. */
.me-app.is-hidden [data-secret] { visibility: hidden; position: relative; }
.me-app.is-hidden [data-secret]::after {
  content: "••••";
  visibility: visible;
  position: absolute;
  left: 0;
  top: 0;
  letter-spacing: .1em;
}

/* ---- actions ---- */
/* The three secondary actions as one segmented pane (2026-10-06): a
   hairline between the segments rather than a tile each, and the glyph in
   the accent rather than a coloured well — these are actions, not kinds of
   thing, and the six tones are for telling kinds apart. */
/* `.me-quick`, the three-up pane, went with `.me-cta` into `.me-acts`. */
.me-well {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex: none;
  border-radius: var(--me-r);
  --me-duo: .24;
}
.me-well.is-amber  { background: var(--me-amber-tint);   color: var(--me-amber); }
.me-well.is-indigo { background: var(--me-tone-indigo-soft); color: var(--me-indigo); }
.me-well.is-teal   { background: var(--me-accent-tint);  color: var(--me-accent-link); }
.me-well.is-coral  { background: var(--me-tone-coral-soft); color: var(--me-tone-coral-ink); }
.me-well.is-ok     { background: var(--me-success-tint); color: var(--me-success); }

/* ---- a panel: a card with a heading row and a link on the right ---- */
.me-panel-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 14px; }
.me-panel-head .me-h2 { margin: 0; font-size: 16px; font-weight: var(--fw-semibold); }
.me-panel-head .spacer { flex: 1; }
.me-panel-note { font-size: 12px; color: var(--me-ink-3); }
.me-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin: -12px 0;
  color: var(--me-accent-link);
  font-size: 14px;
  font-weight: var(--fw-medium);
  text-decoration: none;
}
.me-link:hover { text-decoration: underline; }
.me-caption { margin: 10px 0 0; font-size: 12px; color: var(--me-ink-3); }

/* ---- every wallet on Insights (A7) ---- */
/* Home's chips sit on the dark wallet card; on the page ground they invert:
   a quiet bordered pill, the chosen one filled in the accent. */
.me-wallet-switch-insights { margin: 0 0 var(--s-2); }
.me-wallet-switch-insights .me-wallet-chip {
  background: var(--me-surface);
  color: var(--me-ink-2);
  border: 1px solid var(--me-line-strong);
}
.me-wallet-switch-insights .me-wallet-chip[aria-current="true"] {
  background: var(--me-accent);
  color: var(--me-accent-ink);
  border-color: var(--me-accent);
}
.me-wallet-head-line { margin-top: var(--s-4); }


/* ---- the loyalty app's own pieces (2026-09-18) ----
   The sheet is the driver app's; these are the few shapes only a member's
   screens have. `ly-` so a driver-app page can never pick one up. */
.ly-number { margin: 0; text-align: center; letter-spacing: .12em; }
.ly-next-body { display: flex; align-items: flex-start; gap: 12px; }
.ly-next-copy { flex: 1; min-width: 0; }
.ly-next-copy b { display: block; font-size: 15px; font-weight: var(--fw-semibold); }
.ly-next .me-meter { margin-top: 8px; }
.ly-hero-sm { padding: 16px 20px; }
.ly-hero-sm .me-hero-value { font-size: 36px; }
.ly-reward { padding-bottom: 10px; }
.ly-reward .me-row { padding-bottom: 4px; }
.ly-reward-meter { margin: 0 0 0 52px; height: 6px; }
.ly-short { display: block; font-size: 11px; color: var(--me-ink-3); text-align: right; }
.ly-reward .me-row-value .me-pill { display: inline-block; margin-top: 4px; }
.ly-member { display: flex; align-items: center; gap: 14px; }
.ly-member .me-avatar { width: 48px; height: 48px; font-size: 20px; flex: none; }
.ly-member-copy { display: grid; gap: 2px; min-width: 0; }
.ly-member-copy b { font-size: 17px; font-weight: var(--fw-semibold); }

/* ---- stations (A4) ---- */
.me-stn .me-row-title { white-space: normal; }
.me-stn-prices { display: flex; flex-wrap: wrap; gap: 4px 12px; padding: 0 0 10px 52px; font-size: 13px; color: var(--me-ink-2); }
/* The line grew a date and a second figure (2026-09-19): it wraps within
   itself now, keeping each figure whole. */
.me-stn-price { white-space: normal; }
.me-stn-price b { white-space: nowrap; }
.me-stn-price b { font-weight: var(--fw-semibold); color: var(--me-ink); }
[data-sort-by-distance] { white-space: nowrap; flex: none; }
.me-stn-price em { font-style: normal; color: var(--me-ink-3); }
.me-stn-when { color: var(--me-ink-3); font-size: 12px; }
[data-station][hidden] { display: none; }
.me-stn-go { flex: none; align-self: center; padding: 0 12px; min-height: 36px; }
[data-distance]:not(:empty)::before { content: " · "; }

/* ---- statement (A1) ---- */
.me-seg.me-stmt-seg { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.me-stmt-seg .me-seg-tab { padding-left: 4px; padding-right: 4px; font-size: 13px; }
.me-stmt-count { white-space: nowrap; }
/* A movement's figure is the line's, not the screen's: smaller than the
   fill list's value so the type and the reference keep their room. */
.me-stmt-amt { display: block; font-size: 15px; font-weight: var(--fw-semibold); white-space: nowrap; font-variant-numeric: tabular-nums; }
.me-stmt-amt.is-debit { color: var(--me-bad); }
.me-stmt-figure { flex: none; text-align: right; align-self: center; }
.me-stmt-run { display: block; font-size: 11px; color: var(--me-ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; }
.me-stmt-period { display: grid; gap: var(--s-3); }
.me-stmt-period .me-grid2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.me-stmt-period .me-field + .me-field { margin-top: 0; }
/* A date input has an intrinsic width wider than half a phone; it must
   shrink to its track or the second field leaves the screen. */
.me-stmt-period .me-input { min-width: 0; -webkit-appearance: none; appearance: none; }
.me-stmt-head { align-items: flex-start; }
.me-stmt-wallet { min-width: 0; }
.me-stmt-when { margin: 0; flex: 1; min-width: 0; }
.me-stmt + .me-stmt { margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--me-line); }
.me-stmt-head { margin-top: var(--s-3); }
.me-stmt-wallet { font-weight: var(--fw-semibold); }
.me-stmt-line .me-row-title { white-space: normal; }
.me-stmt-closing { font-size: 18px; font-weight: var(--fw-semibold); white-space: nowrap; }
.me-stmt-figures { display: grid; grid-template-columns: 1fr; gap: 6px; margin: var(--s-3) 0 0; }
.me-stmt-figures > div { display: flex; justify-content: space-between; gap: var(--s-3); }
.me-stmt-figures dt { font-size: 13px; color: var(--me-ink-3); }
.me-stmt-figures dd { margin: 0; font-size: 14px; }
.me-stmt-figures dd.is-credit { color: var(--me-ok); }
.me-stmt-figures dd.is-debit { color: var(--me-bad); }

/* ---- today ---- */
.me-stat-label { display: block; font-size: 12px; color: var(--me-ink-3); }
.me-stat-value { display: block; font-size: 22px; font-weight: var(--fw-semibold); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.me-strip {
  position: relative;
  height: 28px;
  margin-top: 14px;
  border-radius: 8px;
  background: var(--me-surface-2);
  overflow: hidden;
}
.me-tick {
  position: absolute;
  bottom: 0;
  width: 4px;
  border-radius: 2px;
  background: var(--me-accent);
  transform: translateX(-50%);
}
.me-now { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--me-ink); transform: translateX(-50%); }
.me-strip-labels { display: flex; justify-content: space-between; gap: 8px; margin-top: 6px; font-size: 11px; color: var(--me-ink-3); font-weight: var(--fw-medium); }

/* ---- the week ---- */

/* ---- insight cards ---- */
.me-insights { display: flex; flex-direction: column; gap: 10px; }
.me-insight {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px;
  border: 1px solid var(--me-line);
  border-radius: 18px;
  background: var(--me-surface);
}
.me-insight b { display: block; font-size: 15px; font-weight: var(--fw-semibold); }
.me-insight p { margin: 2px 0 0; font-size: 12px; color: var(--me-ink-3); }

/* ---- list cards: 6px vertical, 18px horizontal ---- */
.me-list-card { padding: 6px 18px; }
.me-list-card .me-panel-head { margin: 8px 0 4px; }
.me-list-card .me-row { padding-left: 0; padding-right: 0; }
.me-row-code { letter-spacing: .3px; }

/* ---- insights screen ---- */
.me-seg {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  padding: 4px;
  border: 1px solid var(--me-line);
  border-radius: 14px;
  background: var(--me-surface);
}
.me-seg-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border-radius: 10px;
  color: var(--me-tab-idle);
  font-size: 14px;
  font-weight: var(--fw-medium);
  text-decoration: none;
}
.me-seg-tab[aria-selected="true"] { background: var(--me-accent); color: var(--me-accent-ink); font-weight: var(--fw-semibold); }
.me-seg.me-seg-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Tabs with an add button at the end (My feedback, 2026-10-26): the + sits
   beside the tab it adds to, not floating over a list that may be short. */
.me-seg-row { display: flex; align-items: center; gap: 10px; margin-bottom: var(--s-4); }
.me-seg-row .me-seg { flex: 1; min-width: 0; }
.me-add {
  flex: none;
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: var(--me-accent);
  color: var(--me-accent-ink);
  text-decoration: none;
}
.me-add:active { transform: scale(0.96); }
.me-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* A figure on the ground its kind wears (2026-10-08), not a white pane with
   a hairline round it: the border was the desk product's way of saying where
   a pane ends, and on a cream phone ground the fill says it. `.me-tone-*`
   carries the ground, the measured ink and the strong step for the mark. */
.me-kpi {
  min-width: 0;
  padding: var(--s-4);
  border: 0;
  border-radius: 18px;
  /* The tone's ground when it wears one, a plain surface when it does not —
     the Stations tab has a few figures with no kind. A fallback rather than
     an override, because `.me-kpi` sits *below* the tone rules in this sheet
     and a plain `background` here would beat them. */
  background: var(--me-tile-ground, var(--me-surface));
  box-shadow: inset 0 1px 0 var(--me-glass-edge);
}
.me-kpi-mark {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  margin-bottom: var(--s-2);
  border-radius: 9px;
  background: var(--me-tile-strong);
  color: var(--me-tile-ground);
  --me-duo: 0;
}
.me-kpi-label { display: block; font-size: 12px; opacity: .85; }
.me-kpi-value { display: block; margin-top: 4px; font-size: 26px; font-weight: var(--fw-semibold); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.me-kpi-note { display: block; margin-top: 2px; font-size: 12px; opacity: .85; }
/* A name, not a figure (the Stations tab's "last fill", 2026-09-20): a
   station name at 26px wraps twice, so it takes the row's size and wraps. */
.me-kpi-text { font-size: 18px; letter-spacing: -0.01em; line-height: 1.25; }
/* The marks on a station row — your usual, cheapest — on a line of their
   own under the name, so a long name and a long pill never fight. */
.me-stn-marks { display: flex; flex-wrap: wrap; gap: 4px; margin: 2px 0 4px; }
.me-stn-marks .me-pill { white-space: nowrap; }
/* Fuel economy (A2) takes the row: a fifth tile alone in a two-column
   grid reads as a mistake. Amber when the last stretch was thirsty. */
.me-kpi-wide { grid-column: 1 / -1; }
.me-kpi.is-amber { border-color: var(--me-tone-amber-ink); background: var(--me-tone-amber-soft); }
.me-split { display: flex; gap: 2px; height: 14px; border-radius: 7px; overflow: hidden; background: var(--me-surface-2); }
.me-split > span { display: block; height: 100%; }
.me-split .is-accent { background: var(--me-accent); }
.me-split .is-pink { background: var(--me-pink); }
.me-split .is-amber { background: var(--me-amber); }
.me-legend { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; font-size: 14px; }
.me-legend li { display: flex; align-items: center; gap: 10px; }
.me-legend .spacer { flex: 1; }
.me-legend b { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.me-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.me-swatch.is-accent { background: var(--me-accent); }
.me-swatch.is-pink { background: var(--me-pink); }
.me-swatch.is-amber { background: var(--me-amber); }
.me-fills { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.me-fill-line { display: flex; justify-content: space-between; gap: 10px; font-size: 14px; }
.me-fill-line b { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.me-meter { height: 10px; margin-top: 6px; border-radius: 5px; background: var(--me-surface-2); overflow: hidden; }
.me-meter > span { display: block; height: 100%; border-radius: 5px; background: var(--me-accent); }
.me-station { display: flex; align-items: center; gap: 12px; padding: 8px 0; }
.me-station + .me-station { border-top: 1px solid var(--me-line); }
.me-station-body { flex: 1; min-width: 0; }
.me-station-body b { display: block; font-size: 15px; font-weight: var(--fw-semibold); }
.me-station-body span { display: block; font-size: 12px; color: var(--me-ink-3); }
.me-station-share { font-family: var(--me-font-display); font-size: 18px; font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.me-alert-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; }
.me-alert-row + .me-alert-row { border-top: 1px solid var(--me-line); }
.me-alert-body { flex: 1; min-width: 0; }
.me-alert-body b { display: block; font-size: 15px; font-weight: var(--fw-semibold); }
.me-alert-body span { display: block; font-size: 12px; color: var(--me-ink-3); }
.me-alert-body .me-input { margin-top: 8px; }
.me-switch {
  position: relative;
  width: 52px;
  height: 32px;
  flex: none;
  border: 0;
  border-radius: 16px;
  background: var(--me-line-dashed);
  cursor: pointer;
  transition: background .15s;
}
.me-switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--me-knob);
  transition: transform .15s;
}
.me-switch[aria-checked="true"] { background: var(--me-accent); }
.me-switch[aria-checked="true"]::after { transform: translateX(20px); }
@media (prefers-reduced-motion: reduce) {
  .me-switch, .me-switch::after { transition: none; }
}
.me-dashed-card {
  padding: 18px;
  border: 1.5px dashed var(--me-line-dashed);
  border-radius: 18px;
  color: var(--me-ink-3);
  font-size: 14px;
  text-align: center;
}

/* ---- the rewards app's first screens (2026-09-22) ----
   Sign-in was a chip, a paragraph and three identical slabs with half the
   phone empty beneath. The welcome hero carries the programme in the app's
   own colour — the same shape the card screen opens with — so the three
   doors into the app read as one thing. */
.ly-welcome { padding: 22px 20px 20px; }
.ly-welcome-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: var(--me-r);
  /* A wash of the ink, not of white: the hero is a bright fill now, and a
     white wash on gold disappears. */
  background: rgba(58, 36, 0, .14); color: var(--me-accent-ink);
}
.ly-welcome-title {
  font-family: var(--me-font-display); font-size: 26px; font-weight: var(--fw-semibold);
  letter-spacing: -0.02em; line-height: 1.12; margin: 14px 0 0; color: inherit;
}
.ly-welcome-lede { margin: 8px 0 0; font-size: 15px; line-height: 1.45; opacity: .88; }
.ly-welcome-points { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 8px; }
.ly-welcome-points li { display: flex; align-items: center; gap: 8px; font-size: 14px; opacity: .88; }
.ly-welcome-points .ico { flex: none; opacity: .9; }
/* The rare way in: a link under the two real ones, centred, with room to
   tap. A full-width button here gave a forgotten PIN the weight of signing
   in. */
.ly-quiet { margin: 14px 0 0; text-align: center; font-size: 14px; }
.ly-quiet .me-more { display: inline-flex; min-height: 44px; align-items: center; }
/* The card's code: big enough to scan from a counter, small enough that the
   number and the note below it stay on the first screenful. */
.ly-qr svg { width: min(208px, 54vw); }
.ly-card-note { margin-top: 10px; }


/* ═══════════════════════════════════════════════════════ the forecourt

   Home, 2026-10-06. The screen borrows the objects of a fuel station, so
   every figure comes in a shape a driver already reads on a forecourt: the
   balance is a pump counter, the price is the roadside board, a coupon is
   a ticket, and each fill carries its own litre bar so the list is the
   chart. The figures are still services.dashboard's. */

/* The home screen's top band: the greeting, and a frozen card's warning.

   It is a band and not a pane because it cancels `.me-main`'s padding the
   way the front door does, so the header can put the phone's safe area back
   itself and the avatar can start where the tiles below it start.

   Until 2026-10-07 this was `.me-sheet`: a deep green hero that ran to both
   edges of the phone and carried the balance, with the pay button lifted
   across its lower edge. The balance left for tiles on the page's own
   ground, which left the sheet a green stub holding a greeting — so the
   green went too, and with it the lift, the glass pills and the eighteen
   rules that dressed text on a dark ground. */
.me-home-top {
  margin: calc(-1 * var(--s-3)) calc(-1 * var(--me-gutter)) 0;
}
/* The header lays its own gutter; the warning is in the band, so it needs
   the gutter put back. */
.me-home-top .me-alert { margin: var(--s-3) var(--me-gutter) 0; }

/* The price board: the figure on the roadside sign, in an ink cell the
   way the sign's digits sit in a panel, and beside it which site this card
   paid it at. With no price to show, the cell holds the stations glyph. */

/* A section heading on the ground (Insights). */
.me-section-h2 { margin: 0 0 10px; }

/* The last thirty days, at the head of the fills; and the one sentence a
   quiet week gets instead of an empty chart. */
/* Three figures across, each as wide as it is, so a sum in dollars does
   not wrap at a litre figure's width. */
/* A figure on its own tinted ground (2026-10-08). The three were bare
   columns with space between them, which a reader has to separate by
   alignment alone; a ground does it for them.

   `.me-figure` and not `.me-chip`: that name has belonged to the amount
   pills on the code screen since PR 245, and taking it turned those pills
   into squat left-aligned blocks — shipped in PR 259 and caught here. Six
   changes in this sheet have now gone wrong by reusing a name or sitting on
   the wrong side of one; `test_no_two_components_share_a_class_name` is the
   guard. */
.me-month-note { margin: 0 0 var(--s-3); }

/* Each fill's litre bar, against the largest fill listed. */
.me-fillbar { display: block; height: 6px; margin: 6px 0 5px; border-radius: 3px; background: var(--me-accent-tint); overflow: hidden; }
.me-fillbar > span { display: block; height: 100%; border-radius: 3px; background: var(--me-accent); }

/* Coupons as tickets: a plum stub with the amount, a dashed cut line, and
   two notches punched out in the ground's colour. The stub keeps the
   coupon tone the rows had, so a glance still tells a coupon from a code. */
.me-tickets { display: flex; flex-direction: column; gap: var(--s-3); }
.me-ticket { position: relative; display: flex; align-items: stretch; min-height: 84px; }
.me-ticket-stub {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 96px;
  flex: none;
  padding: var(--s-2);
  border-radius: var(--me-r-lg) 0 0 var(--me-r-lg);
  background: var(--me-tone-plum-soft);
  color: var(--me-tone-plum-ink);
  --me-duo: .22;
}
.me-ticket-stub b {
  font-family: var(--me-font-display);
  font-size: var(--fs-18);
  font-weight: var(--fw-bold);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.me-ticket-body {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: 0 var(--me-r-lg) var(--me-r-lg) 0;
  border-left: 2px dashed var(--me-line-strong);
  background: var(--me-surface);
}
.me-ticket::before,
.me-ticket::after {
  content: "";
  position: absolute;
  left: 87px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--me-ground);
}
.me-ticket::before { top: -9px; }
.me-ticket::after { bottom: -9px; }

/* ═══ the wallet card's identity and kind (2026-10-14) ═══════════════════
   Whose card this is, before what is on it. A driver carries one card for
   one vehicle in one fleet, and the two things that identify it to
   everybody else — the fleet's name and the plate — were on no screen the
   driver could reach. They sit above the balance because that is the order
   somebody reads a card held in the hand. */
.me-wallet-id {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
  min-width: 0;
}
/* The fleet's initial on a light tile, the way a card scheme's mark sits on
   a bank card: a shape to recognise before any word is read. */
.me-wallet-crest {
  flex: none;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  background: var(--me-surface);
  color: var(--me-ink);
  font-size: var(--fs-13);
  font-weight: var(--fw-bold);
}
/* The plate wraps to its own line before the fleet's name is cut. At 320px
   both sat on one row and the name — the longer and the more important of
   the two — was the only thing that could shrink, so "Layout Transport"
   read "Layou…" beside a plate with room to spare. */
.me-wallet-who {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--s-2);
  align-items: baseline;
}
.me-wallet-fleet,
.me-wallet-plate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-13);
}
.me-wallet-fleet { font-weight: var(--fw-semibold); }
.me-wallet-who .me-wallet-plate { opacity: .75; }

/* What this wallet buys, in a well of its own: "Diesel 50ppm" and "6,477"
   set on the same ground were read as one line. */
.me-wallet-panel {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
  padding: var(--s-3);
  border-radius: var(--me-r-lg);
  background: rgba(0, 0, 0, .22);
}
.me-wallet-what { flex: 1; min-width: 0; display: grid; }
.me-wallet-product {
  font-weight: var(--fw-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.me-wallet-type { font-size: var(--fs-12); opacity: .72; }
.me-wallet-state.is-off { opacity: .9; }

/* ═══ this week against the ceiling (2026-10-14) ════════════════════════ */
/* The card itself takes `.me-card`'s surface; this only sets the rhythm
   inside it, so the figures and the meter are not two unrelated blocks. */
.me-week { display: grid; gap: var(--s-1); }
.me-week-figures {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-3);
  margin-bottom: var(--s-4);
}
.me-week-figures > div { display: grid; gap: 2px; min-width: 0; }
.me-week-figures .me-stat-value {
  font-family: var(--me-font-display);
  font-size: var(--fs-20);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
}
.me-week-figures .me-stat-label { font-size: var(--fs-12); color: var(--me-ink-3); }

/* The track is the allowance and the fill is what is gone. `.me-meter` is
   already a component — the loyalty page's progress track — so this adds
   only the one variant it did not have: a card at or over its ceiling shows
   a full track in the refusal colour, never one that runs past its own end. */
.me-meter > span.is-full { background: var(--me-bad); }
.me-week-foot {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-2);
  color: var(--me-ink-3);
  font-size: var(--fs-12);
}
.me-week-foot .spacer { flex: 1; }

/* ═══ recent activity (2026-10-14) ══════════════════════════════════════
   Four columns: when, where, how much, and whether it worked. The outcome
   is a word as well as a colour — a refused fill read as red alone is a
   refused fill nobody colour-blind can read. */
.me-activity .me-row { align-items: flex-start; gap: var(--s-3); }
.me-act-figure {
  flex: none;
  display: grid;
  justify-items: end;
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
}
.me-act-figure small { font-size: var(--fs-12); font-weight: var(--fw-regular); opacity: .75; }
.me-outcome {
  flex: none;
  display: grid;
  justify-items: end;
  min-width: 5.5em;
  color: var(--me-ok);
  font-size: var(--fs-12);
  font-weight: var(--fw-semibold);
}
.me-outcome.is-no { color: var(--me-bad); }
.me-outcome small { font-weight: var(--fw-regular); opacity: .8; text-align: right; }

/* The chevron on a tile that goes somewhere. `.me-fact` is positioned at
   its own rule above; this only places the mark. */
.me-fact-chev { position: absolute; top: var(--s-3); right: var(--s-3); opacity: .55; }

/* ──────────────────────────────────────────────────────────────── feedback */
/* docs/DRIVER-FEEDBACK.md. Stars are five radios, written 5→1 and laid out
   reversed, so "this one and every one before it" is `:checked ~ label`. */
.me-stars { border: 0; padding: 0; margin: 0; min-width: 0; }
.me-stars-row { display: flex; flex-direction: row-reverse; justify-content: flex-end; gap: var(--s-1); }
.me-stars-row input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.me-stars-row label { color: var(--me-line-strong); cursor: pointer; padding: 4px; border-radius: 8px; --me-duo: .15; }
.me-stars-row input:checked ~ label,
.me-stars-row label:hover,
.me-stars-row label:hover ~ label { color: var(--me-warn); --me-duo: .9; }
.me-stars-row input:focus-visible + label { outline: 2px solid var(--me-accent); outline-offset: 2px; }
.me-textarea { min-height: 7rem; resize: vertical; font: inherit; line-height: 1.45; }
.me-fb-facts { display: grid; grid-template-columns: max-content 1fr; gap: 6px var(--s-3); margin: 0; }
.me-fb-facts > div { display: contents; }
.me-fb-facts dt { color: var(--me-ink-3); }
.me-fb-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.me-fb-body { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }
.me-fb-photos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-2); }
.me-fb-photos img { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; border-radius: 10px; background: var(--me-sunk); }
.me-fb-thread { list-style: none; margin: 0; padding: 0 var(--s-4) var(--s-4); display: grid; gap: var(--s-3); }
.me-fb-msg { display: grid; gap: 6px; padding: var(--s-3); border-radius: 12px; background: var(--me-sunk); }
.me-fb-msg.is-staff { background: var(--me-accent-soft); }
.me-fb-msg.is-system { background: none; padding: 0 var(--s-3); }
.me-fb-msg .me-note { margin: 0; }
.me-fb-who { margin: 0; font-weight: 600; }
