/*
 * The customer app's components, matched to the Solarex rider prototype.
 * Class names are the whole API — there is no build step and no utility
 * framework, so a screen is composed from these rather than from utilities in
 * the ERB.
 */

/* ---- Hero -------------------------------------------------------------
   The navy block at the top of home and rewards. The blurred gradient is a
   single positioned div rather than a background image, so it costs nothing to
   download and tints itself from the palette. */

.hero {
  position: relative;
  overflow: hidden;
  background: var(--navy-900);
  padding: calc(var(--space-9) + env(safe-area-inset-top)) var(--space-5) var(--space-6);
}

.hero::before {
  content: "";
  position: absolute;
  inset: -40% -30% auto auto;
  width: 320px;
  height: 320px;
  background: var(--gradient-vice);
  filter: blur(60px);
  opacity: 0.5;
}

.hero__inner {
  position: relative;
}

.hero__wordmark {
  font-size: var(--text-body);
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: #fff;
  opacity: 0.95;
}

.hero__note {
  margin-top: var(--space-2);
  font-size: var(--text-body-sm);
  color: var(--gray-300);
}

.hero__greeting {
  margin-top: var(--space-5);
  font-size: 26px;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  font-weight: var(--fw-bold);
  color: #fff;
}

.hero__tiles {
  margin-top: 18px;
  display: flex;
  gap: 10px;
}

.tile {
  flex: 1;
  background: rgb(255 255 255 / 8%);
  border: 1px solid var(--border-dark);
  border-radius: var(--radius-md);
  padding: 11px 13px;
  text-decoration: none;
}

.tile:hover {
  text-decoration: none;
  background: rgb(255 255 255 / 12%);
}

/* flex, because base.css makes every svg display:block — without this the
   glyph takes a line of its own above the word. */
.tile__label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: var(--text-overline);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--gray-300);
}

.tile__value {
  font-size: var(--text-h4);
  font-weight: var(--fw-bold);
  color: #fff;
  margin-top: 3px;
}

.tile__value--accent { color: var(--teal-300); }

/* ---- Cards ------------------------------------------------------------ */

.card {
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
  background: var(--surface-card);
}

.card__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
}

.card__title {
  font-size: var(--text-h4);
  font-weight: var(--fw-bold);
  margin-top: 6px;
}

.card__meta {
  font-size: var(--text-body-sm);
  color: var(--gray-500);
}

.card__status {
  font-size: var(--text-caption);
  font-weight: var(--fw-bold);
  color: var(--teal-600);
}

.card__status--off { color: var(--gray-400); }

/* The card is the way to the station, so the whole of it is the tap target.
   Same treatment as .session--link further down. */
.card--link {
  display: block;
  text-decoration: none;
  color: var(--text-primary);
}

.card--link:hover {
  border-color: var(--teal-400);
  color: var(--text-primary);
  text-decoration: none;
}

/* Spans rather than paragraphs inside the link, so they need the block back. */
.card--link :is(.card__title, .card__meta) { display: block; }

/* The arrow that says the tap leaves for a map app. */
.card__go { flex: none; color: var(--teal-500); }

/* ---- Action cards -----------------------------------------------------
   The tappable rows on home: icon, label, chevron. Three tones — the primary
   action, an accent, and one that is not available yet. */

.action {
  display: flex;
  gap: 14px;
  align-items: center;
  border-radius: var(--radius-lg);
  padding: 18px;
  border: 1px solid var(--border-default);
  text-decoration: none;
  color: var(--text-primary);
}

.action:hover { text-decoration: none; }

.action__icon {
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.action__body { flex: 1; }

/* Spans rather than divs, so that an <a> wrapping the whole card stays valid —
   which means they have to be blockified by hand to stack. */
.action__label {
  display: block;
  font-size: var(--text-body-lg);
  font-weight: var(--fw-bold);
}

.action__sub {
  display: block;
  font-size: var(--text-body-sm);
  margin-top: 2px;
}

.action--primary {
  padding: var(--space-5);
  border-color: transparent;
  background: var(--teal-500);
  box-shadow: var(--shadow-glow-teal), var(--shadow-md);
}

.action--primary,
.action--primary:hover { color: #fff; }

.action--primary .action__icon { background: rgb(255 255 255 / 18%); }
.action--primary .action__sub { color: rgb(255 255 255 / 85%); }

.action--accent {
  border-color: var(--pink-100);
  background: var(--pink-50);
}

.action--accent .action__icon { background: var(--pink-400); }
.action--accent .action__sub { color: var(--pink-600); }

.action--accent .action__chevron { color: var(--pink-500); }

.action--muted { background: var(--surface-sunken); }

.action--muted .action__icon { background: var(--gray-200); }
.action--muted .action__label { color: var(--gray-500); }
.action--muted .action__sub { color: var(--gray-400); }

/* The chevron follows the card rather than the label — on the accent card the
   label is near-black while the chevron is pink. */
.action__chevron { flex: none; color: var(--gray-300); }
.action--primary .action__chevron { color: rgb(255 255 255 / 90%); }

/* The label sits beside its badge, so the two share a row of their own. */
.action__label-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--gray-200);
  color: var(--gray-600);
  font-size: var(--text-overline);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  vertical-align: middle;
}

