/* ==========================================================================
   Liwan on a phone

   Sits on top of app.css, which holds the palette — every colour here is a
   token from it, so the phone and the desk cannot drift apart.

   The whole screen is designed around one fact: the person holding it is
   standing up, often with one hand full. Nothing is under 48px, there is one
   column, the two decisions on a card are the two widest things on it, and the
   room number is the biggest text on the screen because that is what somebody
   is looking for as they walk down a corridor.
   ========================================================================== */

html, body.phone {
  height: 100%;
  overscroll-behavior-y: contain;
}

/*
  The phone's own palette, set on `body.phone` so every rule below — and every
  rule inherited from app.css — picks it up without being rewritten, and the
  desk is untouched.

  Why it differs at all: the deep petrol band is right on a wide screen, where
  it is a thin strip over a broad page. On a phone the same colour becomes a
  large flat block held at arm's length, and everything under it reads as
  washed out. So the brand stays exactly the brand — but as the accent on
  controls, not as the ground. The ground is a cool near-white, cards are
  white with a hairline rather than a shadow, and the loudest thing on any
  screen is the room number.
*/
body.phone {
  --bg: #f7f8fa;
  --surface: #ffffff;
  --surface-2: #f1f4f6;
  --border: #e6eaee;
  --border-strong: #cfd8dd;
  --text: #10201e;
  /* Darker than the desk's grey by a shade: at 4.38:1 on white it was the
     one thing on the screen that failed to be legible, and what it carries
     is the line under a room number. */
  --text-muted: #626f78;
  --text-soft: #7e8c94;
  --radius: 12px;
  --radius-lg: 14px;
  --shadow-sm: none;

  /* The chips that carry urgency. Warmer and darker than the desk's washes,
     because they are read in a corridor rather than on a monitor. */
  --now-bg: #fff1e7;
  --now-ink: #9a3412;
  --ready-bg: #e8f6ec;
  --ready-ink: #166534;

  /* The ink that goes on a state's wash. One per wash, so nothing is
     written as a hex that cannot follow the theme into the dark. */
  --warn-ink: #78350f;
  --free-ink: #15803d;
  --arriving-ink: #92400e;
  --maintenance-ink: #4c1d95;
  /* What is legible ON the brand. It is a dark teal by day and a light one
     at night, so white is right for exactly one of the two. */
  --on-brand: #ffffff;

  /* The card that leads a screen — the month's takings, tonight's occupancy.
     It was `--text`, which is near-black by day and near-white at night: at
     night the card inverted into a white slab on a dark page, which is the
     one thing the dark palette exists to prevent. */
  --lead: #10201e;
  --on-lead: #ffffff;

  margin: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  -webkit-tap-highlight-color: transparent;
}

/*
  Night. People work these screens in a corridor at eleven at night, and a
  white page at full brightness is the reason somebody turns the phone face
  down. Same layout, same accent, different ground — nothing below this line
  needs to know.
*/
/*
  Night.

  Three ways to get here: the phone says dark and nothing overrides it, or the
  person chose dark outright. `data-theme` is written on <html> from what they
  chose, so "always light" wins over a phone set to dark — which is the whole
  point of offering the choice.

  The declarations below are duplicated on purpose: CSS cannot give one block
  two selectors across a media query boundary. `mobile.tests` asserts the two
  copies are identical, because the way hand-copied CSS fails is that somebody
  fixes a colour in one of them.
*/
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) body.phone {
    --bg: #0e1417;
    --surface: #17201f;
    --surface-2: #1f2a29;
    --border: #232e2d;
    --border-strong: #33403f;
    --text: #e7eeec;
    --text-muted: #8b9c99;
    --text-soft: #7d8f8b;
    --brand: #14b8a6;
    --brand-dark: #0d9488;
    --brand-light: #123834;
    --brand-soft: #101f1d;
    --on-brand: #06201d;
    /* Raised above the page rather than inverted against it. */
    --lead: #1d2a29;
    --on-lead: #e7eeec;
    --now-bg: #3a2110;
    --now-ink: #fdba74;
    --ready-bg: #10301c;
    --ready-ink: #86efac;
    --danger: #f87171;

    /*
      The washes a room tile is painted with.

      They come from the desk's palette, where they are pale tints meant to sit
      under dark text — and at night the text turns light while the tint stays
      pale, so sixty-five room numbers become almost invisible on their own
      tiles. Same hues, turned down until light text sits on them.

      The saturated bar under each tile is untouched: it is the state's real
      signal, and it should be exactly as loud at midnight as at noon.
    */
    --free-bg: #12301f;
    --busy-bg: #3a1418;
    --arriving-bg: #38280e;
    --cleaning-bg: #102439;
    --maintenance-bg: #251a3a;
    --renovation-bg: #351226;
    --owner-bg: #32240f;
    --other-bg: #2a2724;
    --blocked-bg: #222a33;

    /* The ink that goes on those washes. Written out as hexes before,
       which meant a dark brown on a dark amber at 1.6:1 — a line nobody
       could read at night, and the line was "this phone is blocking
       notifications". */
    --warn-ink: #fcd34d;
    --free-ink: #86efac;
    --arriving-ink: #fdba74;
    --maintenance-ink: #c4b5fd;

    --danger-bg: #2e1214;
    --warn-bg: #32270e;
    --ok-bg: #12301f;
    --info-bg: #102439;
  }
}

