/* ============================================================================
   screens/clients.css - the client directory
   ----------------------------------------------------------------------------
   Hotels, villas, restaurants and offices. A filtered, sorted, paged table on
   the desktop; the same page of records as tappable cards on a phone; and one
   drawer carrying the contacts, locations, contracts, cases, assets and vault
   directory of whichever client is open.

   WHAT THIS FILE DOES NOT DO. Everything shared with other screens comes from
   the files above it and is not restated here:

     .panel .card .tbar          components.css (surfaces and the toolbar row)
     .av .bdg .tag .pill .dot    components.css (identity and status atoms)
     .btn .mini-btn .fchip       components.css (controls)
     .res .r-ic .r-body .r-act   components.css (the resource row, reused for
                                 contacts, cases, assets)
     .note .mono .muted .empty   components.css (text roles and the empty state)
     .ui-dt .ui-table .ui-pager  components.css (the data table and the pager)
     .ui-tabs .ui-meter .ui-stat components.css (the tab strip, the health bar
                                 and the four figures above the list)
     .phead .pbody .prow .p-m    mobile.css (the mobile head, column and row)

   So what is left below is only the vocabulary that exists nowhere else: the
   identity cell, the health figure, the case load and contract cells, the
   drawer's own blocks, and the one floating button.

   COLOUR. Every value is a token from tokens.css. There is no hex, no rgba and
   no priority flag in this file, and no rule needs one: each selector either names
   a class that exists nowhere else or scores above the shared rule it refines.

   MOTION. clients.js rebuilds the stage on every render, so anything that moves
   as a record arrives is an animation with `backwards` fill (held through the
   delay, released at the end) rather than a transition, which would have
   nothing to transition from. The keyframes are the shared rise-in and fade-in
   from base.css; clients.js writes `--i` (an index capped at 12) on each card,
   contact, contract, case, asset and vault group. Every duration is a --t-*
   token, so the reduced-motion rule in base.css neutralises the lot by
   overriding the tokens rather than by fighting specificity.
   ============================================================================ */


/* ---------------------------------------------------------------------------
   1. Desktop shell

   .content is already the one desktop scroller, so this screen only has to be
   a column inside it. No height and no overflow are declared here: adding
   either would take the scroll away from .content and strand the last row.
   --------------------------------------------------------------------------- */