/* ---- Balance panel ---------------------------------------------------- */

.balance {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  background: var(--gradient-dusk);
}

.balance::before {
  content: "";
  position: absolute;
  inset: auto -20% -60% auto;
  width: 220px;
  height: 220px;
  background: var(--gradient-vice);
  filter: blur(44px);
  opacity: 0.5;
}

.balance__inner { position: relative; }

.balance__label,
.balance__note {
  font-size: var(--text-caption);
  color: var(--gray-300);
}

.balance__note { margin-top: 6px; }

.balance__amount {
  font-size: 40px;
  font-weight: var(--fw-extrabold);
  color: #fff;
  margin-top: 6px;
  letter-spacing: var(--tracking-tight);
}

/* ---- Buttons ---------------------------------------------------------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 52px;
  padding: 14px var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--teal-500);
  color: #fff;
  font-size: var(--text-body);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--shadow-glow-teal);
  transition: background-color var(--duration-fast) var(--ease-standard);
}

.button:hover {
  background: var(--action-primary-hover);
  color: #fff;
  text-decoration: none;
}

.button--accent { background: var(--pink-400); box-shadow: var(--shadow-glow-pink); }
.button--accent:hover { background: var(--action-accent-hover); }

.button--quiet {
  background: transparent;
  border-color: var(--border-default);
  color: var(--gray-900);
  box-shadow: none;
}

.button--quiet:hover { background: var(--gray-50); color: var(--gray-900); }

.button[disabled],
.button[disabled]:hover {
  background: var(--action-disabled);
  color: var(--action-disabled-text);
  box-shadow: none;
  cursor: not-allowed;
}

.button--dashed {
  background: transparent;
  border: 1px dashed var(--border-strong);
  color: var(--gray-600);
  font-size: var(--text-body-sm);
  box-shadow: none;
}

.button--danger {
  background: transparent;
  border-color: var(--border-default);
  color: var(--semantic-danger);
  box-shadow: none;
}

/* button_to wraps its button in a form, which would not stretch otherwise. */
.button-to { display: block; width: 100%; }

.back-link {
  display: inline-block;
  color: var(--gray-500);
  font-size: var(--text-body-sm);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}

.back-link:hover { color: var(--gray-900); text-decoration: none; }

/* ---- Forms ------------------------------------------------------------ */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.field__label {
  font-size: var(--text-body-sm);
  font-weight: var(--fw-semibold);
}

.field__input {
  width: 100%;
  padding: 13px var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
}

.field__input:focus { border-color: var(--teal-400); }

.field__hint {
  font-size: var(--text-caption);
  color: var(--gray-500);
}

.presets {
  display: flex;
  gap: var(--space-2);
}

.presets__item {
  flex: 1;
  text-align: center;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: 14px 0;
  font-size: var(--text-body);
  font-weight: var(--fw-bold);
  color: var(--gray-900);
  text-decoration: none;
}

.presets__item:hover {
  border-color: var(--teal-400);
  color: var(--gray-900);
  text-decoration: none;
}

/* A stripe, not a fill. ₱500's yellow cannot carry white text, so a filled row
   would have to flip the text colour on one chip and only that chip; a band
   along the top keeps every amount at the same contrast. */
.presets__item {
  border-top-width: 3px;
  border-top-color: var(--border-default);
}

.presets__item--note-20 { border-top-color: var(--note-20); }
.presets__item--note-50 { border-top-color: var(--note-50); }
.presets__item--note-100 { border-top-color: var(--note-100); }
.presets__item--note-200 { border-top-color: var(--note-200); }
.presets__item--note-500 { border-top-color: var(--note-500); }
.presets__item--note-1000 { border-top-color: var(--note-1000); }