html[data-theme="dark"] body.phone {
    --bg: #0e1417;
    --surface: #17201f;
    --surface-2: #1f2a29;
    --border: #232e2d;
    --border-strong: #33403f;
    --text: #e7eeec;
    --text-muted: #8b9c99;
    --text-soft: #7d8f8b;
    --brand: #14b8a6;
    --brand-dark: #0d9488;
    --brand-light: #123834;
    --brand-soft: #101f1d;
    --on-brand: #06201d;
    /* Raised above the page rather than inverted against it. */
    --lead: #1d2a29;
    --on-lead: #e7eeec;
    --now-bg: #3a2110;
    --now-ink: #fdba74;
    --ready-bg: #10301c;
    --ready-ink: #86efac;
    --danger: #f87171;

    /*
      The washes a room tile is painted with.

      They come from the desk's palette, where they are pale tints meant to sit
      under dark text — and at night the text turns light while the tint stays
      pale, so sixty-five room numbers become almost invisible on their own
      tiles. Same hues, turned down until light text sits on them.

      The saturated bar under each tile is untouched: it is the state's real
      signal, and it should be exactly as loud at midnight as at noon.
    */
    --free-bg: #12301f;
    --busy-bg: #3a1418;
    --arriving-bg: #38280e;
    --cleaning-bg: #102439;
    --maintenance-bg: #251a3a;
    --renovation-bg: #351226;
    --owner-bg: #32240f;
    --other-bg: #2a2724;
    --blocked-bg: #222a33;

    /* The ink that goes on those washes. Written out as hexes before,
       which meant a dark brown on a dark amber at 1.6:1 — a line nobody
       could read at night, and the line was "this phone is blocking
       notifications". */
    --warn-ink: #fcd34d;
    --free-ink: #86efac;
    --arriving-ink: #fdba74;
    --maintenance-ink: #c4b5fd;

    --danger-bg: #2e1214;
    --warn-bg: #32270e;
    --ok-bg: #12301f;
    --info-bg: #102439;
  }

/* --- the row at the top --------------------------------------------------
   One row and 64px. It was three bands and 210px — a quarter of a 375px
   screen spent before the first thing anybody had to do. What is on it is
   what a person glances at; the language and the way out are things somebody
   touches twice a year, and they live on the account screen now.
   -------------------------------------------------------------------------- */
.phone__top {
  background: var(--surface);
  border-block-end: 1px solid var(--border);
  padding: calc(env(safe-area-inset-top, 0px) + 11px) 16px 11px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
}

/* The person's initial, which is also the door to their account. A letter
   rather than an icon: it is theirs, and it tells a shared phone apart from
   a wrong sign-in at a glance. */
.phone__me {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--brand);
  color: var(--on-brand);
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-transform: uppercase;
}
.phone__me:active { transform: translateY(1px); }