.cl{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

/* The New client button in the topbar. .tb-tools is a flex row, so the wrapper
   only has to stop the button stretching and keep it off the search field. */
.cl-tb-actions{
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* An empty wrapper still contributes a gap to .tb-tools, which reads as the
   search field having drifted away from the avatar. */
.cl-tb-actions:empty{
  display: none;
}


/* ---------------------------------------------------------------------------
   2. The four figures above the list

   auto-fit rather than a fixed four: at 1100px the sidebar leaves room for
   three, and a fourth tile squeezed to 140px turns its label into two lines.
   --------------------------------------------------------------------------- */

.cl-stats{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
  gap: var(--s-3);
}

.cl-stats:empty{
  display: none;
}

/* The tiles arrive left to right, one --stagger apart, so the row reads as one
   movement rather than four things appearing at once. */
.cl-stats > .ui-stat{
  animation: rise-in var(--t-base) backwards;
}

.cl-stats > .ui-stat:where(:nth-child(2)){ animation-delay: var(--stagger); }
.cl-stats > .ui-stat:where(:nth-child(3)){ animation-delay: calc(var(--stagger) * 2); }
.cl-stats > .ui-stat:where(:nth-child(4)){ animation-delay: calc(var(--stagger) * 3); }


/* ---------------------------------------------------------------------------
   3. Toolbar and summary
   --------------------------------------------------------------------------- */

.cl-tbar{
  flex: none;
}

/* The filter bar carries its own horizontal scroller on a phone, so all this
   has to do is let it have the width it asks for. */
.cl-filters{
  min-width: 0;
  flex: 1;
}

/* The slot the summary line is written into. Its child carries the layout; this
   only stops the slot stretching inside the toolbar's right hand group. */
.cl-summary{
  display: flex;
  align-items: center;
  min-width: 0;
}

.cl-sum{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  font-size: 12.5px;
  color: var(--muted);
}

.cl-count{
  font-weight: 600;
  color: var(--navy);
  white-space: nowrap;
}

.cl-sep{
  color: var(--gray-400);
}

/* The reload control. It is disabled while a request is in flight, and looking
   disabled is the point: pressing it twice queues nothing useful. */
.cl-refresh:disabled{
  color: var(--gray-400);
  cursor: progress;
}


/* ---------------------------------------------------------------------------
   4. The table

   The data table ships no surface of its own, so the panel is here. Overflow is
   hidden on the wrapper only so the rounded corners clip the first and last
   rows; the table's own .ui-dt-scroll still handles a narrow window.
   --------------------------------------------------------------------------- */

.cl-stage{
  min-width: 0;
}

/* Positioned so the .sr-only sentences inside the cells take their containing
   block from here. Without it they resolved against <body>, escaped the
   table's own scroller and stretched the document past the window whenever
   the table was wider than its panel. */
.cl-table{
  position: relative;
  min-width: 0;
  border: 1px solid var(--gray-200);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--sh-sm);
  overflow: hidden;
  animation: fade-in var(--t-base) backwards;
  transition: opacity var(--t-fast);
}

/* A refresh that already has rows on screen dims them rather than replacing
   them with a skeleton, so typing in the search box never strobes the table.
   .is-busy is the app wide "waiting" state class. */
.cl-table.is-busy{
  opacity: .55;
}

/* A churned client is history, not a mistake: it stays legible and simply
   stops competing with the live ones for attention. */
.cl-table .ui-table tbody tr.is-churned{
  color: var(--muted);
}

.cl-foot{
  display: flex;
  justify-content: flex-end;
  min-width: 0;
}

.cl-foot:empty{
  display: none;
}


/* ---------------------------------------------------------------------------
   5. Record atoms - the cells the table and the phone cards share

   Each of these is built by ONE function in clients.js and rendered into both
   views, which is why none of them assumes a table cell around it.
   --------------------------------------------------------------------------- */

/* Avatar, name, code and the meta line. */
.cl-id{
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-width: 0;
}

.cl-id-m{
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}

.cl-id-n{
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A grid rather than a flex row, for the table's sake. A nowrap flex item
   reports its whole length as its minimum however it is told to shrink, so the
   meta line used to set the Client column's floor at its full width and push
   the table past its panel. In a minmax(0, max-content) track it asks for its
   whole length when there is room and for nothing when there is not, which
   leaves the name and the code as the column's floor. */
.cl-id-s{
  display: grid;
  grid-template-columns: auto minmax(0, max-content);
  align-items: baseline;
  column-gap: var(--s-1);
  min-width: 0;
  font-size: 11px;
  color: var(--muted);
}

/* The code is the one atom in this line that may never be broken. Without a
   floor of its own the column split it across two lines as "CL-" and "005",
   which is not a code any more. Unbreakable, it sets the auto track's width and
   the subtitle beside it ellipsizes instead. */
.cl-id-s > .mono{
  white-space: nowrap;
}

/* The subtype, area, city and room count. First to be given up when the column
   narrows, because the code beside it is the part people quote on the phone. */
.cl-id-x{
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The health score: the number, then its bar underneath at a hairline height.
   The bar is the shared .ui-meter, stripped of its label row by the JS. */
.cl-health{
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--s-1);
  min-width: 72px;
}

.cl-health-v{
  font-family: var(--f-disp);
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
}

.cl-health .ui-meter{
  width: 100%;
}

/* A hairline rather than the 8px the meter wears on its own: in a table cell it
   is a sparkline under a number, not a figure in its own right. */
.cl-health .ui-meter-track{
  height: 5px;
}

/* Open cases over the total, plus the two badges that only appear when there is
   something to say. The badges stack under the figure, one per line, so the
   cell asks for no more width than its widest line: whatever the table has to
   spare goes to the Client column, whose meta line is the one that needs it.
   Wide windows put them back beside the figure, at the end of this section. */
.cl-load{
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-2);
  min-width: 0;
}

/* "2 of 12 cases" on one line while the column has room, the figure over its
   caption when it does not. */
.cl-load-n{
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2);
  min-width: 0;
}