/* kWh has no banknote to borrow, so the ramp carries it: deeper teal, more
   energy. Same silhouette as the peso row, so the two modes read as siblings. */
.presets__item--energy-0 { border-top-color: var(--teal-200); }
.presets__item--energy-1 { border-top-color: var(--teal-400); }
.presets__item--energy-2 { border-top-color: var(--teal-600); }

/* ---- Chips ------------------------------------------------------------
   A glyph and a word, for the small facts that hang off a heading: what the
   energy costs, what plug a bay has, what is left in the wallet. */

.chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-body-sm);
  color: var(--gray-500);
}

.chip svg { flex: none; }

.chip--strong { color: var(--gray-900); font-weight: var(--fw-semibold); }
.chip--brand { color: var(--teal-600); }

/* On the navy screens the muted grey disappears. */
.screen--dark .chip { color: var(--gray-300); }
.screen--dark .chip--strong { color: #fff; }

/* ---- Rows -------------------------------------------------------------
   The ledger on the wallet screen and the settings list on You. Same shape:
   label left, value right, hairline between. */

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

.rows__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
  padding: 14px 0;
  border-bottom: 1px solid var(--border-default);
  text-decoration: none;
  color: var(--text-primary);
}

a.rows__row:hover { color: var(--text-primary); text-decoration: none; }

.rows__label { font-size: var(--text-body); }

.rows__value {
  font-size: var(--text-body-sm);
  color: var(--gray-400);
  text-align: right;
  overflow-wrap: anywhere;
}

.rows__title {
  font-size: var(--text-body-sm);
  font-weight: var(--fw-semibold);
}

.rows__date {
  font-size: var(--text-caption);
  color: var(--gray-500);
  margin-top: 2px;
}

.rows__amount {
  font-size: var(--text-body-sm);
  font-weight: var(--fw-bold);
  white-space: nowrap;
}

.rows__amount--credit { color: var(--teal-600); }
.rows__amount--debit { color: var(--gray-900); }

/* No money moved. Neither ledger colour will do — both of them mean a real
   movement, and this row exists to say there wasn't one. */
.rows__amount--none { color: var(--gray-400); font-weight: var(--fw-regular); }

/* ---- Session cards (Activity) ----------------------------------------- */

.session {
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
}

.session__head,
.session__foot {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
}

.session__head { align-items: center; }

.session__station {
  font-size: var(--text-body);
  font-weight: var(--fw-semibold);
}

.session__total {
  font-size: var(--text-body);
  font-weight: var(--fw-bold);
  color: var(--teal-600);
  white-space: nowrap;
}

.session__foot {
  margin-top: 6px;
  font-size: var(--text-caption);
  color: var(--gray-500);
}

/* The home card is an <a>, so its parts are spans — display:block is what
   makes them stack and what gives the meter a height to fill. */
.session--link {
  display: block;
  text-decoration: none;
  color: var(--text-primary);
}

.session--link:hover {
  border-color: var(--teal-400);
  color: var(--text-primary);
  text-decoration: none;
}

.session--link .session__station { display: block; margin-top: 2px; }

.session__total { display: inline-flex; align-items: center; gap: 2px; }

/* Progress on a session that is still running. */
.session__meter {
  display: block;
  height: 6px;
  margin-top: var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--gray-100);
  overflow: hidden;
}

.session__meter-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--teal-500);
}

/* ---- Profile card ----------------------------------------------------- */

.identity {
  display: flex;
  gap: 14px;
  align-items: center;
}

.identity__avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--gradient-vice);
  flex: none;
}

.identity__body { flex: 1; min-width: 0; }

.identity__name {
  display: block;
  font-size: var(--text-body-lg);
  font-weight: var(--fw-bold);
}

.identity__sub {
  display: block;
  font-size: var(--text-body-sm);
  color: var(--gray-500);
  margin-top: 2px;
  overflow-wrap: anywhere;
}

/* ---- Callout ---------------------------------------------------------- */

.callout {
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  background: var(--semantic-warning-bg);
  border: 1px solid color-mix(in oklab, var(--semantic-warning) 35%, transparent);
}

.callout--done {
  background: var(--semantic-success-bg);
  border-color: color-mix(in oklab, var(--semantic-success) 35%, transparent);
}

