/* The card strip and the states a collection can be in. `.fcard` has THREE consumers — fleet sessions,
   history rows, and the Claude-account rows — so it is not the fleet's private style; `.tag`, `.empty`,
   `.loading`, `.error` and the first-paint skeleton are shared by every surface that fetches. */
/* Fleet strip.

   A GRID, and the reason is that the previous spelling had no grid in it at all: `display:flex; flex-wrap:wrap`
   with `flex:1 1 260px` on the card makes 260px a BASIS, not a width. `flex-grow` then distributes each LINE's
   own leftover space, so a full line sits near the basis while the last line absorbs everything it has to
   itself — one trailing card spans the whole row. The fleet is usually 0-2 cards and nobody notices; the
   history is long, which is where the operator meets it.

   Every clause below is load-bearing:

   · `auto-fill`, NOT `auto-fit`. `auto-fit` collapses the tracks no item landed in and lets the remaining ones
     absorb their space, which stretches a lone card to the full row — the same defect respelled, for exactly
     the case that shows it worst.
   · `min(260px, 100%)`, not a bare 260px. The page chrome takes ~76px on a 320px viewport, leaving the grid
     ~244px; a bare `minmax(260px, 1fr)` track cannot shrink to that and overflows horizontally. On a page whose
     headline requirement is mobile-first, that is the requirement failing.
   · `align-items:start`. Grid items stretch by default, so every card on a line would grow to the height of
     the tallest one on it.
   · The empty state is appended into this same container, so it has to span rather than sit in track 1.

   The 260px track minimum is also what the page's first width step is derived FROM: two tracks plus the gap
   need 532px of strip, which is what 640px of viewport leaves once the gutters and the section frame are
   taken. See tokens.css — the breakpoint follows the content rather than a device list. */
.fleet { display:grid; grid-template-columns:repeat(auto-fill, minmax(min(260px, 100%), 1fr));
         gap:var(--s-3); align-items:start; }
.fleet > .empty { grid-column:1 / -1; }
.fcard { min-width:0; border:1px solid var(--line); border-radius:var(--radius-sm);
         padding:var(--s-3) var(--s-4); background:var(--bg);
         display:flex; flex-direction:column; gap:var(--s-2); }
.fcard .subj { font-weight:550; word-break:break-word; }
.fmeta { display:flex; gap:var(--s-2); flex-wrap:wrap; align-items:center; font-size:var(--t-meta);
         color:var(--muted); }
/* The card's actions. They WRAP, because a 246px card on a 320px phone cannot hold two buttons side by side
   at a touch size — and a card whose Stop button has been pushed past its own edge is a control the operator
   cannot reach on the surface where stopping matters most. */
.facts { display:flex; gap:var(--s-2); flex-wrap:wrap; }

.tag { border:1px solid var(--line-soft); background:var(--line-soft); color:var(--muted);
       border-radius:var(--radius-xs); padding:2px var(--s-2); font-size:var(--t-meta); }

.skeleton { height:66px; border-radius:var(--radius); background:var(--panel);
            border:1px solid var(--line); margin-bottom:var(--s-2); overflow:hidden; position:relative; }
.skeleton::after { content:""; position:absolute; inset:0; transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--muted) 9%,transparent),transparent);
  animation:sweep 1.4s infinite; }
@keyframes sweep { 100% { transform:translateX(100%); } }

.error { color:var(--block); padding:var(--s-4); border:1px solid var(--block); background:var(--block-soft);
         border-radius:var(--radius); white-space:pre-wrap; overflow-wrap:anywhere;
         font:var(--t-meta)/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; }
.empty { color:var(--faint); padding:var(--s-6) var(--s-1); text-align:center; font-size:var(--t-ui); }
.loading { color:var(--faint); padding:var(--s-6) var(--s-1); text-align:center; font-size:var(--t-ui);
           display:flex; align-items:center; justify-content:center; gap:var(--s-3); }
.spinner { width:16px; height:16px; border:2px solid color-mix(in srgb,var(--muted) 28%,transparent);
           border-top-color:var(--accent); border-radius:50%; animation:spin .7s linear infinite; flex:none; }
@keyframes spin { to { transform:rotate(360deg); } }

/* Both of this file's animations, disarmed together and AFTER the rules they have to beat — the same cascade
   rule the rest of the sheets carry, and the reason the skeleton's own disarm was moved down here out of the
   middle of the file rather than left where a second one would look like coverage.

   The spinner stops turning, and becomes an evenly coloured ring rather than a frozen one with a single
   brighter arc — a stopped partial ring reads as a spinner that has hung, which on a page where the spinner
   IS the "still fetching" signal is worse than no motion. What carries the signal instead is the copy beside
   it, which says so in words. An animation added below this block has to move it down again. */
@media (prefers-reduced-motion: reduce) {
  .skeleton::after { animation:none; }
  .spinner { animation:none; border-color:color-mix(in srgb,var(--accent) 55%,transparent); }
}

/* Per-account usage-credential enrolment row (accounts.js, renderUsageCredentialRow). It sits in the same
   `.fmeta` flow every other row-scoped strip on the card already uses, so it inherits wrap/gap/align for
   free; what is added here is specific to the two controls that flow does not already cover.

   The authorize URL is rendered as its own VISIBLE text on purpose — an operator on a host with no browser
   has to be able to read it and copy it by hand — so it has to survive the width this card is built for.
   A bare `<a>` has no wrap boundary of its own, and a PKCE authorize URL commonly runs past 200 characters
   with no spaces in it at all. On the 320px card this file's own header names as the requirement (see the
   `.fleet` note above: ~244px of grid track once the chrome is subtracted), an unwrapped run that long would
   push the card past its own track and back into the overflow that note exists to prevent.
   `overflow-wrap:anywhere` breaks it at any character once it runs out of natural break points, which a
   token-bearing URL never offers on its own. */
.credurl { display:block; overflow-wrap:anywhere; word-break:break-word; min-width:0;
           font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; color:var(--accent); }

/* The pasted-code box. Same skin as `.ceilbox` / `.budgetbox` above — through the same tokens, not a copy of
   their literals — but FLEXIBLE rather than fixed-width: unlike a percentage or a dollar figure, a pasted
   authorization code has no length this page can assume, and a fixed 5.5rem box would make a longer one
   scroll inside itself while the operator was still typing it. */
.credcode { min-height:var(--tap); width:100%; flex:1 1 12rem; min-width:0;
            font:var(--t-ui)/1.4 inherit; padding:0 var(--s-3); border:1px solid var(--line);
            border-radius:var(--radius-xs); background:var(--bg); color:var(--fg);
            transition:border-color var(--dur-1) var(--ease); }
.credcode:hover { border-color:var(--faint); }