.cl-load-v{
  font-family: var(--f-disp);
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
}

/* The contract state: a badge, the number and the days left under it. */
.cl-contract{
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-1);
  min-width: 0;
}

/* How long the contract has to run is one fact, and the column is narrow enough
   that the note under the badge wraps. It used to wrap between the number and
   its unit; now the phrase holds together and the break falls after the
   separator instead. */
.cl-contract .cl-days{
  white-space: nowrap;
}

/* "Renew soon", from the server's own contract_expiring_soon flag. Gold rather
   than red on purpose: a contract running out is a job to schedule, not an
   outage, and spending the alarm colour here would leave nothing louder for the
   expired ones.

   The box is .bdg's own, 3px by --s-2 at line height 1.45, so it stands
   exactly as tall as the badge beside it and the phone card's footer keeps
   the height it had when this label was 10px. */
.cl-soon{
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 3px var(--s-2);
  border-radius: var(--r-sm);
  background: var(--gold-100);
  color: var(--gold-700);
  font-family: var(--f-ui);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.45;
  white-space: nowrap;
}

.cl-soon .ic{
  width: 12px;
  height: 12px;
  color: var(--gold-600);
}

/* Assets and vault entries side by side, and the repair badge under them, for
   the same reason the case badges sit under their figure. */
.cl-inv{
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--s-2);
  min-width: 0;
  font-family: var(--f-mono);
  font-size: 11.5px;
  color: var(--muted);
}

.cl-inv-n{
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}

.cl-inv-i{
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
}

.cl-inv-i .ic{
  width: 13px;
  height: 13px;
  color: var(--gray-400);
}

/* Wide windows. From 1460px the panel has room for every cell on as few lines
   as it likes, and the stacking above stops paying for itself: it only made a
   row with a badge one line taller than it had to be. So the badges go back
   beside their figure and their counts, the contract number keeps its days
   left on one line, and the meta line is held whole. That last one is not
   optional: a meta line that may give way loses its width to the badges now
   sitting side by side, and from 1460px to 1500px it was cut on every row.

   Held whole like this, the test directory's longest lines needed 1045px of
   the 1159px the panel has at 1460px (measured 23 October 2026, Indonesian),
   which leaves room for longer lines than the ones measured. */
@media (min-width: 1460px){
  .cl-id-s{
    grid-template-columns: auto max-content;
  }

  .cl-load,
  .cl-inv{
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }

  .cl-inv{
    justify-content: flex-end;
  }

  .cl-contract .note{
    white-space: nowrap;
  }
}


/* ---------------------------------------------------------------------------
   6. The detail drawer

   One scroll, top to bottom: the identity block, the health score, the tab
   strip, then the open panel. The drawer body is already a scroller from
   components.css, so nothing here declares a height.
   --------------------------------------------------------------------------- */

/* Delete is the one action in this footer that cannot be undone, so it is put
   at the far end of the row rather than next to Save, where a mis-aimed click
   would find it. The footer is a flex row from components.css; one auto margin
   on the Delete button is all it takes, and nothing matches when the button is
   absent. It is found by the data-act clients.js gives it, not by its look: the
   opener is a quiet ghost button (the red is on the confirmation), and the old
   .btn--danger selector stopped matching anything when that changed. */
.cl-drawer .ui-dialog-foot > [data-act="delete"]{
  margin-inline-end: auto;
}

.cl-d{
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  min-width: 0;
}

.cl-d-head{
  display: flex;
  align-items: center;
  gap: var(--s-4);
  min-width: 0;
  animation: fade-in var(--t-base) backwards;
}

.cl-d-id{
  flex: 1;
  min-width: 0;
}

/* An h3 inside a dialog whose title is the h2. base.css resets h1 to h3, so
   only the type scale is set here. */
.cl-d-name{
  font-family: var(--f-disp);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.2;
  color: var(--navy);
}

.cl-d-sub{
  margin-top: 2px;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--muted);
}

.cl-d-tags{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-2);
}

/* --- the health block ---------------------------------------------------- */