.callout__title {
  font-weight: var(--fw-bold);
  font-size: var(--text-body);
}

.callout__body {
  font-size: var(--text-body-sm);
  color: var(--gray-600);
  margin-top: 2px;
}

/* ---- Empty state ------------------------------------------------------ */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-9) var(--space-4);
  text-align: center;
}

.empty-state__mark {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-pill);
  background: var(--teal-50);
  color: var(--teal-600);
}

.empty-state__body {
  max-width: 22rem;
  font-size: var(--text-body-sm);
  color: var(--gray-500);
}

/* ---- Flash ------------------------------------------------------------ */

.flash {
  max-width: var(--screen-max-width);
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-body-sm);
  font-weight: var(--fw-semibold);
}

.flash--notice { background: var(--semantic-success-bg); color: var(--teal-700); }
.flash--alert { background: var(--semantic-danger-bg); color: var(--semantic-danger); }

/* ---- Tab bar ---------------------------------------------------------- */

.tab-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 10;
  background: rgb(255 255 255 / 92%);
  backdrop-filter: blur(18px);
  border-top: 1px solid var(--border-default);
}

.tab-bar__items {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  max-width: var(--screen-max-width);
  margin-inline: auto;
  padding: var(--space-2) var(--space-2);
  padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
}

.tab-bar__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: 6px 0;
  color: var(--gray-300);
  text-decoration: none;
  font-size: 10.5px;
  font-weight: var(--fw-semibold);
}

.tab-bar__link:hover { text-decoration: none; color: var(--gray-500); }

/* The accessible current-page state and the visual one are one declaration, so
   they cannot drift apart. */
.tab-bar__link[aria-current="page"] { color: var(--teal-500); }

/* ---- QR --------------------------------------------------------------- */

/* QrCodesHelper emits this class with a black-on-transparent SVG. The plate
   keeps it scannable whatever sits behind it. */
.qr {
  margin-inline: auto;
  padding: var(--space-3);
  background: #fff;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

code { font-family: var(--font-mono); font-size: var(--text-body-sm); }

/* ---- Top bar ----------------------------------------------------------
   The operator console and the pages that answer on every host — sign-in,
   password reset, the signed-out front door. The customer app's screens draw
   their own headers instead. */

.topbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  padding-top: calc(var(--space-3) + env(safe-area-inset-top));
  border-bottom: 1px solid var(--border-default);
}

.topbar__brand {
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--text-primary);
  text-decoration: none;
  margin-right: auto;
}

.topbar__brand:hover { color: var(--text-primary); text-decoration: none; }

.topbar .button { width: auto; }

/* ---- Dark screens -----------------------------------------------------
   The live session and the trip teaser are full navy rather than a hero over
   white, so they get their own shell. */

.screen--dark {
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  background: var(--navy-900);
  color: #fff;
  display: flex;
  flex-direction: column;
  padding: calc(var(--space-6) + env(safe-area-inset-top)) var(--space-5) var(--space-6);
}

.screen--dark::before {
  content: "";
  position: absolute;
  inset: auto -25% -35% -25%;
  height: 340px;
  background: var(--gradient-vice);
  filter: blur(70px);
  opacity: 0.28;
}

.screen--dark > * { position: relative; }

.screen--dark .back-link { color: var(--gray-300); }
.screen--dark .back-link:hover { color: #fff; }

.screen--dark .rows__row { border-bottom-color: var(--border-dark); }
.screen--dark .rows__label { color: var(--gray-300); }
.screen--dark .rows__value { color: #fff; }

/* Fields are drawn for a white page too. On navy a white input is a floodlight,
   and its text would be invisible if it inherited the screen's colour. */
.screen--dark .field__input {
  background: rgb(255 255 255 / 6%);
  border-color: var(--border-dark);
  color: #fff;
}

.screen--dark .field__input::placeholder { color: var(--gray-400); }
.screen--dark .field__input:focus { border-color: var(--teal-400); }
.screen--dark .field__hint { color: var(--gray-400); }
.screen--dark .field__label { color: #fff; }

/* The quiet button is drawn for a white page; on navy it needs the light end
   of the ramp or it disappears into the background. */
.screen--dark .button--quiet {
  border-color: var(--border-dark);
  color: #fff;
}

.screen--dark .button--quiet:hover {
  background: rgb(255 255 255 / 8%);
  color: #fff;
}

.screen--dark .card {
  background: rgb(255 255 255 / 6%);
  border-color: var(--border-dark);
  box-shadow: none;
}

/* ---- Live session ----------------------------------------------------- */

.live {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
}

.live__what {
  font-size: var(--text-overline);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--teal-300);
  font-weight: var(--fw-bold);
}

.live__where {
  font-size: var(--text-body-sm);
  color: var(--gray-300);
  margin-top: 2px;
}

.live__badge {
  display: flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--border-dark);
  border-radius: var(--radius-pill);
  padding: 6px 12px;
  font-size: var(--text-caption);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

.live__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--teal-300);
  animation: sx-pulse 1.3s ease-in-out infinite;
}

