/* Cable Tasks — the field app's own stylesheet.
 *
 * Deliberately NOT app.css. The desk's stylesheet is a 3-column desktop shell
 * with a rail and a top strip; none of it is reachable on a phone, and loading
 * it would mean overriding more than this file contains.
 *
 * The look follows the design the operator drew: white cards on a light ground,
 * heavy type, generous rounding, one fact per line. Two things were added to
 * it, both for where this is actually used — a phone, held one-handed, in
 * daylight, sometimes up a pole:
 *
 *   * every tappable thing is at least 46px tall. The design's rows were
 *     drawn at a comfortable size already; this pins it.
 *   * contrast is pushed past the mock's greys. #6b7075 on white is 5.4:1,
 *     which survives a bright sky; the mock's lighter grey does not.
 *
 * The platform lime (#b4e419) appears only as a MARK — a rule, a bar, a chip
 * with dark text on it. It is never a background under white text: two screens
 * on this platform already paint white on it and it is unreadable
 * (see the portal skin note).
 */

:root {
  --cb-bg: #f2f3f5;
  --cb-card: #ffffff;
  --cb-ink: #111315;
  --cb-ink-2: #3d4247;
  --cb-muted: #6b7075;
  --cb-line: #e2e5e8;
  --cb-line-2: #d3d7dc;
  --cb-black: #0e0f11;
  /* Added 2026-08-30 with the bottom bar and the Create Ticket tile. The set
     had one dark value and the new surfaces need three: a card that sits ON
     the black, the hairline between them, and two greys for text on dark.
     Declared rather than written inline, because the rest of this file reads
     its colours from here and a block that does not is the one that stops
     matching the day a value changes. */
  --cb-black-2: #1a1c1f;
  --cb-line-dark: #24272b;
  --cb-dim: #8b9199;
  --cb-dim-2: #9aa1a9;
  --cb-ink-2: #3d434a;
  --cb-lime: #b4e419;
  --cb-lime-soft: #f0f9d6;
  --cb-red: #b3261e;
  --cb-red-soft: #fdf1f0;
  --cb-amber: #8a5b00;
  --cb-amber-soft: #fdf5e3;
  --cb-green: #276b2b;
  --cb-green-soft: #eef6ee;
  --cb-radius: 14px;
  --cb-pad: 16px;
  --cb-safe-b: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  background: var(--cb-bg);
  color: var(--cb-ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  -webkit-text-size-adjust: 100%;
  /* A field app is a list of tasks, not a document — a rubber-band overscroll
     that reveals a white void under the header reads as a broken page. */
  overscroll-behavior-y: none;
}

.cb-app { min-height: 100vh; display: flex; flex-direction: column; }

/* The whole app is capped at a phone's width and centred, so opening the same
   link on a laptop shows the same screen rather than a 2000px-wide card. */
.cb-page {
  width: 100%; max-width: 520px; margin: 0 auto;
  padding: 0 var(--cb-pad) calc(28px + var(--cb-safe-b));
  flex: 1;
}

.cb-boot {
  padding: 48px 24px; text-align: center; color: var(--cb-muted); font-size: 15px;
}
.cb-spin {
  display: inline-block; width: 16px; height: 16px; margin-right: 8px;
  vertical-align: -3px; border: 2px solid var(--cb-line-2);
  border-top-color: var(--cb-ink); border-radius: 50%;
  animation: cb-spin .7s linear infinite;
}
@keyframes cb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .cb-spin { animation-duration: 3s; } }