.cl-d-health{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--gray-200);
  border-radius: var(--r-lg);
  background: var(--gray-50);
  animation: rise-in var(--t-base) backwards;
  animation-delay: var(--stagger);
}

/* The four penalties. A two column grid so the labels line up and the numbers
   sit in one rail; one column on a narrow drawer. */
.cl-hps{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--s-2);
}

.cl-hp{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2);
  border-radius: var(--r-sm);
  background: var(--white);
  font-size: 12px;
  color: var(--muted);
  transition: background var(--t-fast), color var(--t-fast);
}

.cl-hp .ic{
  flex: none;
  width: 14px;
  height: 14px;
  color: var(--gray-400);
}

.cl-hp-l{
  flex: 1;
  min-width: 0;
}

/* The points deducted. Zero is the good answer and is shown, not hidden: the
   value only takes a colour when it actually cost something. */
.cl-hp-v{
  flex: none;
  font-family: var(--f-mono);
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--gray-400);
}

.cl-hp.is-on{
  background: var(--gold-100);
  color: var(--gold-700);
}

.cl-hp.is-on .ic,
.cl-hp.is-on .cl-hp-v{
  color: var(--gold-700);
}

/* --- panels -------------------------------------------------------------- */

.cl-d-panel{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  min-width: 0;
  animation: fade-in var(--t-base) backwards;
}

/* A panel's own heading row: title, count, and the one action that belongs to
   it. h4 and h5 are outside base.css's h1 to h3 reset, so the margin goes here. */
.cl-ph{
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-3);
  min-width: 0;
}

.cl-ph-t{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  font-family: var(--f-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--muted);
}

/* The sentence under a heading that explains what the list is bounded by, such
   as "the ten most recent cases". */
.cl-panel-note{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
}

.cl-panel-note .ic{
  flex: none;
  width: 14px;
  height: 14px;
  color: var(--gold-600);
}

.cl-block{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

.cl-notes{
  margin: 0;
  padding: var(--s-3);
  border-inline-start: 2px solid var(--gold-300);
  border-radius: var(--r-sm);
  background: var(--gold-100);
  color: var(--ink);
  font-size: 12.5px;
  line-height: 1.55;
}

/* --- the fact list ------------------------------------------------------- */

/* A <dl> whose dt/dd pairs are wrapped in a div each, which HTML allows and
   which is what lets one pair be a grid row without a subgrid. */
.cl-facts{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--s-1) var(--s-4);
  min-width: 0;
}

.cl-fact{
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  min-width: 0;
  padding: var(--s-2) 0;
  border-bottom: 1px solid var(--gray-100);
}

.cl-facts--tight .cl-fact{
  padding: var(--s-1) 0;
  border-bottom: 0;
}

.cl-fact-k{
  flex: none;
  width: 104px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--gray-600);
}

.cl-fact-v{
  flex: 1;
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink);
  word-break: break-word;
}

/* --- locations ----------------------------------------------------------- */