@keyframes sx-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

@media (prefers-reduced-motion: reduce) {
  .live__dot { animation: none; }
}

.ring {
  position: relative;
  width: 232px;
  height: 232px;
  margin-inline: auto;
}

.ring__svg { transform: rotate(-90deg); }

.ring__track { stroke: rgb(255 255 255 / 10%); }

.ring__fill {
  stroke: var(--teal-300);
  transition: stroke-dashoffset 320ms var(--ease-standard);
}

.ring__center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.ring__value {
  font-size: 52px;
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
}

.ring__unit {
  font-size: var(--text-body-sm);
  color: var(--gray-300);
  margin-top: var(--space-2);
}

/* ---- Segmented control ----------------------------------------------
   Pesos or kWh. Links rather than a control, so switching costs no script;
   the active option is a raised white pill on a sunken track. */

.segmented {
  display: flex;
  background: var(--gray-100);
  border-radius: var(--radius-pill);
  padding: 4px;
}

.segmented__option {
  flex: 1;
  text-align: center;
  padding: 9px 0;
  border-radius: var(--radius-pill);
  font-size: var(--text-body-sm);
  font-weight: var(--fw-semibold);
  color: var(--gray-500);
  text-decoration: none;
}

.segmented__option:hover { text-decoration: none; }

.segmented__option[aria-current="page"] {
  background: var(--white);
  color: var(--gray-900);
  box-shadow: var(--shadow-sm);
}

/* ---- Amount entry -----------------------------------------------------
   The screen is a column with the commit button at the foot, so the pad sits
   under the thumb however tall the phone is. */

.charge {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-height: 100dvh;
}

.charge__foot {
  margin-top: auto;
  padding-top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Only one mode's fields and presets are on screen at a time. The class is
   server-rendered and swapped by the controller, so this works either way. */
.numpad-mode-amount .mode--energy,
.numpad-mode-energy .mode--amount { display: none; }

/* The display and the pad replace the plain fields, and only once the
   controller is live — otherwise a no-JS visitor gets a dead grid and no way
   to enter anything. */
.entry,
.numpad { display: none; }

.numpad-ready .entry { display: block; }
.numpad-ready .numpad { display: grid; }
.numpad-ready .entry__fields { display: none; }

.entry { text-align: center; }

.entry__display {
  font-size: 44px;
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: 1.1;
  color: var(--gray-900);
}

/* Two lines are reserved because the hint wraps to two on a narrow phone once
   it is saying something like "₱1,000.00 short · Add money". Without the room
   held open, the column reflows and the keypad moves out from under the thumb
   between one tap and the next. */
.entry__hint {
  margin-top: 4px;
  font-size: var(--text-body-sm);
  color: var(--gray-500);
  min-height: 2.8em;
}

.numpad {
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
}

.numpad__key {
  height: 52px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--gray-50);
  font-size: var(--text-h3);
  font-weight: var(--fw-semibold);
  color: var(--gray-900);
  cursor: pointer;
}

.numpad__key:active { background: var(--gray-200); }

/* ---- Trip teaser ------------------------------------------------------ */

.trip__art {
  height: 150px;
  border-radius: var(--radius-lg);
  background: var(--gradient-vice);
  opacity: 0.9;
  display: flex;
  align-items: flex-end;
  padding: var(--space-4);
}

.trip__art span {
  font-size: var(--text-overline);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: rgb(255 255 255 / 90%);
  font-weight: var(--fw-bold);
}

.trip__headline {
  margin-top: var(--space-3);
  font-size: 28px;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  font-weight: var(--fw-bold);
}

.pill--accent { background: var(--pink-400); color: #fff; }

/* ---- Scanner ----------------------------------------------------------
   The bay code viewport, drawn to the prototype's scan screen. The camera feed
   sits under the brackets; with no camera the frame stays dark and the bay list
   below is the way through, so nothing here is load-bearing. */

.scan__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
}

