/* ============================================================================
   screens/inventory.css - the asset registry
   ----------------------------------------------------------------------------
   Routers, switches, access points and cameras. A filtered, sorted, paged table
   on the desktop; the same page of records as tappable cards on a phone; and
   one drawer carrying the details, the move buttons and the movement history of
   whichever unit 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)
     .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-fb .ui-stat .ui-skel    components.css (filter bar, figures, skeleton)
     .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
   category plate, the identity cell, the location and warranty cells, the chip
   band, the drawer's own blocks, and the one floating button.

   THE PHONE COMES FIRST IN THIS FILE, NOT LAST. Two habits here are answers to
   a real complaint about the screen this one is modelled on:

     1. A chip is sized by its own text. mobile.css makes every `span` inside
        `.p-m` a block, which is right for a line of meta text and wrong for a
        badge: a block badge stretches the full width of the card and reads as a
        coloured bar. `.iv-tags > *` puts them back to inline-flex, and nothing
        in this file ever gives a badge a width.
     2. A filter row that does not fit scrolls sideways inside its own track,
        which is the behaviour the filter bar was written for. It is never left
        to spill past the edge of the screen, and the page body still never
        moves sideways.

   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. inventory.js rebuilds the stage on every render, so anything that
   moves as a record arrives is an animation with `backwards` fill rather than a
   transition, which would have nothing to transition from. The keyframes are
   the shared rise-in from base.css; inventory.js writes `--i` (an index capped
   at 12) on each card and each history row. 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.
   --------------------------------------------------------------------------- */

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

/* The New asset 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. */
.iv-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. */
.iv-tb-actions:empty{
  display: none;
}


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

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

.iv-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. */
.iv-stats > .ui-stat{
  animation: rise-in var(--t-base) backwards;
}

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


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

.iv-tbar{
  flex: none;
}

/* The filter bar carries its own track, so all this has to do is let it have
   the width it asks for and never force the toolbar wider than its column. */
.iv-filters{
  flex: 1;
  min-width: 0;
}

/* 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. */
.iv-summary{
  display: flex;
  align-items: center;
  min-width: 0;
}

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

/* On the desktop toolbar the filters used to squeeze this line until
   "24 di antaranya ditampilkan" stood 61px wide over three lines. It keeps its
   width there; a phone still lets it wrap, so 320px never scrolls sideways. */
@media (min-width: 861px){
  .iv-summary{ flex: none; }
  .iv-sum{ white-space: nowrap; }
}

.iv-count{
  color: var(--ink);
  white-space: nowrap;
}

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

.iv-refresh{
  flex: none;
}

/* The pager sits at the end of its row, like every other list screen. And an
   empty one leaves the column: pagerNode() returns null on a single page
   result, and a zero height flex item is still paid for with a gap. */
.iv-foot{
  display: flex;
  justify-content: flex-end;
  min-width: 0;
}

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


/* ---------------------------------------------------------------------------
   4. The stage, and the atoms both views share

   Every one of these is built once in inventory.js and used by the table cell
   and by the phone card, which is what keeps the two from describing the same
   asset differently.
   --------------------------------------------------------------------------- */

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

/* While a refetch is in flight the table stays put and simply dims, so typing
   in the search box does not strobe the screen through a skeleton. */
.iv-table{
  min-width: 0;
  transition: opacity var(--t-fast);
}

.iv-table.is-busy{
  opacity: 0.6;
}

/* The category plate: the one place a category icon appears, in the table, on
   the card and at the top of the drawer. */
.iv-plate{
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--r-sm);
  background: var(--gray-100);
  color: var(--navy);
}

/* In a table row the icon stands alone: a grey box repeated down the column
   is a plate on every row, which DESIGN.md 13 keeps out of new places. */
.ui-table .iv-plate{
  width: auto;
  height: auto;
  background: none;
  color: var(--gray-500);
}

.iv-plate .ic{
  width: 18px;
  height: 18px;
}