.cl-sites{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

.cl-site{
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--gray-200);
  border-radius: var(--r-sm);
  background: var(--white);
  animation: rise-in var(--t-base) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

.cl-site-m{
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.cl-site-m b{
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
}

/* The two links out of this screen: the client's cases, and its vault. */
.cl-jump{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--gray-200);
}


/* ---------------------------------------------------------------------------
   7. The lists inside the panels

   Contacts, cases and assets all wear the shared .res row, so this section only
   adds what a directory row needs on top of it: the stagger, the wrap that
   keeps the actions reachable in a 480px drawer, and the two state marks.
   --------------------------------------------------------------------------- */

.cl-list{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

.cl-list > li{
  min-width: 0;
}

.cl-list .res{
  flex-wrap: wrap;
  margin-bottom: 0;
  animation: rise-in var(--t-base) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

/* A floor width on the body is what actually triggers the wrap: .r-body carries
   min-width:0, so without this it would shrink towards nothing and the action
   buttons would crush the value instead of dropping to their own line. */
.cl-list .r-body{
  min-width: 180px;
}

.cl-list .r-act{
  flex-wrap: wrap;
  margin-inline-start: auto;
}

/* --- contacts ------------------------------------------------------------ */

.cl-contact .r-val{
  gap: var(--s-1) var(--s-2);
}

/* The primary contact carries a gold edge as well as the pill, so the mark
   survives a greyscale print and does not rely on hue alone. */
.cl-contact.is-primary{
  border-color: var(--gold-300);
  background: var(--gold-100);
}

.cl-primary{
  margin-inline-start: var(--s-2);
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* A WhatsApp number is not a link: wa.me would send the team out of the app and
   into a browser tab, so it is shown as text to copy. */
.cl-wa{
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  color: var(--muted);
}

.cl-wa .ic{
  width: 13px;
  height: 13px;
  color: var(--green);
}

/* Remove: the one action in a contact row that cannot be undone, so it warms to
   the alarm colour under the pointer instead of staying neutral like Edit. */
.cl-remove:hover{
  border-color: var(--red);
  color: var(--red-700);
}

.cl-remove .ui-x{
  width: 13px;
  height: 13px;
}

/* --- contracts ----------------------------------------------------------- */

.cl-contract-card{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-4);
  animation: rise-in var(--t-base) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

.cl-cc-top{
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2);
  min-width: 0;
}

.cl-cc-no{
  flex: 1;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
}

.cl-cc-note{
  margin: 0;
}

.cl-cc-act{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--gray-100);
}

/* --- cases --------------------------------------------------------------- */

/* The row is an anchor, so the underline comes off; the row box already gives
   it a visible boundary, and the hover wash says it leads somewhere. */
.cl-case{
  text-decoration: none;
  color: inherit;
}

.cl-case:hover{
  border-color: var(--gold-300);
  background: var(--gold-a05);
}

.cl-who{
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  min-width: 0;
  font-family: var(--f-ui);
  color: var(--muted);
}

/* --- assets -------------------------------------------------------------- */

/* A unit in repair is a hole in that property's network, so its row keeps a red
   edge even after the badge has scrolled out of view on a phone. */
.cl-asset.is-repair{
  border-inline-start: 2px solid var(--red);
  padding-inline-start: calc(var(--s-4) - 2px);
}

.cl-asset .note .ic{
  width: 12px;
  height: 12px;
  margin-inline-end: var(--s-1);
  color: var(--gray-400);
  vertical-align: -2px;
}

/* --- vault --------------------------------------------------------------- */

/* A directory, never a viewer: clients/get carries no value, no ciphertext and
   no rotation secret, so there is nothing here to mask and nothing to reveal. */
.cl-vgroup{
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--gray-200);
  border-radius: var(--r-lg);
  background: var(--white);
  animation: rise-in var(--t-base) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

.cl-vgroup-t{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0 0 var(--s-2);
  font-family: var(--f-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--muted);
}

.cl-vgroup-t .ic{
  width: 14px;
  height: 14px;
  color: var(--gray-400);
}

.cl-vitems{
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  min-width: 0;
}

.cl-vitem{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  padding: var(--s-1) 0;
  font-size: 12.5px;
  color: var(--ink);
}

.cl-vitem .ic{
  flex: none;
  width: 14px;
  height: 14px;
  color: var(--gray-400);
}

.cl-vitem-n{
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cl-vitem.is-stale .ic{
  color: var(--gold-600);
}


/* ---------------------------------------------------------------------------
   8. Mobile

   The same records, the same atoms, a different arrangement. .view-mobile is
   display:none above 860px, so everything below only exists where the tab bar
   it has to clear also exists.
   --------------------------------------------------------------------------- */

/* .tb-search carries flex: 0 1 230px, and inside a .phead - a flex COLUMN -
   that 230px would be read as a height. */
.cl-msearch{
  flex: none;
  width: 100%;
}

.cl-mbody{
  min-width: 0;
}

.cl-msummary{
  padding-inline: var(--s-1);
}

.cl-mlist{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

/* The card is a .prow from mobile.css, so the 44px target, the press, the
   surface and the selection shadow are all shared. The arrangement is this
   screen's own: three bands, the same reading order the Cases card uses on a
   phone - who it is, what is open, what the contract says.

   A grid rather than .prow's flex row, because the chip band and the contract
   footer have to run the FULL width under the identity line, not sit beside
   the avatar as two more columns. Naming the areas is what keeps the avatar in
   its own column on the first band and out of the way on the other two. */
.cl-mrow{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "av   main tail"
    "tags tags tags"
    "foot foot foot";
  align-items: center;
  column-gap: var(--s-3);
  row-gap: var(--s-2);
  animation: rise-in var(--t-base) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

.cl-mrow > .av{
  grid-area: av;
}

.cl-mrow > .p-m{
  grid-area: main;
}

/* The code, the category and the area, joined by middle dots. One line and
   clipped, never wrapped: a separator that lands at the head of the next line
   stops reading as a separator and starts reading as a bullet. The name above
   it already truncates the same way, from mobile.css. */
.cl-mrow-meta{
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A three digit health score sits hard against the chevron on --s-1; the wider
   gap holds for 67 and for 100 alike. */
.cl-mrow > .p-tail{
  grid-area: tail;
  align-items: center;
  gap: var(--s-2);
}

/* The chip band. Inline chips, each the width of its own text, flowing onto a
   second line when they run out of room - the Cases card's top row, without
   its fixed two slot split, because a client carries anywhere from one chip to
   four. It is a SIBLING of .p-m, never a child: mobile.css blockifies every
   span inside .p-m, which is right for a two line list row and was what used
   to stretch each badge across the whole card. */
.cl-mrow > .cl-mrow-tags{
  grid-area: tags;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  min-width: 0;
}

/* components.css sizes an icon inside .tag and inside .kcard-meta but not one
   inside .bdg, so a badge glyph falls back to the base 18px and towers over
   its own 11px label. Bring it down to the badge's scale. */
.cl-mrow-tags .bdg .ic{
  width: 13px;
  height: 13px;
}

/* "1 of 6 cases open", as one sentence on one line. It wears .b-low, so it is
   grey rather than coloured: a figure is not a warning, and the red and the
   gold chips beside it are the ones that have to carry. */
.cl-mload .ic{
  color: var(--gray-500);
}

/* The contract footer. Two groups pushed to the two edges with no separator
   glyph between them: a middle dot that lands at the head of a wrapped line
   reads as a bullet, so the layout does the separating instead. */
.cl-mrow > .cl-mft{
  grid-area: foot;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  min-width: 0;
  padding-top: var(--s-2);
  border-top: 1px solid var(--gray-100);
}

.cl-mft-l,
.cl-mft-r{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.cl-mft-r{
  margin-inline-start: auto;
}

.cl-mft-l > .ic{
  width: 14px;
  height: 14px;
  color: var(--gray-400);
}

/* The contract number is the one string here that can run long. */
.cl-mft-l .mono{
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
}

.cl-mft-l .bdg .ic,
.cl-mft-r .cl-soon .ic{
  width: 12px;
  height: 12px;
}

.cl-mft-d{
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
  white-space: nowrap;
}

/* No contract at all: the badge is the whole footer, and there is nothing to
   push it against. */
.cl-mft > .bdg .ic{
  width: 13px;
  height: 13px;
}

.cl-mrow-health{
  font-family: var(--f-disp);
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
}

.cl-mrow .p-tail .p-go{
  width: 16px;
  height: 16px;
  color: var(--gray-400);
}

.cl-mrow.is-churned .p-m b{
  color: var(--muted);
}

/* mobile.css gives a hovered .prow a box-shadow, which outranks base.css's
   focus ring. Put the ring back rather than leaving keyboard focus invisible. */
.cl-mrow:focus-visible{
  box-shadow: var(--focus-ring);
}

/* The floating New client button. Bottom RIGHT: commandbar.css parks its own
   launcher bottom left and the two must not stack. Cleared of the tab bar and
   of the iPhone home indicator with the same tokens the tab bar itself uses. */
.cl-fab{
  position: fixed;
  right: calc(var(--s-4) + var(--safe-r));
  bottom: calc(var(--bottombar-h) + var(--safe-b) + var(--s-4));
  z-index: 44;
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--fab-h);
  height: var(--fab-h);
  border: 0;
  border-radius: 999px;
  background: var(--gold);
  color: var(--navy-900);
  box-shadow: var(--sh-lg);
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--t-base), background var(--t-fast);
}

.cl-fab .ic{
  width: 22px;
  height: 22px;
}

.cl-fab:hover{
  background: var(--gold-600);
}

.cl-fab:active{
  transform: scale(.94);
}


@media (max-width: 860px){

  /* The fixed button only exists where the tab bar it clears also exists. */
  .cl-fab{
    display: inline-flex;
  }

  /* Room under the last card for the floating button, on top of the tab bar
     clearance layout.css already pays. 68px is the button itself plus the gap
     it keeps above the tab bar; --s-6 on top of that is the gap between the
     button and the last card, so scrolling to the end of the directory leaves
     the final row readable instead of half covered. The class is toggled by
     clients.js from the same permission check that decides whether to render
     the button at all, so nobody without clients.create pays for empty space. */
  .cl-mbody.has-fab{
    padding-bottom: calc(var(--s-6) + 68px);
  }

  /* components.css turns the filter track into a sideways scroller below
     720px. That is the right answer for a track holding two controls, and the
     wrong one for this track, which holds four category chips, two selects, a
     direction toggle and Clear: the tail of it sat off the right edge of a
     390px screen with nothing on screen to say there was more. Cases answers
     the same problem by wrapping, so this wraps too - the chips take a band of
     their own, the selects and the toggle share the band under it. */
  .view-mobile .cl-filters .ui-fb-track{
    flex-wrap: wrap;
    overflow-x: visible;
    padding-bottom: 0;
  }

  .view-mobile .cl-filters .ui-fb-chips{
    flex: 1 1 100%;
    flex-wrap: wrap;
  }

  /* The selects may shrink to share one line; the chips and the toggle keep
     their content width, because a squashed chip label has nowhere to go. */
  .view-mobile .cl-filters .ui-fb-select{
    flex: 0 1 auto;
    min-width: 0;
  }

  .view-mobile .cl-filters .ui-fb-select-el{
    width: 100%;
    min-width: 0;
    text-overflow: ellipsis;
  }

  /* Inside the drawer the fact list is one column: two 240px tracks do not fit,
     and auto-fit would otherwise leave a half empty second column. */
  .cl-facts,
  .cl-hps{
    grid-template-columns: minmax(0, 1fr);
  }

  /* At 390px a contact row has to stack: name and contact details first, the
     actions under them on their own full width line, each control a real 44px
     target. The wrap itself is section 7's rule; this is what makes the wrapped
     line usable with a thumb. */
  .cl-list .r-act{
    width: 100%;
    margin-top: var(--s-2);
    margin-inline-start: 0;
    justify-content: flex-end;
  }

  .cl-list .mini-btn{
    min-width: 44px;
    min-height: 44px;
  }

  .cl-fact-k{
    width: 92px;
  }
}


/* ---------------------------------------------------------------------------
   9. Print

   print.css hides every button inside .app, which is right for the filter bar
   and the floating action but would print the directory empty, because the
   table rows are buttons. These selectors score 0,3,0 and 0,2,0 against that
   rule's 0,1,1, so the list comes back without a priority flag and without
   touching print.css.
   --------------------------------------------------------------------------- */

@media print{

  .app .cl{
    display: block;
  }

  .app .cl-table .ui-dt-open{
    display: inline;
    color: var(--ink);
    cursor: auto;
  }

  /* Chrome, not content. */
  .app .cl-fab,
  .app .cl-tb-actions,
  .app .cl-refresh,
  .app .cl-filters,
  .app .cl-foot,
  .app .cl-jump,
  .app .cl-cc-act{
    display: none;
  }

  /* A stage caught at the first frame of its entrance would print blank. */
  .cl-stats > .ui-stat,
  .cl-table,
  .cl-d-head,
  .cl-d-health,
  .cl-d-panel,
  .cl-list .res,
  .cl-contract-card,
  .cl-vgroup,
  .cl-site,
  .cl-mrow{
    animation: none;
  }

  /* The dimming that says "a request is in flight" means nothing on paper. */
  .cl-table.is-busy{
    opacity: 1;
  }

  .app .cl-asset.is-repair{
    border-inline-start: 2px solid var(--gray-400);
  }
}