/* ───────────────────────────────────────────────────────────── the top bar */
.cb-top {
  position: sticky; top: 0; z-index: 20;
  background: var(--cb-black); color: #fff;
  padding: calc(10px + env(safe-area-inset-top, 0px)) 12px 10px;
}
.cb-top-in {
  max-width: 520px; margin: 0 auto;
  display: flex; align-items: center; gap: 8px; min-height: 34px;
}
.cb-top h1 {
  margin: 0; font-size: 17px; font-weight: 700; letter-spacing: -.2px;
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-back, .cb-topbtn {
  appearance: none; border: 0; background: rgba(255,255,255,.12); color: #fff;
  width: 38px; height: 38px; border-radius: 10px; font-size: 17px;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; flex: none;
}
.cb-back:active, .cb-topbtn:active { background: rgba(255,255,255,.26); }
/* `flex: 1` is load-bearing: this sits inside a flex row and has no content, so
   without it the box is 0px wide and the brand rule is simply invisible — which
   is how it shipped in the first screenshot pass. */
.cb-top .rule {
  flex: 1; height: 3px; background: var(--cb-lime);
  border-radius: 2px; margin-top: 10px;
}

/* ────────────────────────────────────────────────────────────── the greeting */
.cb-hello { padding: 22px 2px 6px; text-align: center; }
.cb-hello .hi { font-size: 15px; color: var(--cb-muted); font-weight: 600; }
.cb-hello .who {
  font-size: 30px; font-weight: 800; letter-spacing: -.7px; line-height: 1.14;
  margin: 2px 0 0; display: flex; align-items: baseline; justify-content: center; gap: 8px;
}
.cb-hello .who .wave { font-size: 24px; }
.cb-hello .team { margin-top: 6px; font-size: 13.5px; color: var(--cb-muted); }

.cb-h2 {
  font-size: 19px; font-weight: 800; letter-spacing: -.3px;
  margin: 24px 2px 4px;
}
.cb-sub { font-size: 13.5px; color: var(--cb-muted); margin: 0 2px 12px; }

/* ─────────────────────────────────────────────────────────────── stat cards */
.cb-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.cb-stat {
  appearance: none; text-align: left; font: inherit; color: inherit;
  background: var(--cb-card); border: 1px solid var(--cb-line);
  border-radius: var(--cb-radius); padding: 16px 16px 14px;
  min-height: 96px; cursor: pointer; display: block; width: 100%;
}
.cb-stat:active { background: #f7f8f9; }
.cb-stat .n {
  font-size: 34px; font-weight: 800; line-height: 1; letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
}
.cb-stat .k { margin-top: 8px; font-size: 14px; font-weight: 600; color: var(--cb-ink-2); }
.cb-stat.is-pending .n { color: var(--cb-ink); }
.cb-stat.is-working .n { color: var(--cb-amber); }
.cb-stat.is-done .n { color: var(--cb-green); }
.cb-stat.is-hold .n { color: var(--cb-ink-2); }

/* ────────────────────────────────────────────────────────────── menu rows */
.cb-rows { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.cb-row {
  appearance: none; font: inherit; color: inherit; text-align: left; width: 100%;
  background: var(--cb-card); border: 1px solid var(--cb-line);
  border-radius: var(--cb-radius); padding: 0 14px;
  min-height: 58px; display: flex; align-items: center; gap: 12px; cursor: pointer;
  text-decoration: none;
}
.cb-row:active { background: #f7f8f9; }
.cb-row .ico { width: 24px; flex: none; display: flex; justify-content: center; color: var(--cb-ink-2); }
.cb-row .lbl { flex: 1; font-size: 16.5px; font-weight: 700; letter-spacing: -.2px; }
.cb-row .cnt {
  font-size: 13px; font-weight: 700; color: var(--cb-muted);
  font-variant-numeric: tabular-nums;
}
.cb-row .chev { color: var(--cb-line-2); font-size: 20px; }

/* ──────────────────────────────────────────────────────────── task cards */
.cb-list { display: flex; flex-direction: column; gap: 12px; margin-top: 4px; }
.cb-task {
  appearance: none; font: inherit; color: inherit; text-align: left; width: 100%;
  background: var(--cb-card); border: 1px solid var(--cb-line);
  border-radius: var(--cb-radius); padding: 15px 15px 13px; cursor: pointer;
  display: block;
}
.cb-task:active { background: #f7f8f9; }
.cb-task .t {
  font-size: 17px; font-weight: 800; letter-spacing: -.3px; line-height: 1.25;
  margin: 0 0 2px;
}
.cb-task .meta { font-size: 13.5px; color: var(--cb-muted); }
/* .meta above is now unused -- .kind/.addr replace it, same retire-in-
   place convention as elsewhere in this file. New leaf classes for the
   redesigned card, 2026-09-03: */
.cb-task .top { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 7px; }
.cb-task .kind {
  font-size: 14px; font-weight: 600; color: var(--cb-ink-2, var(--cb-ink)); line-height: 1.3; margin: 0 0 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-task .addr {
  font-size: 13.5px; color: var(--cb-muted); line-height: 1.4; margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.cb-task .asg {
  font-size: 12px; font-weight: 600; color: var(--cb-muted);
  max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-task .foot {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--cb-line);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.cb-task .num {
  font-size: 12px; font-weight: 700; color: var(--cb-muted);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.cb-task .spacer { flex: 1; }

/* the countdown, the one thing on the card that changes colour */
.cb-clock {
  font-size: 13px; font-weight: 700; padding: 4px 9px; border-radius: 999px;
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
}
.cb-clock.ok { background: var(--cb-green-soft); color: var(--cb-green); }
.cb-clock.soon { background: var(--cb-amber-soft); color: var(--cb-amber); }
.cb-clock.late { background: var(--cb-red-soft); color: var(--cb-red); }
.cb-clock.none { background: #f1f2f4; color: var(--cb-muted); }

.cb-chip {
  font-size: 12px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  background: #f1f2f4; color: var(--cb-ink-2); white-space: nowrap;
}
.cb-chip.st-OPEN { background: var(--cb-lime-soft); color: #405c00; }
.cb-chip.st-IN_PROGRESS { background: var(--cb-amber-soft); color: var(--cb-amber); }
.cb-chip.st-WAITING { background: #eef0f8; color: #3b4a7a; }
.cb-chip.st-RESOLVED, .cb-chip.st-CLOSED { background: var(--cb-green-soft); color: var(--cb-green); }
.cb-chip.pri-HIGH, .cb-chip.pri-URGENT { background: var(--cb-red-soft); color: var(--cb-red); }

/* ────────────────────────────────────────────────────────── category grid */
.cb-cats { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.cb-cat {
  appearance: none; font: inherit; color: inherit; text-align: left; width: 100%;
  background: var(--cb-card); border: 1px solid var(--cb-line);
  border-radius: var(--cb-radius); padding: 14px; min-height: 108px; cursor: pointer;
  display: flex; flex-direction: column;
}
.cb-cat:active { background: #f7f8f9; }
.cb-cat .nm {
  font-size: 15px; font-weight: 800; letter-spacing: -.2px; line-height: 1.25;
  /* A complaint type can be 45 characters ("UTP cable to fiber cable update
     kore dite hobe"). Clamped rather than truncated to one line, so the tile
     shows enough to be recognised. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.cb-cat .sp { flex: 1; }
.cb-cat .n { font-size: 22px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.cb-cat .u { font-size: 12.5px; color: var(--cb-muted); margin-top: 3px; }
.cb-cat .late { color: var(--cb-red); font-weight: 700; }

/* ───────────────────────────────────────────────────────── detail screen */
.cb-detail { background: var(--cb-card); border: 1px solid var(--cb-line); border-radius: var(--cb-radius); padding: 16px; margin-top: 16px; }
.cb-detail h2 { margin: 0 0 4px; font-size: 21px; font-weight: 800; letter-spacing: -.4px; line-height: 1.2; }
.cb-detail .chips { display: flex; gap: 6px; flex-wrap: wrap; margin: 10px 0 2px; }
.cb-facts { margin: 14px 0 0; display: flex; flex-direction: column; gap: 0; }
.cb-fact { display: flex; gap: 12px; padding: 10px 0; border-top: 1px solid var(--cb-line); font-size: 14.5px; }
.cb-fact .k { width: 96px; flex: none; color: var(--cb-muted); font-weight: 600; }
.cb-fact .v { flex: 1; min-width: 0; word-break: break-word; }
.cb-fact .v a { color: #14507a; font-weight: 700; text-decoration: none; }
.cb-dash { color: var(--cb-line-2); }

.cb-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
.cb-btn {
  appearance: none; font: inherit; width: 100%; min-height: 52px; cursor: pointer;
  border-radius: 12px; border: 1px solid var(--cb-line-2); background: var(--cb-card);
  color: var(--cb-ink); font-size: 16px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; gap: 9px;
}
.cb-btn:active { background: #eef0f2; }
.cb-btn[disabled] { opacity: .55; cursor: default; }
.cb-btn.primary { background: var(--cb-black); border-color: var(--cb-black); color: #fff; }
.cb-btn.primary:active { background: #26292c; }
.cb-btn.go { background: var(--cb-lime); border-color: #9ecb0f; color: #23300a; }
.cb-btn.go:active { filter: brightness(.94); }
.cb-btn.quiet { background: transparent; border-color: transparent; color: var(--cb-muted); min-height: 44px; font-weight: 600; }

/* ─────────────────────────────────────────────────────── timeline / notes */
.cb-tl { margin-top: 8px; display: flex; flex-direction: column; gap: 12px; }
.cb-tl-i { display: flex; gap: 10px; font-size: 14px; }
.cb-tl-i .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--cb-line-2); margin-top: 7px; flex: none; }
.cb-tl-i .bd { flex: 1; min-width: 0; }
.cb-tl-i .w { color: var(--cb-muted); font-size: 12.5px; margin-top: 1px; }

/* ────────────────────────────────────────────────────────── sign-in card */
.cb-signin { max-width: 380px; margin: 0 auto; padding: 34px 20px calc(40px + var(--cb-safe-b)); }
.cb-brand { text-align: center; margin-bottom: 26px; }
.cb-brand .mk {
  width: 60px; height: 60px; border-radius: 16px; background: var(--cb-black);
  display: inline-flex; align-items: center; justify-content: center; margin-bottom: 12px;
}
.cb-brand .nm { font-size: 22px; font-weight: 800; letter-spacing: -.4px; }
.cb-brand .sb { font-size: 14px; color: var(--cb-muted); margin-top: 3px; }
.cb-field { margin-bottom: 14px; }
.cb-field label { display: block; font-size: 13px; font-weight: 700; color: var(--cb-ink-2); margin-bottom: 6px; }
.cb-field input {
  width: 100%; height: 52px; padding: 0 14px; font-size: 16px; /* 16px: anything
    smaller makes iOS Safari zoom the page on focus and it never zooms back. */
  border: 1px solid var(--cb-line-2); border-radius: 12px; background: #fff;
  color: var(--cb-ink); font-family: inherit;
}
/* Show / Hide sits INSIDE the password box. The button is padded to a real
   finger target rather than sized to its two words, and the input gets right
   padding so a long password never runs under it. */
.cb-pw { position: relative; }
.cb-pw input { padding-right: 76px; }
.cb-pw button {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  min-width: 62px; height: 40px; padding: 0 12px;
  font: inherit; font-size: 14px; font-weight: 700;
  color: var(--cb-ink-2); background: transparent;
  border: 0; border-radius: 10px; cursor: pointer;
}
.cb-pw button:active { background: var(--cb-line); }

.cb-field input:focus { outline: 2px solid var(--cb-black); outline-offset: -1px; border-color: var(--cb-black); }

.cb-note {
  border-radius: 12px; padding: 12px 14px; font-size: 14px; margin: 0 0 14px;
  border: 1px solid var(--cb-line);
}
.cb-note.err { background: var(--cb-red-soft); border-color: #f0cdc9; color: var(--cb-red); }
.cb-note.ok { background: var(--cb-green-soft); border-color: #cde2ce; color: var(--cb-green); }
.cb-note.info { background: #fff; color: var(--cb-ink-2); }

.cb-empty {
  text-align: center; padding: 44px 22px; color: var(--cb-muted); font-size: 15px;
  background: var(--cb-card); border: 1px solid var(--cb-line); border-radius: var(--cb-radius);
  margin-top: 4px;
}
.cb-empty b { display: block; color: var(--cb-ink); font-size: 17px; margin-bottom: 6px; font-weight: 800; }

/* ────────────────────────────────────────────────────────────────── toast */
.cb-toasts {
  position: fixed; left: 0; right: 0; bottom: calc(16px + var(--cb-safe-b));
  z-index: 60; display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none; padding: 0 16px;
}
.cb-toast {
  background: var(--cb-black); color: #fff; border-radius: 999px;
  padding: 11px 18px; font-size: 14.5px; font-weight: 600; max-width: 100%;
  box-shadow: 0 6px 20px rgba(0,0,0,.28);
}
.cb-toast.err { background: var(--cb-red); }

/* A sheet for the one thing that needs typing in the field: a note. */
.cb-sheet-bg {
  position: fixed; inset: 0; background: rgba(10,12,14,.5); z-index: 70;
  display: flex; align-items: flex-end; justify-content: center;
}
.cb-sheet {
  background: var(--cb-card); width: 100%; max-width: 520px;
  border-radius: 18px 18px 0 0; padding: 18px 18px calc(18px + var(--cb-safe-b));
}
.cb-sheet h3 { margin: 0 0 4px; font-size: 19px; font-weight: 800; letter-spacing: -.3px; }
.cb-sheet p { margin: 0 0 12px; font-size: 13.5px; color: var(--cb-muted); }
.cb-sheet textarea {
  width: 100%; min-height: 96px; padding: 12px; font-size: 16px; font-family: inherit;
  border: 1px solid var(--cb-line-2); border-radius: 12px; resize: vertical; color: var(--cb-ink);
}
.cb-sheet .row { display: flex; gap: 10px; margin-top: 12px; }
.cb-sheet .row .cb-btn { flex: 1; }


/* ══════════════════════════════════════════════════════════════════════════
   ⚠ SUPERSEDED 2026-08-31 — the gradient text wordmark in this section is
   retired in favour of the real logo (see "THE REAL LOGO" at the end of this
   file). .cb-word / .cb-wordsub / .mk / .nm / .sb are unused now; left in
   place rather than cut out of a file that already carries two overlapping
   .cb-brand / .cb-brandbar declarations — deleting the wrong half of that is
   an easy mistake, and dead CSS costs nothing a live selector does.

   THE BRAND (2026-08-30) — "spacenet upore ticketing hobe, akta gradient dao,
   jate cable operator ra dekhe khushi hoy."
   ══════════════════════════════════════════════════════════════════════════ */

/* The bar itself lifts off flat black into a lime-lit slope. Kept dark enough
   that white title text is still 12:1 on it — a header that looks good and
   cannot be read at arm's length in daylight is not an improvement for people
   working outdoors. */
.cb-top {
  background:
    radial-gradient(120% 160% at 84% -30%, rgba(180, 228, 25, .20), transparent 62%),
    linear-gradient(135deg, #0d0d0d 0%, #18220a 52%, #0d0d0d 100%);
}

.cb-brandbar {
  min-height: 0;
  gap: 8px;
  align-items: baseline;
  padding-bottom: 3px;
}

/* The wordmark. `background-clip: text` needs the -webkit- prefix to work in
   the Android and iOS browsers this app actually runs in, and a colour must be
   set to transparent or the fill paints over the gradient. */
.cb-word {
  font-weight: 800;
  font-size: 15.5px;
  line-height: 1;
  letter-spacing: -.3px;
  background: linear-gradient(96deg, #eaff8a 0%, #b4e419 44%, #86c40c 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.cb-wordsub {
  font-weight: 600;
  font-size: 10px;
  line-height: 1;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .58);
}

/* the rule under the bar picks the same light up */
.cb-top .rule {
  background: linear-gradient(90deg, #b4e419 0%, #86c40c 46%, rgba(134, 196, 12, .12) 100%);
}

/* ── the sign-in card ──────────────────────────────────────────────────── */
.cb-signin .cb-word {
  display: block;
  font-size: 30px;
  letter-spacing: -.8px;
  margin-top: 10px;
}
.cb-signin .cb-wordsub {
  display: block;
  margin-top: 5px;
  font-size: 11.5px;
  letter-spacing: 3.4px;
  color: #6f7568;
}
.cb-signin .cb-wordfoot {
  margin-top: 9px;
  font-size: 12.5px;
  letter-spacing: 0;
  text-transform: none;
  color: #8b9184;
}

@media (prefers-reduced-motion: no-preference) {
  .cb-signin .cb-word { transition: none; }
}


/* ── Direction / Open Location, on the task screen ─────────────────────────
   Two taps for someone standing in a road: one starts navigation, the other
   just shows the pin. Sized like the rest of this app rather than as text
   links — 46px of height and a real gap between them, because a mis-tap here in
   the rain is a wasted trip to the wrong place.

   Only new class names are defined here; nothing above is redefined. The
   specificity on .cb-fact .v is needed because that block already colours every
   <a> inside a fact value blue, and these are buttons, not links in a sentence.
   Direction is lime-on-black — the highest-contrast pair in this palette, which
   is what a phone held up in daylight needs. (Never white ON lime: #b4e419 is
   far too bright a background for white text.) */
.cb-maplinks { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 10px; }
.cb-fact .v a.cb-maplink {
  flex: 1 1 auto;
  min-width: 132px;
  min-height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 14px;
  border-radius: 12px;
  border: 1px solid var(--cb-line-2);
  background: var(--cb-card);
  color: var(--cb-ink);
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
}
.cb-fact .v a.cb-maplink.go {
  background: var(--cb-black);
  border-color: var(--cb-black);
  color: var(--cb-lime);
}
.cb-fact .v a.cb-maplink:active { transform: translateY(1px); }


/* ══ THE BOTTOM BAR, AND WHAT MOVED OUT OF THE PAGE TO REACH IT ══════════
   (2026-08-30) "task and report and setting agula nicher portile ar under
   rakho" — those three were rows down the home screen, so reaching Settings
   from a task meant going back to home first. On a phone the bar is the
   right place: one thumb, from anywhere.

   `position: fixed` with the safe-area inset, which is what index.html's
   viewport-fit=cover was already put there for. The page gets bottom padding
   to match, or the bar sits on top of the last row of every screen — and the
   last row of a task screen is usually a button. */
.cb-tabs {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  /* ⚠ Was repeat(4, 1fr). Hard-coding the count meant removing a tab left a
     quarter of the bar as empty space — the kind of break that only shows up
     on screen. Auto columns size themselves to however many tabs there are. */
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  background: var(--cb-black);
  border-top: 1px solid var(--cb-line-dark);
  padding-bottom: var(--cb-safe-b);
}
.cb-tab {
  appearance: none; border: 0; background: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 9px 4px 8px; color: var(--cb-dim); font: inherit;
  -webkit-tap-highlight-color: transparent;
  /* Without this the ::before marker below positions against .cb-tabs — which
     IS positioned, being fixed — and lands in the top-left corner of the whole
     bar instead of over its own tab. Caught by looking at it; the rule was
     "correct" and the marker was in the wrong place. */
  position: relative;
}
.cb-tab .lbl { font-size: 11px; font-weight: 600; letter-spacing: .2px; }
.cb-tab.is-on { color: var(--cb-lime); }
/* The lit tab also carries a bar along the top edge. Colour alone is the one
   cue a crew in daylight with a cracked screen most often cannot see. */
.cb-tab.is-on::before {
  content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 30px; height: 3px; border-radius: 0 0 3px 3px; background: var(--cb-lime);
}
.cb-page { padding-bottom: calc(74px + var(--cb-safe-b)); }

/* ══ CREATE TICKET ═══════════════════════════════════════════════════════
   The first thing on the home screen, per his order, and deliberately not a
   stat tile: it is the one control there that DOES something rather than
   counting something, so it does not sit in the grid with the four that do. */
.cb-new {
  appearance: none; width: 100%; text-align: left; cursor: pointer;
  display: grid; grid-template-columns: 44px 1fr; grid-template-rows: auto auto;
  column-gap: 12px; align-items: center;
  margin: 14px 0 4px; padding: 14px 16px;
  border: 0; border-radius: 16px; background: var(--cb-black-2); color: var(--cb-card);
  box-shadow: 0 2px 10px rgba(0,0,0,.16);
}
.cb-new .plus {
  grid-row: 1 / 3; display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: 13px;
  background: var(--cb-lime); color: var(--cb-ink); font-size: 27px; font-weight: 700; line-height: 1;
}
.cb-new .t { font-size: 17px; font-weight: 700; }
.cb-new .s { font-size: 12px; color: var(--cb-dim-2); }
.cb-new:active { transform: scale(.99); }

/* Total sits on its own above the four, because it IS the four added up and
   putting it in the grid would read as a fifth slice of itself. */
.cb-total {
  appearance: none; width: 100%; cursor: pointer; text-align: left;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 4px 0 10px; padding: 13px 16px;
  border: 1px solid var(--cb-line); border-radius: 14px; background: var(--cb-card); color: inherit;
}
.cb-total .n { font-size: 27px; font-weight: 800; line-height: 1; }
.cb-total .k { font-size: 14px; font-weight: 600; color: var(--cb-muted); }
.cb-total .late {
  margin-left: auto; font-size: 12px; font-weight: 700;
  color: var(--cb-red); background: var(--cb-red-soft); padding: 3px 9px; border-radius: 999px;
}

/* ══ THE CREATE FORM ═════════════════════════════════════════════════════
   One field per row, full width, 44px+ targets. A two-up grid fits on paper
   and loses to thumbs on a phone held in one hand at a gate. */
.cb-form { margin-top: 14px; display: grid; gap: 13px; }
.cb-f { display: grid; gap: 5px; }
.cb-f .k { font-size: 13px; font-weight: 700; color: var(--cb-ink-2); }
.cb-f.req .k { color: var(--cb-ink); }
.cb-f input, .cb-f select, .cb-f textarea {
  width: 100%; box-sizing: border-box;
  padding: 12px 13px; font: inherit; color: var(--cb-ink);
  background: var(--cb-card); border: 1px solid var(--cb-line); border-radius: 12px;
  /* 16px or iOS zooms the whole page in on focus and the crew loses the form. */
  font-size: 16px;
  min-width: 0;
}
.cb-f textarea { resize: vertical; }
.cb-f input:focus, .cb-f select:focus, .cb-f textarea:focus {
  outline: 2px solid var(--cb-lime); outline-offset: 1px; border-color: var(--cb-lime);
}
.cb-f .cb-btn.sm { justify-self: start; padding: 8px 14px; font-size: 13px; }
.cb-fhint { font-size: 12px; color: var(--cb-muted); line-height: 1.4; }


/* ══ THE HEADER, TIDIED — AND THE LANGUAGE CHOOSER ══════════════════════
   (2026-08-31) "agula aro nice koro and right side ye corner-e language
   English and Bangla."

   The brand row and the title row were two loose lines with a rule under
   them. Now the brand sits left with the chooser hard against the right
   corner, and the title row below it carries the screen name at a size worth
   the space it takes. The rule became the header's own bottom edge — one
   fewer element, and it no longer looks like a divider that lost its list.

   "Cable Tasks" is gone on his instruction: it named the audience, not the
   screen, and every crew member already knows they are the cable crew. The
   screen is Field Operations. */
.cb-top { padding-bottom: 0; }
.cb-brandbar { align-items: center; justify-content: space-between; gap: 10px; }
.cb-brand { display: inline-flex; align-items: baseline; gap: 7px; min-width: 0; }
.cb-titlebar { align-items: center; gap: 10px; padding-bottom: 14px; }
.cb-titlebar h1 {
  flex: 1; min-width: 0; margin: 0;
  font-size: 23px; font-weight: 800; letter-spacing: -.3px;
  /* A long screen name on a 360px phone must shorten, not push the refresh
     button off the edge. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The lime edge, now the header's own bottom border rather than a floating
   rule. Fades out to the right so it reads as a finish, not a progress bar —
   the old solid line was mistaken for one. */
.cb-top::after {
  content: ""; display: block; height: 3px;
  background: linear-gradient(90deg, var(--cb-lime) 0%, var(--cb-lime) 42%, rgba(180,228,25,.15) 100%);
}
.cb-topbtn, .cb-back {
  display: grid; place-items: center; flex: none;
  width: 38px; height: 38px; border-radius: 12px;
  background: rgba(255,255,255,.07); border: 0; color: #fff; cursor: pointer;
}
.cb-topbtn:active, .cb-back:active { background: rgba(255,255,255,.16); }

/* THE CHOOSER. Two options that both fit, so a segmented control rather than
   a dropdown — a menu you must open to see two things is one tap of nothing.
   The inactive half stays readable instead of greyed to a whisper: it is the
   thing somebody is looking for. */
.cb-lang {
  display: inline-flex; flex: none; padding: 2px;
  background: rgba(255,255,255,.09); border-radius: 999px;
}
.cb-langb {
  appearance: none; border: 0; cursor: pointer;
  padding: 5px 12px; border-radius: 999px;
  font: inherit; font-size: 12px; font-weight: 700; line-height: 1.3;
  background: none; color: rgba(255,255,255,.72);
  -webkit-tap-highlight-color: transparent;
  /* 32px tall inside a 26px pill: the tap target is bigger than the paint,
     which is what stops a thumb on a moving bus missing it. */
  min-height: 32px;
}
.cb-langb.is-on { background: var(--cb-lime); color: var(--cb-black); }
.cb-langb:not(.is-on):active { color: #fff; }

/* ⚠ BANGLA NEEDS MORE VERTICAL ROOM THAN LATIN AT THE SAME px, and the first
   pass did not give it enough: the hasant and the vowel signs that hang below
   the baseline (পেন্ডিং, টিকিট) were being clipped by line boxes sized for
   English. Caught by looking at a screenshot, not by any check — nothing about
   it is detectable from the markup.

   So the rule is a floor on line-height for every element that holds a
   translated string, not a per-element patch, because the next string added is
   the one the per-element list would miss. Scoped to the html[lang=bn] the
   switcher stamps, so English keeps its tighter setting. The big display
   NUMBERS are exempt — they are Latin digits either way, and 1.6 on a 27px
   numeral would push the label off the card. */
html[lang="bn"] .cb-titlebar h1 { font-size: 21px; line-height: 1.55; }
html[lang="bn"] .cb-tab .lbl { font-size: 11.5px; line-height: 1.7; }
html[lang="bn"] .cb-stat .k,
html[lang="bn"] .cb-total .k,
html[lang="bn"] .cb-h2,
html[lang="bn"] .cb-sub,
html[lang="bn"] .cb-new .t,
html[lang="bn"] .cb-new .s,
html[lang="bn"] .cb-f .k,
html[lang="bn"] .cb-fhint,
html[lang="bn"] .cb-fact .k,
html[lang="bn"] .cb-fact .v,
html[lang="bn"] .cb-btn,
html[lang="bn"] .cb-empty,
html[lang="bn"] .cb-hello .hi,
html[lang="bn"] .cb-total .late,
html[lang="bn"] .cb-chip,
html[lang="bn"] .cb-task .t,
html[lang="bn"] .cb-task .kind,
html[lang="bn"] .cb-task .addr,
html[lang="bn"] .cb-task .asg,
html[lang="bn"] .cb-clock { line-height: 1.65; }
/* A chip and a pill are fixed-height boxes, so extra line-height alone would
   still crop; they get the padding as well. */
html[lang="bn"] .cb-chip,
html[lang="bn"] .cb-clock,
html[lang="bn"] .cb-total .late { padding-top: 5px; padding-bottom: 5px; }
html[lang="bn"] .cb-stat .k { min-height: 2.6em; }

/* ═══════════════════════════════════════════════════════════════════════════════
   THE REAL LOGO (2026-08-31) — "tickeing remove kore dao mobiel view theke
   only speednet dao ... logo ta click korle chat gpt ar moto left side theke
   page asbe ... SpeedNet ata sidebar open hole asbe". The gradient wordmark
   above is retired for the actual company mark, pulled read-only from
   admin.speednetisp.com's own uploaded asset (the same file the live billing
   panel wears) — it already reads "SpeedNet" with its tagline baked in, so
   nothing here hand-draws an approximation of a real illustration.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ⚠ THE LOGO CARRIES BLACK TEXT — its tagline, "YOUR TRUSTED INTERNET
   PARTNER", is near-black, and "SpeedNet" itself is orange and green on a
   background that was baked flat #f7f7f7 in the source file. Two consequences,
   both of which shipped wrong in the first pass and were only caught by
   compositing the asset over the app's actual colours and LOOKING at it:

     1. The source PNG was 100% opaque. Dropped straight into this header it is
        a pale grey rectangle on black, and on the light sign-in card it is a
        visible lighter band. The asset is keyed to real transparency now
        (background removed, edges un-premultiplied so no white halo survives
        on a dark ground, transparent margin trimmed).

     2. Even keyed, the black tagline disappears on black. So in the DRAWER,
        which is dark, the logo sits on a white chip rather than directly on
        the black. That keeps the artwork exactly as the company drew it;
        recolouring somebody's logo to suit a background is not a styling
        decision that belongs in a stylesheet. On the light sign-in card it
        needs no chip and gets none.

     (The top bar no longer carries the logo at all — it is a menu button now,
     and the logo appears only inside the drawer that button opens.) */

/* THE MENU BUTTON (2026-08-31) — "uporer logo ar jaigai menu button dao".
   Styled as one of the bar's own controls rather than as a brand chip, so it
   reads as something to press and matches the refresh button opposite it. */
/* The mark itself is the button — no glyph beside it, nothing else to press.
   It needs no chip behind it because this asset has the tagline erased and a
   real alpha channel: the bike and the wordmark are saturated orange and green
   and read straight off the black. */
.cb-menubtn {
  appearance: none; border: 0; cursor: pointer; flex: none;
  display: inline-flex; align-items: center;
  padding: 6px 8px; border-radius: 10px;
  background: transparent; color: #fff;
}
.cb-menubtn:active { background: rgba(255,255,255,.12); }
.cb-navmark { display: block; height: 24px; width: auto; }

/* The sign-in card's own, larger lockup — light ground, so no chip. */
.cb-signbrand { text-align: center; margin-bottom: 22px; }
.cb-signlogo { height: 40px; width: auto; }
.cb-signfoot {
  margin-top: 10px; font-size: 12.5px; letter-spacing: .3px;
  color: var(--cb-muted); text-transform: none;
}

/* ── the drawer ───────────────────────────────────────────────────
   "chat gpt ar moto left side theke page asbe": a backdrop plus a panel that
   slides in from the left rather than a full-screen replacement, so the crew
   can still see — and tap outside to reach — the screen underneath. */
.cb-drawer-bg {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(10,12,14,0); transition: background .24s ease;
}
.cb-drawer-bg.is-open { background: rgba(10,12,14,.5); }
.cb-drawer {
  position: absolute; top: 0; bottom: 0; left: 0; width: min(84vw, 320px);
  background: var(--cb-black); color: #fff;
  /* The bottom inset matters as much as the top one here: the drawer runs the
     full height of the screen, so Sign out lands exactly where the iPhone
     home indicator is without it. Every other fixed thing in this app
     already pads for it. */
  padding: calc(18px + env(safe-area-inset-top, 0px)) 18px calc(18px + var(--cb-safe-b));
  transform: translateX(-100%); transition: transform .24s ease;
  display: flex; flex-direction: column;
  box-shadow: 8px 0 28px rgba(0,0,0,.3);
}
.cb-drawer-bg.is-open .cb-drawer { transform: translateX(0); }
@media (prefers-reduced-motion: reduce) {
  .cb-drawer-bg, .cb-drawer { transition: none; }
}
/* Rafiu, 2026-09-03: "profile ye click korle akhon left side theke bahir
   hoy ... ta right side theke bahir korar." Scoped to .is-profile only --
   the menu drawer (retired, unreachable from the bar now) keeps sliding
   from the left if anything ever reaches it again; the two are not required
   to agree on a side. */
.cb-drawer-bg.is-profile .cb-drawer {
  left: auto; right: 0;
  transform: translateX(100%);
  box-shadow: -8px 0 28px rgba(0,0,0,.3);
}
.cb-drawer-bg.is-profile .cb-drawer-top { flex-direction: row-reverse; }
/* BUG, caught by a real screenshot: this .is-profile rule's specificity
   (3 classes) beat the generic '.cb-drawer-bg.is-open .cb-drawer { transform:
   translateX(0) }' rule (2 classes) even while OPEN, so the panel stayed
   pinned off-screen at translateX(100%) the whole time -- only the dark
   backdrop ever showed. This 4-class rule outranks both. */
.cb-drawer-bg.is-profile.is-open .cb-drawer { transform: translateX(0); }
/* "logo ta upore tule dao page ar jekhane cross button ache" — brand and
   close on ONE row, the mark hard left and the ✕ hard right, instead of the ✕
   floating above a stacked brand block. */
.cb-drawer-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 18px;
}
.cb-drawer-x {
  appearance: none; border: 0; background: rgba(255,255,255,.12); color: #fff;
  width: 34px; height: 34px; border-radius: 9px; font-size: 15px;
  cursor: pointer; flex: none; display: grid; place-items: center;
}
.cb-drawer-x:active { background: rgba(255,255,255,.26); }
/* ⚠ NO WHITE CHIP ANY MORE — "image ta transparent koro, just cycle and name
   ta". The chip existed only because the full lockup's tagline is near-black
   and vanished on a dark panel. With the tagline erased from this asset the
   two things left, the bike and the wordmark, are saturated orange and green
   and read straight off the black, so the chip has nothing to solve and the
   mark can sit on bare background as he asked. */
.cb-drawer-logo { display: block; height: 26px; width: auto; }
.cb-drawer-nav { display: flex; flex-direction: column; gap: 2px; }
.cb-drawer-link {
  appearance: none; border: 0; background: transparent; color: #fff;
  display: flex; align-items: center; gap: 12px; text-align: left;
  min-height: 48px; padding: 0 8px; border-radius: 10px;
  font-size: 15.5px; font-weight: 600; cursor: pointer;
}
.cb-drawer-link .ico { color: var(--cb-lime); flex: none; display: flex; }
.cb-drawer-link:active { background: rgba(255,255,255,.1); }
.cb-drawer-foot {
  margin-top: auto; padding-top: 14px; border-top: 1px solid rgba(255,255,255,.12);
}

/* ── the profile panel ──────────────────────────────────────────
   Same panel as the menu — same slide, same backdrop, same close — carrying
   the account instead of the nav. One mechanism means the two cannot drift
   apart in how they behave. */
.cb-drawer-body { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.cb-prof-who { padding: 2px 2px 14px; }
.cb-prof-nm { font-size: 21px; font-weight: 800; letter-spacing: -.3px; }
.cb-prof-sub { margin-top: 3px; font-size: 12.5px; color: var(--cb-dim); }
/* The fact rows are the light-card ones; on this dark panel they need their
   own colours rather than inheriting greys meant for white. */
.cb-drawer .cb-facts { display: flex; flex-direction: column; gap: 0; }
.cb-drawer .cb-fact {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 11px 2px; border-top: 1px solid rgba(255,255,255,.09);
  font-size: 14px;
}
.cb-drawer .cb-fact .k { color: var(--cb-dim); flex: none; }
.cb-drawer .cb-fact .v { color: #fff; text-align: right; min-width: 0; word-break: break-word; }
.cb-drawer .cb-dash { color: var(--cb-dim-2, #6c7278); }
/* the Location dropdown row -- a <details> styled to read as one more
   .cb-fact until it is tapped open. */
.cb-fact-details { border-top: 1px solid rgba(255,255,255,.09); }
.cb-fact-details summary {
  list-style: none; cursor: pointer;
  display: flex; justify-content: space-between; align-items: center;
  padding: 11px 2px; font-size: 14px;
}
.cb-fact-details summary::-webkit-details-marker { display: none; }
.cb-fact-details .chev { color: var(--cb-dim); transition: transform .15s ease; display: inline-block; }
.cb-fact-details[open] .chev { transform: rotate(-90deg); }
.cb-fact-detail-body { padding: 0 2px 12px; color: var(--cb-dim); font-size: 13px; line-height: 1.5; }
.cb-prof-note {
  margin: 14px 2px 0; font-size: 12.5px; line-height: 1.55; color: var(--cb-dim);
}
.cb-drawer .cb-boot { color: var(--cb-dim); padding: 24px 2px; text-align: left; }
.cb-drawer .cb-note.err { background: rgba(214,69,52,.14); border-color: rgba(214,69,52,.4); color: #ffb4a8; }
html[lang="bn"] .cb-drawer .cb-fact,
html[lang="bn"] .cb-prof-note,
html[lang="bn"] .cb-prof-sub { line-height: 1.7; }
.cb-drawer-foot .cb-drawer-link { color: rgba(255,255,255,.75); font-weight: 600; }

/* the drawer's nav labels are translated text — same clipping trap as the
   rest of the app, so the same floor applies here. */
html[lang="bn"] .cb-drawer-link { line-height: 1.65; }

/* ── the language button + the sidebar's profile row (2026-08-31) ──────────
   "uporer navbar oi khane language ar icon dao" — the segmented EN/বাংলা pill
   is replaced by one icon button carrying the language you will GET, not the
   one you are in: a toggle that shows its current state reads as a label and
   gets tapped by mistake; one that shows its destination is a button. */
.cb-langbtn { width: auto; min-width: 38px; padding: 0 10px; gap: 6px; display: inline-flex; }
.cb-langbtn .lb { font-size: 11.5px; font-weight: 700; letter-spacing: .2px; }
/* 2026-09-03: flag-only button now (see chrome() in cable.js) -- .lb above
   is dead, unused since the EN/বাং text span is gone. */
.cb-langbtn .flag { font-size: 19px; line-height: 1; }
/* one level down inside the same panel, not a second panel */
.cb-drawer-back {
  appearance: none; border: 0; background: transparent; color: var(--cb-dim);
  font: inherit; font-size: 13.5px; font-weight: 600; text-align: left;
  padding: 0 2px 12px; cursor: pointer;
}
.cb-drawer-back:active { color: #fff; }
.cb-drawer-link .chev { margin-left: auto; color: var(--cb-dim); font-size: 18px; }
html[lang="bn"] .cb-drawer-back { line-height: 1.7; }

/* ══════════════════════════════════════════════════════════════════════════
   THE DESK'S TABLE ON THE PHONE (2026-08-31) — "table alare dekhao ... desktop
   view ar hubu replica mobile view teo."
   ══════════════════════════════════════════════════════════════════════════ */

/* Seventeen columns do not fit in 360px, and squeezing them until they do is
   no longer a replica — so it scrolls sideways, which is what the desk's own
   table does at a narrow window. -webkit-overflow-scrolling keeps that scroll
   momentum-based on iOS; overscroll-behavior-x stops a swipe past the last
   column turning into the browser's back gesture. */
.cb-tablewrap {
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  background: var(--cb-card);
  border: 1px solid var(--cb-line);
  border-radius: var(--cb-radius);
}
.cb-table { border-collapse: collapse; width: 100%; min-width: 1180px; font-size: 13px; }
.cb-table thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--cb-black); color: #fff;
  text-align: left; white-space: nowrap;
  font-size: 11px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  padding: 11px 12px;
}
.cb-table tbody td {
  padding: 12px; border-top: 1px solid var(--cb-line);
  vertical-align: top; color: var(--cb-ink-2);
}
.cb-table tbody tr:first-child td { border-top: 0; }
.cb-table tbody tr { cursor: pointer; }
.cb-table tbody tr:active td { background: #f4f6f8; }
.cb-table tbody tr:focus-visible { outline: 2px solid var(--cb-black); outline-offset: -2px; }

/* The long free-text columns are capped and the short ones never wrap, so one
   ticket stays one row: a table whose rows are three lines tall stops being
   scannable, which is the only reason to have a table. */
.cb-table td.c-title, .cb-table td.c-last_comment,
.cb-table td.c-note, .cb-table td.c-address {
  max-width: 230px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-table td.c-number, .cb-table td.c-created_at, .cb-table td.c-closed_at,
.cb-table td.c-age, .cb-table td.c-status, .cb-table td.c-pop_name,
.cb-table td.c-box_vlan, .cb-table td.c-open_location { white-space: nowrap; }
/* ⚠ The name columns were missing from the line above and "Abdul Karim" wrapped
   onto two lines, making every row two lines tall — the exact thing the comment
   above says a table must not do. Names get a cap AND nowrap, like the other
   free-text columns; a truncated name is still scannable, a two-line row is
   not. Only visible by looking at a rendered table. */
.cb-table td.c-customer_name, .cb-table td.c-assignee,
.cb-table td.c-created_by, .cb-table td.c-closed_by, .cb-table td.c-customer_type {
  max-width: 170px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-tnum { font-weight: 800; color: var(--cb-ink); }
.cb-tmap { color: #1a56b8; font-weight: 700; text-decoration: none; padding: 4px 0; display: inline-block; }
.cb-tmap:active { text-decoration: underline; }
.cb-table .cb-chip, .cb-table .cb-clock { display: inline-block; white-space: nowrap; font-size: 12px; }
html[lang="bn"] .cb-table thead th { line-height: 1.7; letter-spacing: 0; }
html[lang="bn"] .cb-table tbody td { line-height: 1.65; }

/* ── the Overdue button (2026-08-31) — "overdue ar akta button" ────────────
   Full width, on its own, between Total and the four tiles that add up to it.
   Red ONLY when something actually is late: a control that is permanently
   alarming stops being an alarm, and this is the one thing on the screen that
   should mean "go now" when it is lit. */
/* Sized to sit with the others rather than under them — "overdue ar dashboard
   box ta aktu boro koro baki gular moto". It takes .cb-total's numeral (27px)
   and its 13/16 padding, so the two full-width boxes on this screen read as one
   pair; the four .cb-stat cards below already share that numeral too. A
   control that is visibly smaller than everything around it reads as a
   footnote, and this is the one number that means "go now". */
.cb-od {
  appearance: none; width: 100%; cursor: pointer; font: inherit; text-align: left;
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 4px 0 10px; padding: 13px 16px;
  background: var(--cb-card); color: var(--cb-ink);
  border: 1px solid var(--cb-line); border-radius: 14px;
}
/* The icon sits on the text baseline with the rest of the row, so it needs
   taking off it by hand — align-items: baseline would hang an svg. */
.cb-od .ic { display: flex; color: var(--cb-muted); flex: none; align-self: center; }
.cb-od .n { font-size: 27px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.cb-od .t { font-size: 14px; font-weight: 600; color: var(--cb-muted); }
.cb-od .chev { margin-left: auto; color: var(--cb-line-2); font-size: 20px; align-self: center; }
.cb-od:active { background: #eef0f2; }

.cb-od.is-late {
  background: var(--cb-red-soft); border-color: #f0cdc9;
}
.cb-od.is-late .ic, .cb-od.is-late .t, .cb-od.is-late .n { color: var(--cb-red); }
.cb-od.is-late .chev { color: #d9a49c; }
.cb-od.is-late:active { filter: brightness(.97); }
/* Waiting for the office — amber, between the lime of work arriving and the
   red of work overdue: nothing is wrong yet, but somebody is waiting. */
.cb-od.is-wait { border-color: #f0e0b8; background: #fffaf0; }
.cb-od.is-wait .ic, .cb-od.is-wait .n { color: #a9750a; }
.cb-od.is-new .ic, .cb-od.is-new .n { color: #4a7c0f; }
.cb-od.is-new { border-color: #dbe9bd; background: #f7fbee; }
html[lang="bn"] .cb-od .t { line-height: 1.7; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE HOME HEADER, STRIPPED (2026-08-31) — "হ্যালো, rafi 👋 Owner / field
   operation — agula home page theke delete kore dao."
   ═══════════════════════════════════════════════════════════════════════════ */

/* One row instead of two: the logo left, the chooser and refresh grouped hard
   right. Grouping them is what keeps `justify-content: space-between` working
   — a third loose child would have spread all three evenly across the bar
   instead of pinning two to the corner. */
.cb-topright { display: flex; align-items: center; gap: 8px; flex: none; }
.cb-top-bare .cb-brandbar { padding-bottom: 11px; min-height: 42px; }

/* The h1 is still in the markup, just not on screen — see chrome(). This is
   the standard clip pattern rather than display:none, which would take it out
   of the accessibility tree along with the layout. */
.cb-sr {
  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;
}

/* The greeting used to open this page, so its top padding was the gap under
   the header. With it gone the first card would sit against the lime edge. */
.cb-page-home { padding-top: 18px; }

/* ⚠ .cb-hello and its html[lang="bn"] rule above are unused as of this change.
   Left in place: the block is three declarations, and putting the greeting
   back is one line of JS if he asks for it. */


/* ══════════════════════════════════════════════════════════════════════════
   THE SUMMARY CARDS + THE FIXED NAVBAR (2026-09-01)
   "agula box ar card akare kore dao and touch horizon kore dao ... aktu
   designer call dao ... ami kon feature click korle jate upore navbar change
   na hoy."
   ══════════════════════════════════════════════════════════════════════════ */

/* ── the row: TWO CARDS PER LINE ─────────────────────────────────────────
   "mobile view te card 2 ta kore thakbe akta sarite" (2026-09-01) — this was a
   horizontal snap-scroller for a day, with half the next card peeking; he
   ruled a two-up grid instead, and it is the better ruling: it matches the
   four stat tiles right below, so the whole screen is one rhythm, and every
   number is on screen at once with no gesture owed.

   Same track sizing as .cb-stats so the two grids' columns line up — a card
   edge that almost aligns with the tile edge under it reads as a mistake. An
   odd last card keeps one cell rather than stretching: a full-width straggler
   would look more important than the cards above it for no reason. */
.cb-strip {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  /* the SAME gap as .cb-stats, or the two grids' columns are a pixel apart —
     measured 185 vs 184 before this matched */
  gap: 12px;
  margin: 4px 0 12px;
}

.cb-card {
  appearance: none; cursor: pointer; font: inherit; text-align: left;
  display: flex; flex-direction: column; gap: 2px;
  padding: 13px 14px 14px; min-height: 116px;
  background: var(--cb-card); color: var(--cb-ink);
  border: 1px solid var(--cb-line); border-radius: 16px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .04);
  transition: transform .12s ease, box-shadow .12s ease;
}
.cb-card:active { transform: scale(.985); box-shadow: none; }
.cb-card .ic {
  display: inline-flex; width: 34px; height: 34px; margin-bottom: 8px;
  align-items: center; justify-content: center; border-radius: 10px;
  background: var(--cb-line-soft, #eef0f2); color: var(--cb-muted);
}
.cb-card .n {
  font-size: 27px; font-weight: 800; line-height: 1.05;
  font-variant-numeric: tabular-nums; letter-spacing: -.5px;
}
.cb-card .k {
  font-size: 12.5px; font-weight: 600; color: var(--cb-muted);
  line-height: 1.3;
}

/* ⚠ COLOUR ONLY WHEN THERE IS SOMETHING TO SEE. A card at zero stays neutral;
   the moment its number is above zero the icon and the figure take the card's
   own colour. A panel where everything is always lit tells you nothing about
   which one to look at. */
.cb-card.k-total.is-on .n { color: var(--cb-ink); }
.cb-card.k-total.is-on .ic { background: #eef2f6; color: #344054; }
/* lifetime is a fact, not an alert — neutral like Total, at any number */
.cb-card.k-life.is-on .n { color: var(--cb-ink); }
.cb-card.k-life.is-on .ic { background: #eef2f6; color: #344054; }

.cb-card.k-wait.is-on { border-color: #f0e0b8; background: #fffdf7; }
.cb-card.k-wait.is-on .n { color: #a9750a; }
.cb-card.k-wait.is-on .ic { background: #fdf3dd; color: #a9750a; }

.cb-card.k-new.is-on { border-color: #dbe9bd; background: #fbfdf6; }
.cb-card.k-new.is-on .n { color: #4a7c0f; }
.cb-card.k-new.is-on .ic { background: #eef6dd; color: #4a7c0f; }

/* the three that used to be .cb-stat tiles, keeping those tiles' colours */
.cb-card.k-work.is-on { border-color: #f0e0b8; background: #fffdf7; }
.cb-card.k-work.is-on .n { color: var(--cb-amber, #b45309); }
.cb-card.k-work.is-on .ic { background: #fdf3dd; color: var(--cb-amber, #b45309); }
.cb-card.k-hold.is-on .n { color: var(--cb-ink-2); }
.cb-card.k-hold.is-on .ic { background: #eef0f2; color: var(--cb-ink-2); }
.cb-card.k-done.is-on { border-color: #cde2ce; background: #fbfdfb; }
.cb-card.k-done.is-on .n { color: var(--cb-green, #166534); }
.cb-card.k-done.is-on .ic { background: #e7f3e8; color: var(--cb-green, #166534); }
.cb-card.k-late.is-on { border-color: #f4cfcb; background: #fffbfa; }
.cb-card.k-late.is-on .n { color: var(--cb-red); }
.cb-card.k-late.is-on .ic { background: #fdecea; color: var(--cb-red); }

/* ── the page head, below the bar ────────────────────────────────────────
   The screen's name lives here now instead of inside the navbar, so the bar is
   the same height and the same content on every screen. */
.cb-pagehead { background: var(--cb-bg); }
.cb-pagehead-in {
  max-width: 520px; margin: 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding: 14px var(--cb-pad) 2px;
}
.cb-pagehead .t {
  font-size: 22px; font-weight: 800; letter-spacing: -.4px; color: var(--cb-ink);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ⚠ .cb-back was styled white-on-translucent for the dark bar. It sits on the
   light ground now, so it needs its own colours or it is a white button on a
   near-white page. */
.cb-pagehead .cb-back {
  width: 36px; height: 36px; flex: none; border-radius: 10px;
  background: transparent; color: var(--cb-ink); border: 1px solid var(--cb-line);
  display: grid; place-items: center; margin-left: -4px;
}
.cb-pagehead .cb-back:active { background: #e9ecef; }

html[lang="bn"] .cb-pagehead .t { font-size: 20px; line-height: 1.55; }
html[lang="bn"] .cb-card .k { line-height: 1.6; }

/* ⚠ SUPERSEDED by the block above: .cb-titlebar (the navbar's old second row)
   and .cb-od (the three stacked full-width boxes) are no longer emitted by
   cable.js. Their rules are left in place rather than picked out of a file that
   carries several overlapping .cb-top declarations — dead CSS costs nothing a
   live selector does, and cutting the wrong half of that cascade by hand is how
   a header breaks silently. */

/* ═══ PHOTOS (shared markup from assets/photos.js) ════════════════════════
   Bigger than the desk's: every one of these is a finger target on a phone
   held in one hand at the top of a ladder. */
.snp { border: 1px solid var(--cb-line-2); border-radius: 12px; padding: 12px; background: #fff; }
.snp-head { font-size: 13px; font-weight: 700; color: var(--cb-ink-2); margin-bottom: 8px; }
.snp-count { font-weight: 600; color: var(--cb-ink-3, #8a8a8a); }
.snp-btns { display: flex; flex-wrap: wrap; gap: 8px; }
.snp-btn {
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-size: 15px; font-weight: 700; min-height: 48px; padding: 0 16px;
  border: 1px solid var(--cb-line-2); border-radius: 12px; background: #fff;
  color: var(--cb-ink); cursor: pointer;
}
.snp-btn:active { background: var(--cb-line); }
.snp-strip { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.snp-thumb { position: relative; width: 84px; height: 84px; }
.snp-thumb img { width: 100%; height: 100%; object-fit: cover; border-radius: 10px; border: 1px solid var(--cb-line-2); }
.snp-x {
  position: absolute; top: -8px; right: -8px; width: 28px; height: 28px;
  border: 0; border-radius: 50%; background: var(--cb-black, #111); color: #fff;
  font-size: 18px; line-height: 26px; padding: 0; cursor: pointer;
}
.snp-err { margin-top: 8px; font-size: 13px; color: var(--cb-red); }
.snp-empty { margin: 0; font-size: 13px; color: var(--cb-ink-2); }
.snp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; }
.snp-cell { display: block; }
.snp-cell img {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: 10px; border: 1px solid var(--cb-line-2); background: var(--cb-line);
}

/* Comments as a WhatsApp chat (2026-10-11): desk on the left (white, name on top),
   the crew on the right (green), newest at the bottom on a soft chat background. */
.cb-thread .cb-cmt-list { display: flex; flex-direction: column; gap: 6px; background: #efeae2; border-radius: 12px; padding: 10px 8px; margin: 8px 0; }
.cb-cmt-msg.wa-them, .cb-cmt-msg.wa-me { max-width: 82%; padding: 6px 10px 4px; border-radius: 10px; box-shadow: 0 1px 1px rgba(0,0,0,.12); border: 0; margin: 0; }
.cb-cmt-msg.wa-them { align-self: flex-start; background: #fff; border-top-left-radius: 2px; }
.cb-cmt-msg.wa-me { align-self: flex-end; background: #d9fdd3; border-top-right-radius: 2px; }
.cb-cmt-msg.wa-them .cb-cmt-who { color: #1f7aec; font-weight: 700; font-size: 12.5px; }
.cb-cmt-msg.wa-me .cb-cmt-who { color: #1d6b3a; font-weight: 700; font-size: 12.5px; text-align: right; }
.cb-cmt-msg.wa-them .cb-cmt-txt, .cb-cmt-msg.wa-me .cb-cmt-txt { font-size: 15px; line-height: 1.35; white-space: pre-wrap; word-break: break-word; }
.cb-cmt-msg.wa-them .cb-cmt-at, .cb-cmt-msg.wa-me .cb-cmt-at { font-size: 11px; color: #667781; text-align: right; margin-top: 2px; }

/* ── Profile page (2026-10-14): photo circle, name, position, rule, facts ── */
.cb-prof-head { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 4px 2px 6px; }
.cb-prof-pic {
  position: relative; width: 104px; height: 104px; border-radius: 50%;
  background: rgba(255,255,255,.08); border: 3px solid var(--cb-lime);
  display: grid; place-items: center; cursor: pointer; flex: none; margin-bottom: 12px;
}
.cb-prof-pic img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.cb-prof-ini { font-size: 36px; font-weight: 800; color: #fff; letter-spacing: .5px; }
.cb-prof-cam {
  position: absolute; right: -2px; bottom: 2px; width: 30px; height: 30px; border-radius: 50%;
  background: var(--cb-lime); color: #111; display: grid; place-items: center;
  border: 2px solid var(--cb-black);
}
.cb-prof-head .cb-prof-nm { font-size: 21px; font-weight: 800; letter-spacing: -.3px; }
.cb-prof-pos { margin-top: 3px; font-size: 14.5px; font-weight: 600; color: var(--cb-lime); }
.cb-prof-head .cb-prof-sub { margin-top: 4px; }
.cb-prof-rule { border: 0; border-top: 2px solid rgba(255,255,255,.16); margin: 14px 0 2px; }
.cb-drawer .cb-prof-rule + .cb-facts .cb-fact:first-child { border-top: 0; }
.cb-drawer .cb-fact .v a.cb-prof-tel, .cb-prof-tel { color: #fff; text-decoration: underline; text-decoration-color: rgba(255,255,255,.35); text-underline-offset: 3px; }
.cb-prof-from { font-size: 11.5px; color: var(--cb-dim); }
.cb-prof-sec { margin: 16px 2px 6px; font-size: 12px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; color: var(--cb-dim); }
.cb-prof-crew { display: flex; flex-direction: column; gap: 6px; }
.cb-prof-mem { padding: 9px 11px; border-radius: 10px; background: rgba(255,255,255,.06); }
.cb-prof-mem.is-me { background: rgba(255,255,255,.12); }
.cb-prof-mem .nm { font-size: 14px; font-weight: 700; color: #fff; }
.cb-prof-mem .ds { margin-top: 2px; font-size: 12.5px; color: var(--cb-dim); }
.cb-drawer .cb-prof-mem .ds a.cb-prof-tel { color: var(--cb-dim); }
.cb-prof-tag { display: inline-block; font-size: 10.5px; font-weight: 700; padding: 1px 7px; border-radius: 99px; background: var(--cb-lime); color: #111; vertical-align: 1px; }
.cb-prof-tag.me { background: rgba(255,255,255,.2); color: #fff; }
.cb-prof-more { margin-top: 14px; }
.cb-prof-more .cb-facts { padding-bottom: 4px; }
.cb-prof-more .cb-prof-note { margin-top: 6px; }
html[lang="bn"] .cb-prof-pos, html[lang="bn"] .cb-prof-mem .nm, html[lang="bn"] .cb-prof-mem .ds { line-height: 1.7; }
.cb-drawer .cb-fact .k { white-space: nowrap; }