/* ---- Paying ----------------------------------------------------------
   One rail today. The row is drawn as a chosen option rather than a statement
   because the cashless rails join it later, and a group of one that becomes a
   group of three should not change shape when it does. */

.pay-option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  background: var(--surface-card);
}

.pay-option--on {
  border-color: var(--teal-500);
  background: var(--teal-50);
}

.pay-option__body { flex: 1; }

.pay-option__label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--text-body);
  font-weight: var(--fw-semibold);
  color: var(--gray-900);
}

.pay-option__sub {
  display: block;
  font-size: var(--text-caption);
  color: var(--gray-500);
  margin-top: 2px;
}

.pay-option__dot {
  width: 20px;
  height: 20px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
}

.pay-option--on .pay-option__dot {
  border-color: var(--teal-500);
  background: radial-gradient(circle, var(--teal-500) 0 5px, var(--white) 5px);
}

.pay__total {
  font-size: var(--text-h2);
  font-weight: var(--fw-bold);
  color: var(--teal-600);
}

.scanner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-7) 0;
}

.scanner__viewport {
  position: relative;
  width: 236px;
  height: 236px;
  border-radius: 26px;
  overflow: hidden;
  background: linear-gradient(150deg, #1b2430, #0e141c 60%, #182233);
}

.scanner__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--duration-slow, 360ms) var(--ease-standard);
}

.scanner--live .scanner__video { opacity: 1; }

/* Only ever read from, never shown. */
.scanner__canvas { display: none; }

/* Something to look at while the camera wakes up, and what stays if it never
   does. Tinted rather than white so an empty viewport still looks deliberate. */
.scanner__glyph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: color-mix(in srgb, var(--teal-300) 22%, transparent);
  transition: opacity var(--duration-slow, 360ms) var(--ease-standard);
}

.scanner__glyph svg {
  width: 72px;
  height: 72px;
}

/* The feed fades in as the glyph fades out, so neither ever fights the other. */
.scanner--live .scanner__glyph { opacity: 0; }

.scanner__corner {
  position: absolute;
  width: 30px;
  height: 30px;
  border: 0 solid var(--teal-300);
}

.scanner__corner--tl {
  left: 26px; top: 26px;
  border-top-width: 3px; border-left-width: 3px;
  border-radius: 8px 0 0 0;
}

.scanner__corner--tr {
  right: 26px; top: 26px;
  border-top-width: 3px; border-right-width: 3px;
  border-radius: 0 8px 0 0;
}

.scanner__corner--bl {
  left: 26px; bottom: 26px;
  border-bottom-width: 3px; border-left-width: 3px;
  border-radius: 0 0 0 8px;
}

.scanner__corner--br {
  right: 26px; bottom: 26px;
  border-bottom-width: 3px; border-right-width: 3px;
  border-radius: 0 0 8px 0;
}

.scanner__line {
  position: absolute;
  left: 32px;
  right: 32px;
  top: 26px;
  height: 2px;
  background: var(--teal-300);
  box-shadow: 0 0 14px var(--teal-300);
  animation: sx-scan 2.2s var(--ease-standard) infinite alternate;
}

/* Nothing is being read, so nothing should look like it is. */
.scanner--off .scanner__line { display: none; }

@keyframes sx-scan {
  from { transform: translateY(0); }
  to { transform: translateY(184px); }
}

@media (prefers-reduced-motion: reduce) {
  .scanner__line { animation: none; }
}

.scanner__status {
  font-size: var(--text-body-sm);
  color: var(--gray-300);
  text-align: center;
  max-width: 22rem;
}

.scan__fallback { margin-top: auto; }


/* ---- Settled session --------------------------------------------------
   What the ring becomes once there is no progress left to draw. The figure is
   the money actually taken, not the energy: a receipt answers "what did this
   cost me" first, and the kWh is the reason for the number. */

.settled { text-align: center; }

.settled__amount {
  font-size: 52px;
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: 1;
}

.settled__unit {
  font-size: var(--text-body-sm);
  color: var(--gray-300);
  margin-top: var(--space-2);
}

/* Teal-300 rather than the ledger's --teal-600, which is drawn for a white
   background and disappears on navy. */
.settled__returned {
  font-size: var(--text-body-sm);
  color: var(--teal-300);
  margin-top: var(--space-3);
}