.phone__who {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.phone__name {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.phone__where {
  font-size: 11.5px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The building, for somebody who covers more than one. Drawn as the same line
   the property name would be anyway, so the header does not grow a control. */
.phone__site { margin: 0; display: flex; min-width: 0; }
.phone__site select {
  max-width: 100%;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 11.5px;
  color: var(--text-muted);
  cursor: pointer;
  appearance: none;
  text-overflow: ellipsis;
}
.phone__site option { color: var(--text); background: var(--surface); }

.phone__bell {
  position: relative;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  cursor: pointer;
}
.phone__bell svg { width: 19px; height: 19px; }
.phone__bell:active { transform: translateY(1px); }
.phone__bell.is-on { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }

.phone__badge {
  position: absolute;
  inset-block-start: -3px;
  inset-inline-start: -3px;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  box-sizing: border-box;
  border-radius: 999px;
  background: var(--busy);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}
.phone__badge[hidden] { display: none; }

/* --- the account screen's language switch --------------------------------- */
.me__lang {
  margin: 0;
  min-height: 56px;
  padding: 0 15px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  display: flex;
  align-items: center;
  gap: 12px;
}
.me__lang-label { flex-grow: 1; font-size: 14px; font-weight: 600; }
.me__lang-pair {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  overflow: hidden;
}
.me__lang-btn {
  border: 0;
  background: none;
  /* Three of these fit where two did, so the padding gives way rather than
     the row wrapping under the label. */
  padding: 9px 13px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-muted);
  cursor: pointer;
}
.me__lang-btn.is-on { background: var(--brand); color: var(--on-brand); }

/* --- the way between the jobs somebody does -------------------------------
   Only the jobs. The bell and the account moved to the header, which took the
   bar from seven items on a 375px screen — where two of the labels were cut
   in half — down to at most five, each with its whole name.
   -------------------------------------------------------------------------- */
.phone__bar {
  flex: none;
  display: flex;
  background: var(--surface);
  border-block-start: 1px solid var(--border);
  padding: 8px 6px calc(env(safe-area-inset-bottom, 0px) + 10px);
}
.phone__door {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 4px 2px;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 11.5px;
  font-weight: 500;
}
.phone__door svg { width: 21px; height: 21px; }
.phone__door span:last-child {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
@media (max-width: 380px) { .phone__door { font-size: 10.5px; } }
.phone__door.is-on { color: var(--brand); font-weight: 700; }
.phone__door:active { background: var(--surface-2); }

/* --- the filters ----------------------------------------------------------
   On the page rather than inside the band above it: they belong to the list
   under them, not to the person over them.
   -------------------------------------------------------------------------- */
.phone__tabs {
  flex: none;
  display: flex;
  gap: 8px;
  padding: 10px 14px 6px;
  overflow-x: auto;
  scrollbar-width: none;
}
.phone__tabs::-webkit-scrollbar { display: none; }

.phone__tab {
  flex: 0 0 auto;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 8px 14px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  white-space: nowrap;
}
.phone__tab span {
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: var(--surface-2);
  border-radius: 999px;
  padding: 1px 6px;
}
.phone__tab.is-on {
  background: var(--text);
  border-color: var(--text);
  color: var(--surface);
}
.phone__tab.is-on span { background: rgba(255, 255, 255, 0.18); color: inherit; }

/* --- the list ------------------------------------------------------------- */
.phone__body {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 6px 14px calc(env(safe-area-inset-bottom, 0px) + 22px);
  display: flex;
  flex-direction: column;
  /* Tighter than a card list wanted: the rows carry their own border now, so
     the gap is a separation rather than a shadow's breathing room. */
  gap: 8px;
}
.phone__body--centred {
  justify-content: center;
  align-items: center;
  gap: 18px;
  text-align: center;
}

.phone__loading,
.phone__empty {
  color: var(--text-muted);
  font-size: 14px;
  text-align: center;
  padding: 44px 16px;
  line-height: 1.7;
}
.phone__nothing {
  max-width: 300px;
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.7;
}

.phone__choice {
  width: 100%;
  max-width: 320px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 30px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--face);
  box-shadow: var(--bevel);
  color: var(--text);
  text-decoration: none;
  font-size: 17px;
  font-weight: 700;
}
.phone__choice svg { width: 34px; height: 34px; color: var(--brand); }
.phone__choice:active { transform: translateY(1px); box-shadow: var(--bevel-press); }

/* --- a room ---------------------------------------------------------------
   A row, not a card.

   It was a card: the number, a line of text, and under them a teal button the
   width of the screen. Four fitted on a phone — out of forty-six — and the
   same two words were written down the list forty-six times, which is noise
   rather than an instruction. Laid across instead, the number stays the
   loudest thing, the action shrinks to the size of a thumb, and eight fit.
   -------------------------------------------------------------------------- */
.rcard {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 11px 13px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* The work lists: one room, one line, one action, laid across. */
.rcard--row {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
}

/* The state is a mark at the leading edge, and never the only sign: the words
   in the row say the same thing. */
.rcard--urgent { border-inline-start: 3px solid var(--busy); }
.rcard--waiting { border-inline-start: 3px solid var(--arriving); }
.rcard--doing { border-inline-start: 3px solid var(--cleaning); }
.rcard--held { border-inline-start: 3px solid var(--maintenance); }
.rcard--done { border-inline-start: 3px solid var(--free); }

.rcard__head {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 12px;
}
.rcard--row .rcard__head { flex: 1 1 auto; }
.rcard__number {
  flex: none;
  min-width: 46px;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.rcard__text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.rcard__title {
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rcard__line {
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.4;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* What somebody has to know before they reach the door. A chip rather than
   another grey line, because grey is what the eye skips and this is the one
   fact on the row that changes what a person does. */
.rcard__badge,
.rcard__inside {
  align-self: flex-start;
  border-radius: 6px;
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  background: var(--now-bg);
  color: var(--now-ink);
}

.rcard__row {
  display: flex;
  gap: 8px;
}
.rcard__row > .bigbtn { flex: 1 1 0; }
.rcard--row .rcard__row { flex: none; }
.rcard--row .rcard__row > .bigbtn { flex: none; }

/* --- the buttons on a row -------------------------------------------------
   Square and the size of a thumb. The word that was on them is the same word
   on every row of the list, so the shape carries it instead: a triangle to
   start, a tick to finish, a spanner to report.
   -------------------------------------------------------------------------- */
.bigbtn {
  min-width: 46px;
  min-height: 46px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
}
.bigbtn svg { width: 19px; height: 19px; }
.bigbtn:active { transform: translateY(1px); }
.bigbtn[disabled] { opacity: .55; }

.bigbtn--go { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }
.bigbtn--ok { background: var(--free); border-color: var(--free); color: #fff; }
.bigbtn--held { background: var(--maintenance); border-color: var(--maintenance); color: #fff; }
.bigbtn--plain { color: var(--text-muted); font-weight: 600; }
.bigbtn--icon { color: var(--text-muted); padding: 0; flex: none; }
.rcard .bigbtn { min-height: 48px; }
.rcard--row .bigbtn { min-height: 46px; }


/* In a sheet, where there is one decision and room to name it, the buttons go
   back to being wide and worded. */
.sheet__row .bigbtn { flex: 1 1 0; min-height: 52px; }

/* --- a decision waiting on somebody --------------------------------------
   The figure is the biggest thing on the card, the way the room number is on
   a cleaning card: it is what the person is deciding about, and everything
   else on the card is there to justify it. */
.ask__head {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.ask__kind {
  /* Hugs its words and pushes the time to the far end, rather than stretching
     into a pill with a word lost in the middle of it. */
  margin-inline-end: auto;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--brand-dark);
  background: var(--brand-soft);
  border: 1px solid var(--brand-light);
  border-radius: 999px;
  padding: 4px 11px;
}
.ask__when { font-size: 11px; color: var(--text-soft); white-space: nowrap; }

.ask__figure {
  font-size: 25px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.ask__who {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.5;
}
.ask__reason {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--text);
}
.ask__reason--up {
  background: var(--maintenance-bg);
  border-color: var(--maintenance-br);
  color: var(--maintenance-ink);
}
.ask__outcome {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
}

/* A third choice under the two: smaller, because it is the rarer one. */
.bigbtn--thin {
  min-height: 42px;
  font-size: 12.5px;
  font-weight: 600;
  background: transparent;
  box-shadow: none;
  border-style: dashed;
  color: var(--text-muted);
}

/* --- the bell's own screen ------------------------------------------------ */
.alert {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 13px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: inherit;
  text-decoration: none;
}
.alert--unread {
  background: var(--brand-soft);
  border-color: var(--brand-light);
}
.alert__mark {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--blocked-bg);
  color: var(--blocked);
}
.alert__mark svg { width: 19px; height: 19px; }
.alert__mark--repair { background: var(--maintenance-bg); color: var(--maintenance); }
.alert__mark--clean { background: var(--cleaning-bg); color: var(--cleaning); }
.alert__mark--ready { background: var(--free-bg); color: var(--free-ink); }
.alert__mark--decide { background: var(--arriving-bg); color: var(--arriving-ink); }

.alert__text {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.alert__title { font-size: 14px; font-weight: 700; line-height: 1.4; }
.alert__body { font-size: 12.5px; color: var(--text-muted); line-height: 1.55; }
.alert__when { flex: 0 0 auto; font-size: 11px; color: var(--text-soft); white-space: nowrap; }

/* The one thing on the screen that asks for a decision rather than reporting
   one, so it is the only card with the brand's colour behind it. */
.alert-ask {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 15px 16px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--brand);
  background: linear-gradient(180deg, var(--brand) 0%, var(--brand-dark) 100%);
  box-shadow: var(--bevel-strong);
  color: #fff;
}
.alert-ask__title { font-size: 14.5px; font-weight: 700; }
.alert-ask__body { font-size: 12.5px; color: rgba(255, 255, 255, 0.85); line-height: 1.6; }
.alert-ask__btn {
  min-height: 46px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.6);
  background: #fff;
  color: var(--brand-dark);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}
.alert-ask__btn:active { transform: translateY(1px); }

/* A line of explanation among the cards — the phone refusing notifications,
   or anything else worth saying once without taking a card's worth of room. */
.phone__note {
  margin: 0;
  padding: 11px 13px;
  border-radius: var(--radius);
  background: var(--warn-bg);
  border: 1px solid var(--arriving-br);
  color: var(--warn-ink);
  font-size: 12.5px;
  line-height: 1.6;
}

.phone__clear {
  align-self: center;
  min-height: 44px;
  padding: 0 18px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}

/* --- the books ------------------------------------------------------------
   One figure large enough to read at arm's length, and the rest underneath it
   in the order somebody checks them.
   -------------------------------------------------------------------------- */
.till {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 11px;
}

/* The month. Dark on purpose: it is the one thing on the screen that is read
   first and from across a room, and the brand belongs on the figure somebody
   is actually asking about rather than on the furniture. */
.till--lead {
  background: var(--lead);
  border-color: var(--lead);
  color: var(--on-lead);
}
.till--lead .till__when { color: color-mix(in srgb, var(--on-lead) 62%, transparent); }
.till--lead .till__label { color: color-mix(in srgb, var(--on-lead) 62%, transparent); }

.till--thin {
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
}
.till__side { display: flex; flex-direction: column; gap: 3px; }

.till__when { font-size: 12px; font-weight: 700; color: var(--text-muted); }
.till__net { display: flex; align-items: baseline; gap: 9px; }
.till__figure {
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.till__figure--small { font-size: 21px; }
.till__label { font-size: 12px; color: var(--text-muted); }

/* What the figure is made of. A row each would be three more grey lines; side
   by side they are one glance. */
.till__split {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  padding-block-start: 12px;
  border-block-start: 1px solid color-mix(in srgb, var(--on-lead) 16%, transparent);
}
.till__cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.till__cell-label { font-size: 10.5px; color: var(--text-muted); }
.till--lead .till__cell-label { color: color-mix(in srgb, var(--on-lead) 55%, transparent); }
.till__cell-value {
  font-size: 13.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.till__way { display: flex; flex-direction: column; gap: 6px; }
.till__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  color: var(--text-muted);
}
.till__row b { color: var(--text); font-variant-numeric: tabular-nums; }
.till__track {
  height: 6px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}
.till__fill { height: 6px; border-radius: 999px; background: var(--brand); }

.sheet__label { font-size: 12.5px; color: var(--text-muted); }

/* --- the rooms, as a grid -------------------------------------------------
   Small squares because the question they answer is "which ones are free" —
   read across the whole floor at once, not one room at a time. */
.grid-rooms {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 8px;
}
.gtile {
  min-height: 84px;
  padding: 9px 8px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  border-block-end: 4px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
  cursor: pointer;
  text-align: start;
  overflow: hidden;
}
.gtile:active { transform: translateY(1px); }
.gtile:disabled { cursor: default; }
/* The number and the kind on one line, the number given whatever is left. */
.gtile__top {
  width: 100%;
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.gtile__number {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 19px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* The property's own code for the kind. Quiet — the number is what somebody
   is scanning for — but there, because "Free" on its own does not say which
   room to offer. Latin in both languages, so it is isolated: mirrored into
   the Arabic layout, 2BHK arrives as KHB2. */
.gtile__code {
  flex: none;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .02em;
  padding: 2px 5px;
  border-radius: 5px;
  /* Mixed from the tile's own text colour, so it reads on a pale tint by
     day and on a dark one at night without a second rule. */
  background: color-mix(in srgb, currentColor 12%, transparent);
  color: inherit;
  opacity: .8;
  direction: ltr;
  unicode-bidi: isolate;
  white-space: nowrap;
}
.gtile__state { font-size: 10.5px; font-weight: 600; color: var(--text-muted); }
.gtile__guest {
  font-size: 10.5px;
  /* Not `--text-soft`: that grey is tuned against the page, and a tile is a
     state wash — the softest grey on a green one came out at 4.18:1, and this
     is somebody's name. */
  color: var(--text-muted);
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The state is the bar under the tile and the word on it, never the colour
   alone. */
.gtile--free { background: var(--free-bg); border-block-end-color: var(--free); }
.gtile--busy { background: var(--busy-bg); border-block-end-color: var(--busy); }
.gtile--arriving { background: var(--arriving-bg); border-block-end-color: var(--arriving); }
.gtile--cleaning { background: var(--cleaning-bg); border-block-end-color: var(--cleaning); }
.gtile--maintenance { background: var(--maintenance-bg); border-block-end-color: var(--maintenance); }
.gtile--blocked { background: var(--blocked-bg); border-block-end-color: var(--blocked); }

/* --- the account screen --------------------------------------------------- */
.me__card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.me__row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 13px 15px;
  border-block-end: 1px solid var(--surface-2);
}
.me__row:last-child { border-block-end: 0; }
.me__label { flex-grow: 1; font-size: 12.5px; color: var(--text-muted); }
.me__value { font-size: 14px; font-weight: 600; text-align: end; }

.me__link {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 0 15px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
}
.me__link svg { width: 20px; height: 20px; color: var(--brand); flex: 0 0 auto; }
.me__link:active { background: var(--surface-2); }

.me__out { margin: 10px 0 0; display: flex; }
.bigbtn--leave {
  border-color: var(--busy-br);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--danger);
}
.bigbtn--leave svg { width: 19px; height: 19px; }
/*
  Leaving the app altogether. Quiet on purpose — it sits under the way out of
  the account, and closing the app is the rarer of the two. It carries its own
  `[hidden]` rule because it sets a display: the browser's own
  `[hidden] { display: none }` loses to any rule in a stylesheet, and without
  this it would be offered in a browser, where it cannot do anything.
*/
.me__quit {
  display: block;
  width: 100%;
  margin: 10px 0 0;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: none;
  font: inherit;
  font-size: 13.5px;
  color: var(--text-soft);
  cursor: pointer;
}
.me__quit[hidden] { display: none; }
.me__quit:active { background: var(--surface); }

.me__version {
  margin: 4px 0 0;
  text-align: center;
  font-size: 11.5px;
  color: var(--text-soft);
}

/* --- no signal, and what was said about it -------------------------------- */
.phone__offline {
  background: var(--warn-bg);
  color: var(--warn-ink);
  border-block-end: 1px solid var(--arriving-br);
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  padding: 9px 14px;
}
/*
  The offer to turn notifications on. It uses `display: flex`, which beats the
  browser's own `[hidden] { display: none }` — so it carries its own rule to
  hide it, or it would sit on every screen for ever, including for the people
  who already said yes.
*/
.phone__push {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--brand-light);
  color: var(--brand-dark);
  border-block-end: 1px solid var(--border);
}
.phone__push[hidden] { display: none; }
.phone__push > svg { width: 20px; height: 20px; flex: none; }
.phone__push-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.phone__push-text strong { font-size: 13px; font-weight: 700; }
.phone__push-text span { font-size: 11.5px; opacity: .85; line-height: 1.35; }
.phone__push-btn {
  margin-inline-start: auto;
  flex: none;
  border: 0;
  border-radius: 999px;
  padding: 7px 14px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--on-brand);
  background: var(--brand);
  cursor: pointer;
}
.phone__push-btn:active { transform: translateY(1px); }
.phone__push-btn[disabled] { opacity: .6; }

.phone__flash {
  position: fixed;
  inset-inline: 16px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 18px);
  z-index: 60;
  background: var(--text);
  color: #fff;
  border-radius: 12px;
  padding: 13px 16px;
  font-size: 13.5px;
  font-weight: 600;
  text-align: center;
  box-shadow: var(--shadow-lg);
  cursor: pointer;
}
.phone__flash--bad { background: var(--danger); }

/* --- the one panel that asks for typing ----------------------------------- */
.phone__sheet {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgba(15, 23, 42, 0.55);
  display: flex;
  align-items: flex-end;
}
/* A class that sets `display` beats the browser's own `[hidden] {display:none}`,
   because any author rule does. Without this line the panel is never hidden: it
   lies over the whole screen at z-index 70 and swallows every tap, which looks
   exactly like an app whose buttons do nothing. */
.phone__sheet[hidden] { display: none; }

.sheet {
  width: 100%;
  background: var(--surface);
  border-radius: 20px 20px 0 0;
  padding: 18px 16px calc(env(safe-area-inset-bottom, 0px) + 18px);
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-shadow: var(--shadow-lg);
}
.sheet__title { margin: 0; font-size: 16px; font-weight: 700; }
.sheet__field {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  padding: 12px;
  font: inherit;
  /* 16px or iOS zooms the page the moment the keyboard opens. */
  font-size: 16px;
  color: var(--text);
  background: var(--surface-2);
  resize: none;
}
.sheet__row { display: flex; gap: 8px; }

/* --- selling a room -------------------------------------------------------
   The dates are the question and they never scroll away; everything under
   them is the answer to them.
   -------------------------------------------------------------------------- */
.sell__when {
  flex: none;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 10px 14px 6px;
}
.sell__field {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.sell__field span { font-size: 10.5px; font-weight: 700; color: var(--text-muted); }
.sell__field input {
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  padding: 0 10px;
  font: inherit;
  /* 16px, or iOS zooms the page the moment the field is touched. */
  font-size: 16px;
  color: var(--text);
}
.sell__nights {
  flex: none;
  padding-block-end: 12px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  white-space: nowrap;
}

.sell__narrow { display: flex; gap: 8px; }
.sell__pick {
  flex: 1 1 0;
  min-width: 0;
  min-height: 42px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 0 10px;
}
.sell__count {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
}

/* The room's name gets the width it needs: a type cut to "Standard R…" is a
   room the seller cannot name on the telephone. */
.rcard--sell .rcard__title { white-space: normal; }

/* What the whole stay costs, which is the question on the telephone — with
   the nightly rate and the size under it, which are the two that follow. */
.sell__price { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sell__total {
  font-size: 17px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sell__each {
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* "Bookable, but not ready to hand over" on a room in the sell list. */
.sell__notready {
  margin-block-start: 3px;
  font-size: 11px;
  font-weight: 700;
  color: var(--warn-ink, var(--warn));
}

.sell__found { display: flex; flex-direction: column; gap: 6px; max-height: 190px; overflow-y: auto; }
.sell__guest {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.sell__guest.is-blocked { border-color: var(--busy-br); background: var(--danger-bg); }
.sell__guest-name { flex: 1 1 auto; font-size: 14px; font-weight: 600; }
.sell__guest-phone { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sell__guest-mark {
  background: var(--busy);
  color: #fff;
  border-radius: 6px;
  padding: 3px 7px;
  font-size: 10.5px;
  font-weight: 700;
}

.sell__party { display: flex; gap: 8px; }
.sell__count-box {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 48px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
}
.sell__count-label { flex: 1 1 auto; font-size: 12.5px; color: var(--text-muted); }
.sell__count-value { min-width: 18px; text-align: center; font-size: 15px; font-weight: 700; }
.sell__step {
  width: 36px;
  height: 36px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: 17px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.sell__step:active { transform: translateY(1px); }

/* --- the booking sheet -----------------------------------------------------
   It is a form now rather than one box: with no channel manager a booking from
   a site arrives as an email, and every line of that email has to go in while
   it is on the screen beside this. Tall enough to scroll, because that is more
   fields than a phone shows at once.
   -------------------------------------------------------------------------- */
.sheet--tall { max-height: 88vh; overflow-y: auto; }

/* A label that stays. A placeholder vanishes the moment somebody types, so a
   half-filled form used to say nothing about what was in it. */
.sell__input { display: flex; flex-direction: column; gap: 5px; }
.sell__input-label {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-muted);
}
.sell__input[hidden] { display: none; }

/* The new guest's fields, hidden the moment one on file is picked — there is
   nothing left to type about somebody the system already knows. */
.sell__fresh { display: flex; flex-direction: column; gap: 10px; }
.sell__fresh[hidden] { display: none; }

/* Attaching the email the booking was typed from. */
.sell__shot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px dashed var(--border-strong);
  border-radius: 12px;
}
.sell__shot-btn {
  flex: none;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  padding: 9px 14px;
  cursor: pointer;
}
.sell__shot-btn:active { transform: translateY(1px); }
.sell__shot-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 11.5px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A field that has to be filled says so where the eye already is — on its own
   label — rather than in a message after the form has been sent. */
.sell__must {
  margin-inline-start: 6px;
  font-size: 10px;
  font-weight: 700;
  color: var(--busy);
}
.sell__must[hidden] { display: none; }
.sell__input.is-missing .sheet__field {
  border-color: var(--busy);
  background: var(--danger-bg);
}

/* --- how full it is tonight ------------------------------------------------
   The answer, not the data. A desk is asked "how are we doing" and "have you
   got a two-bed" all day, and neither is answerable by reading sixty-five
   tiles — which is what the web board is, rightly, on a monitor.
   -------------------------------------------------------------------------- */
.tonight {
  background: var(--lead);
  color: var(--on-lead);
  border-radius: var(--radius-lg);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 13px;
}
.tonight__head { display: flex; align-items: center; gap: 16px; }

.tonight__dial { display: flex; flex-direction: column; gap: 1px; flex: none; }
.tonight__full {
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.tonight__word {
  font-size: 10.5px;
  color: color-mix(in srgb, var(--on-lead) 62%, transparent);
}

.tonight__side {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 8px;
}
.tonight__pair { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tonight__figure {
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tonight__label {
  font-size: 10px;
  color: color-mix(in srgb, var(--on-lead) 55%, transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* What is left of each kind.

   A grid rather than a scrolling row. It was a row, and with five kinds only
   two and a half of them were on the screen — the rest behind a sideways
   scroll with nothing to say it was there. Somebody holding a phone in front
   of a guest who has just asked "have you got a two-bed" does not discover a
   hidden scroll; they answer "no". An answer has to be visible, and the cost
   of that is forty pixels of height. */
.tonight__kinds {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(76px, 1fr));
  gap: 7px;
  padding-block-start: 12px;
  border-block-start: 1px solid color-mix(in srgb, var(--on-lead) 16%, transparent);
}
.tonight__kind {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 7px 10px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--on-lead) 12%, transparent);
}
/* Nothing left of this kind. Dimmed rather than hidden: "no two-beds" is an
   answer, and a kind that vanished would read as one nobody asked about. */
.tonight__kind.is-none { opacity: .45; }
.tonight__kind-count {
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* The property's own code for the kind — STD, 2BHK — which is what the paper
   in the office says and what fits three to a row. The full name is on the
   chip's title for anybody who has not learned them yet. */
.tonight__kind-name {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .02em;
  color: color-mix(in srgb, var(--on-lead) 62%, transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* A code is Latin in both languages: mirrored, "2BHK" becomes "KHB2". */
  direction: ltr;
  unicode-bidi: isolate;
  text-align: start;
}

/* Which building the screen is about. A control where the content depends on
   the answer, rather than a caption under somebody's name in the header — and
   a list rather than tabs, because a property is a thing somebody adds and
   five of them do not fit across a phone. */
.which {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.which__label {
  flex: none;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
}
.which__pick {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 14.5px;
  font-weight: 700;
  color: var(--text);
  text-align: end;
  cursor: pointer;
}
.which__pick option { color: var(--text); background: var(--surface); }

/* ---------------------------------------------------------------- laundry */
/*
  A trolley counted into a phone. The row is a name and a number box, and the
  box sits at the thumb end with a minus and a plus either side of it —
  somebody counting out loud taps once per sheet as often as they type a
  total, and both have to work without the keyboard covering the list.
*/
.lday {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px 14px;
}
.lday__middle { flex: 1 1 auto; text-align: center; }
/* `input.` rather than `.`: the shared stylesheet dresses every input type by
   name — input[type="date"] — and a bare class loses to it on specificity, so
   the box ends up the full width of the row with the item name crushed into a
   ten-pixel column beside it. */
input.lday__date {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 15px;
  text-align: center;
}
.lday__total {
  margin-top: 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
}

.lrow { display: flex; align-items: center; gap: 12px; width: 100%; }
.lrow__words { flex: 1 1 auto; min-width: 0; }
.lrow__name { font-size: 15px; font-weight: 700; line-height: 1.3; }
.lrow__retired { font-weight: 400; color: var(--text-muted); font-size: 12px; }
.lrow__price { margin-top: 2px; font-size: 12px; color: var(--text-muted); }
.lrow__count { display: flex; align-items: center; gap: 6px; flex: none; }

/* 44px is the smallest target a thumb hits reliably; the stepper is used
   once per piece down a list of twenty, so it is the one control here that
   must not be a near miss. */
.lstep {
  width: 44px;
  height: 44px;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  font-size: 22px;
  line-height: 1;
  font-weight: 700;
}
input.lcount {
  width: 68px;
  height: 44px;
  padding: 0 6px;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 17px;
  font-weight: 700;
  text-align: center;
}
/* The spinner arrows a browser adds are a two-pixel target beside a 44px
   one, and they push the digits off centre. */
.lcount::-webkit-outer-spin-button,
.lcount::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input.lcount { -moz-appearance: textfield; appearance: textfield; }

.lfoot { display: flex; gap: 10px; padding: 14px 2px 4px; }
.lfoot > .bigbtn { flex: 1 1 0; }

.phone__hint { font-size: 13px; color: var(--text-muted); margin-top: 8px; }

/* The room the boxes below are counting, and what the day has had so far. */
.lroom { padding: 0 2px 12px; }
select.lroom__pick {
  width: 100%;
  padding: 12px;
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
}
/* Rooms already counted today, as a strip to tap back into. It scrolls
   sideways rather than wrapping: on a round of forty rooms a wrapping strip
   would push the price list off the bottom of the screen. */
.lroom__done {
  display: flex;
  gap: 6px;
  margin-top: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
  scrollbar-width: none;
}
.lroom__done::-webkit-scrollbar { display: none; }
.lchip {
  flex: none;
  padding: 6px 10px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}
.lchip.is-on { background: var(--ready-bg); color: var(--ready-ink); border-color: var(--ready-ink); }