.iv-plate--lg{
  width: 52px;
  height: 52px;
  border-radius: var(--r);
  background: var(--gold-a14);
  color: var(--navy-900);
}

.iv-plate--lg .ic{
  width: 24px;
  height: 24px;
}

.iv-id{
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-width: 0;
}

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

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

.iv-id-s{
  display: flex;
  align-items: baseline;
  min-width: 0;
  font-size: 12px;
  color: var(--muted);
}

.iv-id-x{
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Where the unit is. The name leads, the holder is a second, quieter line. */
.iv-place{
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.iv-place-n{
  font-size: 13px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The warranty cell. A healthy unit shows a date and a countdown and no badge
   at all; only a problem earns one. */
.iv-warr{
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--s-1);
  min-width: 0;
}

.iv-warr-d{
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* Retired and lost units stay in the list, but stop competing for attention. */
.iv-table .is-gone .iv-id-n{
  color: var(--muted);
}

/* The chip band, used on the card and in the drawer head.

   THE RULE THAT MATTERS: a chip is intrinsic. It never grows to the width of
   its row, it never becomes a block, and a healthy asset carries one of them
   rather than a stack of four. */
.iv-tags{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-2);
  min-width: 0;
}

.iv-tags > *{
  flex: 0 0 auto;
  max-width: 100%;
}


/* ---------------------------------------------------------------------------
   5. Detail drawer
   --------------------------------------------------------------------------- */

/* Delete is the one action in this footer that cannot be undone, so it is
   pushed off the end of the row rather than left sitting against Close and Edit.
   .ui-dialog-foot is justify-content: flex-end, so 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 inventory.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. */
.iv-drawer .ui-dialog-foot > [data-act="delete"]{
  margin-inline-end: auto;
}

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

.iv-d-head{
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  min-width: 0;
}

.iv-d-id{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

.iv-d-name{
  margin: 0;
  font-family: var(--f-disp);
  font-size: 17px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
}

.iv-d-sub{
  margin: 0;
  font-size: 12px;
  color: var(--muted);
}

/* A small section heading, shared by the three blocks under the head. */
.iv-ph{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}

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

.iv-ph .iv-ph-t{
  margin-bottom: 0;
}

.iv-d-moves,
.iv-d-facts,
.iv-d-hist{
  min-width: 0;
}

/* The move buttons wrap rather than scroll: there are at most three of them at
   any one time, because the server only offers the moves this state allows. */
.iv-d-movebtns{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

.iv-d-moves .note{
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.iv-d-moves .note .ic{
  width: 14px;
  height: 14px;
}

/* The definition list. Two columns where there is room, one on a phone. */
.iv-facts{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--s-2) var(--s-4);
  margin: 0;
}

.iv-fact{
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  padding-block: var(--s-2);
  border-bottom: 1px solid var(--gray-100);
}

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

.iv-fact-v{
  margin: 0;
  font-size: 13px;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.iv-holder{
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}

.iv-link{
  color: var(--navy);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--t-fast);
}

.iv-link:hover{
  color: var(--gold-700);
}

.iv-d-notes{
  margin: var(--s-3) 0 0;
  padding: var(--s-3);
  border-radius: var(--r-sm);
  background: var(--gray-50);
  font-size: 13px;
  color: var(--gray-600);
}

/* The movement history: newest first, exactly as the route ordered it. */
.iv-moves{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.iv-move{
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: 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));
}

.iv-move-ic{
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: var(--gray-100);
  color: var(--navy);
}

.iv-move-ic .ic{
  width: 14px;
  height: 14px;
}

.iv-move-b{
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.iv-move-t{
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

.iv-move-n{
  font-size: 12px;
  color: var(--gray-600);
  overflow-wrap: anywhere;
}

.iv-move-m{
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  text-align: right;
}


/* ---------------------------------------------------------------------------
   6. 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. */
.iv-msearch{
  flex: none;
  width: 100%;
}

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

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

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

/* One asset, one card. The plate sits with the first line rather than centred
   against the whole block, so the identity line stays the top of the card. */
.iv-mrow{
  align-items: flex-start;
  animation: rise-in var(--t-base) backwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

.iv-mrow .p-m{
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Line two: the tag and the category, quieter than the name above it. */
.iv-mrow-meta{
  font-size: 12px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The tag inside that line is a `span.mono`, and mobile.css blocks every span
   inside .p-m, which would drop the category onto a line of its own. This scores
   above it and keeps the tag and the category on one line. */
.iv-mrow .p-m .iv-mrow-meta > *{
  display: inline;
}

/* Line three: where the unit is. Quieter again, and the first thing to go when
   the card runs out of width. */
.iv-mrow-place{
  font-size: 11px;
  color: var(--gray-500);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* mobile.css makes every span inside .p-m a block, which is right for the two
   meta lines above and wrong for a row of badges: a block badge fills the card
   and reads as a coloured bar. These two rules score above it and put the band
   and its chips back to intrinsic width. */
.iv-mrow .p-m .iv-tags{
  display: flex;
  margin-top: var(--s-1);
}

.iv-mrow .p-m .iv-tags > *{
  display: inline-flex;
  width: auto;
}

.iv-mrow .p-tail{
  align-self: center;
}

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

.iv-mrow.is-gone .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. */
.iv-mrow:focus-visible{
  box-shadow: var(--focus-ring);
}

/* The floating New asset 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 home indicator with the same tokens the tab bar itself uses. */
.iv-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);
}

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

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

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


@media (max-width: 860px){

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

  /* Room under the last card for the floating button, on top of the tab bar
     clearance layout.css already pays. The class is toggled by inventory.js
     from the same permission check that decides whether to render the button at
     all, so nobody without inventory.create pays for empty space. */
  .iv-mbody.has-fab{
    padding-bottom: calc(var(--s-4) + 68px);
  }

  /* THE FILTER ROW.

     The search field is already its own full width control in the head, so the
     bar below it is one row of chips and pickers. It is allowed to be wider
     than the screen and scroll sideways inside its own track, which is the one
     box in this screen that scrolls horizontally. What it must never do is
     wrap into three stacked rows that eat the fold, or run under the edge of
     the screen where the last chip cannot be reached. */
  .iv-mfilters{
    min-width: 0;
  }

  .iv-mfilters .ui-fb{
    flex-direction: column;
    align-items: stretch;
    gap: var(--s-2);
  }

  .iv-mfilters .ui-fb-track{
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    padding-bottom: var(--s-1);
  }

  .iv-mfilters .ui-fb-track::-webkit-scrollbar{
    display: none;
  }

  /* Nothing inside the track may shrink: a squashed picker is what turns a
     scrollable row back into a cut off one. */
  .iv-mfilters .ui-fb-track > *,
  .iv-mfilters .ui-fb-chips > *{
    flex: 0 0 auto;
  }

  .iv-mfilters .ui-fb-chips{
    flex-wrap: nowrap;
  }

  /* The 44px floor from the build contract, applied to every control in the
     row rather than to the chips alone. */
  .iv-mfilters .fchip,
  .iv-mfilters .ui-fb-select-el,
  .iv-mfilters .ui-fb-reset{
    min-height: 44px;
  }

  /* One column of facts in the drawer: two 220px columns inside a sheet on a
     390px screen would leave every value on its own line anyway. */
  .iv-facts{
    grid-template-columns: 1fr;
  }

  /* The history row keeps its stamp under the text on a narrow sheet instead of
     squeezing the note into a two word column. */
  .iv-move{
    flex-wrap: wrap;
  }

  .iv-move-m{
    flex-direction: row;
    align-items: center;
    gap: var(--s-2);
    width: 100%;
    padding-left: calc(28px + var(--s-3));
    text-align: left;
  }
}
