/* ============================================================================
   Moedatech Sales — design system v1
   Built from scratch for the sales product. Deliberately NOT the dashboard's
   system: this is a separate product with its own palette, type and shape.
   Do not import design-system/tokens.css here.

   Direction: the white studio equipment render. White body, cool graphite
   ground, darks reserved for the few parts that are genuinely dark. One
   signal colour, borrowed from hi-vis, spent only on urgency.

   Laptop first. The phone is the field case, not the design target.
   ========================================================================= */

/* ---- palette ------------------------------------------------------------
   Cool graphite. The dashboard's neutrals are warm, so the two products can
   never be mistaken for each other even on a shared screen. */
:root{
  --s0:#ffffff;
  --s5:#fafbfc;
  --s10:#f3f5f7;
  --s20:#e8eaee;
  --s30:#d7dae0;
  --s40:#b6bbc4;
  /* Measured, not asserted. The value that used to sit here claimed 4.6:1
     and was actually 3.19:1 on --s5 and 2.74:1 on --s20, so every secondary
     line in the app failed AA. This one clears 4.5:1 on every ground it is
     used on. If it changes, measure it again. */
  --s50:#667080;
  --s60:#5d646f;
  --s70:#3d434c;
  --s80:#262a31;
  --s90:#14171b;

  /* Signal. Hi-vis, and spent ONLY on time running out. If this colour shows
     up anywhere that is not urgency, the system is already leaking. */
  /* #c8461a measured 4.42:1 on --bg: close enough to look fine and still a
     fail. This clears 4.5 on every ground the clock sits on while staying
     the same hi-vis hue. */
  --signal:#bf4118;
  --signal-soft:#fbe9e3;

  /* Outcome. Rare by design: a queue row is neutral until it is resolved. */
  --good:#1f6b4a;
  --good-soft:#e2efe9;

  --bg:var(--s10);
  --panel:var(--s0);
  --line:var(--s20);
  --line-strong:var(--s30);
  --ink:var(--s90);
  --ink-2:var(--s60);
  --ink-3:var(--s50);

  --font:'Instrument Sans','Noto Sans Arabic',-apple-system,BlinkMacSystemFont,sans-serif;
  --mono:'JetBrains Mono',ui-monospace,'SF Mono',monospace;

  /* Type scale. Four steps, nothing between them. A dense table tempts you into
     11.5 / 12.5 / 13.5 to make a row fit; that is drift, not hierarchy. If a
     size is not one of these four, it is a bug. */
  --t-micro:11px;  --lh-micro:15px;   /* labels, counts, secondary meta */
  --t-body:13px;   --lh-body:19px;    /* everything a rep actually reads */
  --t-mid:16px;    --lh-mid:22px;     /* page and panel titles */
  --t-head:20px;   --lh-head:27px;    /* the one heading on a screen */

  /* Shape lock: one radius. Chips are the single exception and they are pills. */
  --r:6px;
  --r-pill:999px;

  /* Two curves, three durations. Never ease-in on interface. */
  --out:cubic-bezier(.22,1,.36,1);
  --in-out:cubic-bezier(.65,0,.35,1);
  --t-fast:110ms;
  --t:180ms;
  --t-slow:320ms;

  --rail:216px;
  --detail:400px;
}

@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --s0:#16191e;  --s5:#1a1e24;  --s10:#12151a; --s20:#272c34;
    --s30:#353b45; --s40:#4c545f; --s50:#8e96a2; --s60:#aeb5bf;
    --s70:#cbd1d9; --s80:#e4e8ed; --s90:#f5f7f9;
    --signal:#f0733f; --signal-soft:#3a221a;
    --good:#5cb98d;   --good-soft:#163025;
    --bg:var(--s10); --panel:var(--s5); --line:var(--s20); --line-strong:var(--s30);
  }
}
:root[data-theme="dark"]{
  --s0:#16191e;  --s5:#1a1e24;  --s10:#12151a; --s20:#272c34;
  --s30:#353b45; --s40:#4c545f; --s50:#8e96a2; --s60:#aeb5bf;
  --s70:#cbd1d9; --s80:#e4e8ed; --s90:#f5f7f9;
  --signal:#f0733f; --signal-soft:#3a221a;
  --good:#5cb98d;   --good-soft:#163025;
  --bg:var(--s10); --panel:var(--s5); --line:var(--s20); --line-strong:var(--s30);
}

*,*::before,*::after{box-sizing:border-box}

html,body{height:100%}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font);
  font-size:var(--t-body);
  line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
[dir="rtl"] body{ font-feature-settings:"ss01"; }

/* Every number is mono. In a queue the eye scans columns of figures, and
   proportional digits make that column ragged. */
.num,time,.metric{font-family:var(--mono);font-variant-numeric:tabular-nums}

button,input,select{font:inherit;color:inherit}
button{cursor:pointer;background:none;border:0;padding:0}
a{color:inherit}

::selection{background:var(--s80);color:var(--s0)}

:where(a,button,input,select,[tabindex]):focus-visible{
  outline:2px solid var(--ink);
  outline-offset:2px;
  border-radius:var(--r);
}


/* ---- viewing as --------------------------------------------------------
   Deliberately outside the app's palette: it is not part of the product, it
   is a state the product is in. Same treatment as the dashboard banner. */
.viewing{
  position:sticky;top:0;z-index:60;
  display:flex;align-items:center;justify-content:center;
  padding:7px 14px;
  background:#7c2d12;color:#fff;
  font-size:var(--t-micro);line-height:var(--lh-micro);font-weight:600;
  letter-spacing:.01em;
}
/* The frame is a full-height grid, so a banner above it has to come out of
   that height or the bottom of the app falls off the screen. */
body:has(.viewing) .app{height:calc(100dvh - 29px)}

/* ---- app frame ---------------------------------------------------------
   Laptop: fixed rail, fluid main, detail panel docks on the side.
   Phone: rail becomes a bottom bar, detail becomes a sheet. */
.app{
  display:grid;
  grid-template-columns:var(--rail) minmax(0,1fr);
  height:100dvh;
  overflow:hidden;
}

.rail{
  background:var(--panel);
  border-right:1px solid var(--line);
  display:flex;
  flex-direction:column;
  min-height:0;
}

.mark{
  display:flex;align-items:center;gap:9px;
  padding:18px 16px 14px;
}
.mark-glyph{
  width:26px;height:26px;border-radius:var(--r);
  background:var(--ink);
  /* The box is --ink, which flips to near-white in dark, so the glyph inside
     must be --s0 and not a hardcoded #fff or it disappears. */
  color:var(--s0);
  display:grid;place-items:center;
  flex:none;
}
.mark-glyph svg{width:14px;height:14px;display:block}
.mark-name{font-size:var(--t-body);font-weight:600;letter-spacing:-.01em}

.nav{padding:6px 8px;display:flex;flex-direction:column;gap:1px}
.nav-item{
  display:flex;align-items:center;gap:10px;
  padding:7px 8px;border-radius:var(--r);
  color:var(--ink-2);
  transition:background var(--t-fast) var(--out),color var(--t-fast) var(--out);
  text-decoration:none;
  width:100%;
}
.nav-item svg{width:16px;height:16px;flex:none;stroke-width:1.6}
.nav-item:hover{background:var(--s10);color:var(--ink)}
.nav-item[aria-current="page"]{background:var(--s20);color:var(--ink);font-weight:550}
.nav-count{
  margin-inline-start:auto;
  font-family:var(--mono);font-size:var(--t-micro);
  color:var(--ink-3);font-variant-numeric:tabular-nums;
}

.rail-foot{margin-top:auto;padding:10px 8px;border-top:1px solid var(--line)}

.new-btn{
  display:flex;align-items:center;justify-content:center;gap:7px;
  width:100%;padding:9px;border-radius:var(--r);
  background:var(--ink);color:var(--s0);
  font-size:var(--t-body);font-weight:550;
  transition:transform var(--t-fast) var(--out),opacity var(--t-fast) var(--out);
}
.new-btn svg{width:15px;height:15px;stroke-width:2}
.new-btn:hover{opacity:.88}
.new-btn:active{transform:translateY(1px)}

/* ---- main --------------------------------------------------------------- */
.main{display:flex;flex-direction:column;min-width:0;min-height:0}

.topbar{
  display:flex;align-items:center;gap:12px;
  padding:0 18px;height:52px;flex:none;
  border-bottom:1px solid var(--line);
  background:var(--panel);
}
.h1{font-size:var(--t-mid);line-height:var(--lh-mid);font-weight:600;letter-spacing:-.015em;margin:0}

.search{
  margin-inline-start:auto;
  position:relative;width:260px;max-width:38vw;
}
.search input{
  width:100%;padding:7px 10px 7px 30px;
  background:var(--bg);
  border:1px solid transparent;border-radius:var(--r);
  transition:border-color var(--t-fast) var(--out),background var(--t-fast) var(--out);
}
.search input::placeholder{color:var(--ink-3)}
.search input:focus{background:var(--panel);border-color:var(--line-strong);outline:none}
.search svg{
  position:absolute;left:9px;top:50%;transform:translateY(-50%);
  width:14px;height:14px;color:var(--ink-3);pointer-events:none;
}
[dir="rtl"] .search input{padding:7px 30px 7px 10px}
[dir="rtl"] .search svg{left:auto;right:9px}

.who{
  width:26px;height:26px;border-radius:var(--r-pill);
  background:var(--s20);color:var(--ink-2);
  display:grid;place-items:center;
  font-size:var(--t-micro);font-weight:600;flex:none;
}

/* ---- filter strip ------------------------------------------------------- */
.strip{
  display:flex;align-items:center;gap:6px;
  padding:10px 18px;flex:none;
  border-bottom:1px solid var(--line);
  background:var(--panel);
  overflow-x:auto;scrollbar-width:none;
}
.strip::-webkit-scrollbar{display:none}

.chip{
  display:inline-flex;align-items:center;gap:6px;
  padding:4px 10px;border-radius:var(--r-pill);
  border:1px solid var(--line-strong);
  color:var(--ink-2);white-space:nowrap;
  font-size:var(--t-body);
  transition:border-color var(--t-fast) var(--out),background var(--t-fast) var(--out),color var(--t-fast) var(--out);
}
.chip:hover{border-color:var(--s40);color:var(--ink)}
.chip[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--s0)}
.chip .n{font-family:var(--mono);font-size:var(--t-micro);font-variant-numeric:tabular-nums;opacity:.7}

.strip-sep{width:1px;height:18px;background:var(--line);flex:none;margin:0 4px}

/* ---- queue table -------------------------------------------------------
   Laptop gets a real table. The phone gets the same rows as cards, driven
   by data-label, so there is one renderer and not two. */
.scroll{overflow:auto;flex:1;min-height:0}

.q{width:100%;border-collapse:collapse}
.q thead th{
  position:sticky;top:0;z-index:2;
  background:var(--bg);
  text-align:start;font-weight:500;font-size:var(--t-micro);line-height:var(--lh-micro);
  letter-spacing:.02em;color:var(--ink-3);
  padding:8px 12px;
  border-bottom:1px solid var(--line);
  white-space:nowrap;
}
.q tbody tr{
  border-bottom:1px solid var(--line);
  transition:background var(--t-fast) var(--out);
  cursor:pointer;
}
.q tbody tr:hover{background:var(--panel)}
.q tbody tr[aria-selected="true"]{background:var(--panel);box-shadow:inset 2px 0 0 var(--ink)}
.q td{padding:9px 12px;vertical-align:middle}

.lead-name{font-weight:550;letter-spacing:-.005em}
.lead-sub{color:var(--ink-3);font-size:var(--t-micro);line-height:var(--lh-micro);margin-top:2px}

/* Equipment thumbnail. The silhouette is the label — this is why the render
   set has to keep one facing direction. */
.equip{
  width:38px;height:28px;border-radius:4px;
  background:var(--s10);
  object-fit:contain;flex:none;
  display:block;
}

.bucket{
  display:inline-block;padding:2px 8px;border-radius:var(--r-pill);
  background:var(--s20);color:var(--ink-2);
  font-size:var(--t-micro);line-height:var(--lh-micro);white-space:nowrap;
}

/* The request ladder is ORDINAL, so it reads as one deepening ramp rather than
   a set of unrelated hues. The dashboard says the same thing in a warm family;
   this system is monochrome, and a monochrome ramp carries "further along"
   better than colour does anyway.
   Recurring is the one break in the ramp, and it earns it: at four requests
   they are not a lead with a request, they are a customer with a habit, and
   that is a different call. */
.bucket[data-b="first_request"]{background:var(--s20);color:var(--ink-2)}
.bucket[data-b="second_request"]{background:var(--s30);color:var(--ink)}
/* --ink, not --s0. White on s40 measures 1.93:1 and fails AA outright;
   ink on the same ground is 9.33:1. The ramp still deepens through the
   background, which is what carries the ordering anyway. */
.bucket[data-b="third_request"]{background:var(--s40);color:var(--ink)}
.bucket[data-b="recurring_request"]{background:var(--good-soft);color:var(--good)}

/* The two shared-link buckets are one story, not two: money on the table from
   someone never signed. Outlined rather than filled, so they read as a pair
   and stay distinct from the ladder without adding a second accent. */
.bucket[data-b="link_no_account"],
.bucket[data-b="link_not_converted"]{
  background:transparent;color:var(--ink-2);
  box-shadow:inset 0 0 0 1px var(--line-strong);
}
.bucket[data-b="link_not_converted"]{color:var(--ink)}

/* A bucket this row also qualified for, but did not win. Present, secondary,
   never mistaken for the one that decides the call. */
.bucket.ghost{
  background:transparent;color:var(--ink-3);
  box-shadow:inset 0 0 0 1px var(--line);
  margin-inline-start:4px;
}

/* Realness. A bar, not a number with a label — the eye reads fill faster
   than it reads "72%". Track stays visible so partial is legible. */
.real{display:flex;align-items:center;gap:7px}
.real-track{display:block;width:44px;height:4px;border-radius:var(--r-pill);background:var(--s20);overflow:hidden;flex:none}
/* display:block is load-bearing: these are spans, and an inline box ignores
   width, so the fill silently renders at 0 and the track reads as an empty bar. */
.real-fill{display:block;height:100%;background:var(--ink);border-radius:inherit}
.real-n{font-family:var(--mono);font-size:var(--t-micro);color:var(--ink-3);font-variant-numeric:tabular-nums}

.bids{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--t-body)}
.bids-0{color:var(--ink-3)}

/* The clock is the only place the signal colour is allowed. */
.clock{font-family:var(--mono);font-size:var(--t-body);font-variant-numeric:tabular-nums;color:var(--ink-2)}
.clock.warm{color:var(--ink)}
.clock.hot{color:var(--signal);font-weight:600}

.owner{display:flex;align-items:center;gap:6px;color:var(--ink-2);font-size:var(--t-body)}
.owner-dot{
  width:22px;height:22px;border-radius:var(--r-pill);
  background:var(--s20);display:grid;place-items:center;
  font-size:var(--t-micro);font-weight:600;color:var(--ink-2);flex:none;
}
.unowned{color:var(--ink-3)}

.tick{
  width:26px;height:26px;border-radius:var(--r);
  border:1px solid var(--line-strong);
  display:grid;place-items:center;color:var(--ink-3);
  transition:border-color var(--t-fast) var(--out),color var(--t-fast) var(--out),background var(--t-fast) var(--out);
}
.tick svg{width:14px;height:14px;stroke-width:2}
.tick:hover{border-color:var(--good);color:var(--good);background:var(--good-soft)}


/* ---- ownership controls ------------------------------------------------ */
.claim{
  padding:3px 10px;border-radius:var(--r-pill);
  border:1px solid var(--line-strong);color:var(--ink-2);
  font-size:var(--t-micro);
  transition:border-color var(--t-fast) var(--out),color var(--t-fast) var(--out),background var(--t-fast) var(--out);
}
.claim:hover{border-color:var(--ink);color:var(--ink);background:var(--s10)}

.assign{
  max-width:104px;padding:2px 4px;
  background:var(--bg);color:var(--ink-2);
  border:1px solid var(--line-strong);border-radius:var(--r);
  font-size:var(--t-micro);
}

.owner-x{
  display:grid;place-items:center;
  width:16px;height:16px;border-radius:var(--r-pill);
  color:var(--ink-3);
  transition:background var(--t-fast) var(--out),color var(--t-fast) var(--out);
}
.owner-x svg{width:10px;height:10px;stroke-width:2.4}
.owner-x:hover{background:var(--signal-soft);color:var(--signal)}

/* A write that failed has to say so somewhere. The queue has no room for an
   inline error per row, so it surfaces once, briefly, out of the way. */
.toast{
  position:fixed;inset-inline:0;bottom:22px;margin-inline:auto;
  width:max-content;max-width:min(420px,88vw);z-index:70;
  padding:9px 14px;border-radius:var(--r);
  background:var(--s90);color:var(--s0);
  font-size:var(--t-body);
  opacity:0;transform:translateY(6px);pointer-events:none;
  transition:opacity var(--t) var(--out),transform var(--t) var(--out);
}
:root[data-theme="dark"] .toast{background:var(--s20);color:var(--s90)}
.toast.on{opacity:1;transform:none}

/* ---- states ------------------------------------------------------------- */
.skel{
  height:11px;border-radius:3px;
  background:linear-gradient(90deg,var(--s20) 25%,var(--s10) 37%,var(--s20) 63%);
  background-size:400% 100%;
  animation:shimmer 1.3s ease-in-out infinite;
}
@keyframes shimmer{from{background-position:100% 0}to{background-position:0 0}}

.empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:14px;padding:64px 24px;text-align:center;color:var(--ink-3);
}
.empty img{width:180px;max-width:60%;opacity:.5}
.empty p{margin:0;font-size:var(--t-body)}

.fail{
  margin:18px;padding:12px 14px;border-radius:var(--r);
  border:1px solid var(--line-strong);
  display:flex;align-items:center;gap:10px;
}
.fail svg{width:16px;height:16px;color:var(--signal);flex:none}
.retry{
  margin-inline-start:auto;padding:5px 10px;border-radius:var(--r);
  border:1px solid var(--line-strong);font-size:var(--t-body);
  transition:background var(--t-fast) var(--out);
}
.retry:hover{background:var(--s10)}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
}





/* A single-word verdict. Outreach answers "can I send" with a state, not a
   paragraph, so the word carries the colour and nothing else is said. */
.state-line{
  font-size:var(--t-mid);line-height:var(--lh-mid);font-weight:600;
  letter-spacing:-.01em;color:var(--ink-2);
}
.state-line[data-tone="good"]{color:var(--good)}
.state-line[data-tone="bad"]{color:var(--signal)}

/* ---- views -------------------------------------------------------------
   One scroll region, one view at a time. Contacts is the umbrella: supplier
   and rentee are a FILTER on one registry, never two registries. Two lists
   means the same company entered twice and drifting apart, which is the
   duplicate problem this company already paid to fix once. */
.view{display:none}
.view.on{display:block}

.tier{
  display:inline-grid;place-items:center;
  width:18px;height:18px;border-radius:var(--r-pill);
  font-size:var(--t-micro);font-weight:600;
  background:var(--s20);color:var(--ink-2);
}
.tier[data-t="A"]{background:var(--good-soft);color:var(--good)}
.tier[data-t="B"]{background:var(--s30);color:var(--ink)}

/* plaintext, not direction:rtl. Setting the element rtl also flips `start`, so
   the Arabic name drifts to the far edge of a wide column instead of sitting
   under the English one. plaintext orders the glyphs from the content while
   the box stays aligned to the column. */
.name-ar{
  color:var(--ink-3);font-size:var(--t-micro);line-height:var(--lh-micro);
  margin-top:2px;unicode-bidi:plaintext;text-align:start;
}

.on-app{
  display:inline-flex;align-items:center;gap:5px;
  font-family:var(--mono);font-size:var(--t-micro);color:var(--ink-2);
}
.on-app::before{
  content:"";width:6px;height:6px;border-radius:var(--r-pill);background:var(--good);
}

.more{
  display:block;width:100%;padding:12px;
  font-size:var(--t-body);color:var(--ink-2);
  border-top:1px solid var(--line);
  transition:background var(--t-fast) var(--out),color var(--t-fast) var(--out);
}
.more:hover{background:var(--panel);color:var(--ink)}
.more[disabled]{opacity:.4;pointer-events:none}

/* ---- create ------------------------------------------------------------
   The + makes exactly two things, because those are the only two a rep
   creates from nothing. Everything else is reached, not made. */
.pick{display:grid;gap:6px;padding:10px}
.pick-item{
  display:flex;align-items:center;gap:11px;width:100%;
  padding:13px 14px;border-radius:var(--r);
  border:1px solid var(--line-strong);text-align:start;
  transition:background var(--t-fast) var(--out),border-color var(--t-fast) var(--out);
}
.pick-item:hover{background:var(--s10);border-color:var(--s40)}
.pick-item svg{width:18px;height:18px;stroke-width:1.7;flex:none;color:var(--ink-2)}
.pick-item[aria-disabled="true"]{opacity:.42;pointer-events:none}

.field{padding:0 16px 12px}
.field label{
  display:block;font-size:var(--t-micro);line-height:var(--lh-micro);
  color:var(--ink-2);margin-bottom:6px;
}
.field input,.field select,.field textarea{
  width:100%;padding:9px 11px;
  background:var(--bg);color:var(--ink);
  border:1px solid var(--line-strong);border-radius:var(--r);
  font-size:var(--t-body);font-family:inherit;
  transition:border-color var(--t-fast) var(--out),box-shadow var(--t-fast) var(--out);
}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--ink);box-shadow:0 0 0 3px var(--s20);
}
.field textarea{resize:vertical;min-height:66px}
.field input.bad{border-color:var(--signal)}
.field .hint{
  font-family:var(--mono);font-size:var(--t-micro);color:var(--ink-3);
  margin-top:5px;min-height:15px;
}
.field .hint.bad{color:var(--signal)}
.field .hint.ok{color:var(--good)}

/* Segmented control. Two options, so a pair of buttons beats a select. */
.seg{display:flex;gap:0;border:1px solid var(--line-strong);border-radius:var(--r);overflow:hidden}
.seg button{
  flex:1;padding:8px;font-size:var(--t-body);color:var(--ink-2);
  transition:background var(--t-fast) var(--out),color var(--t-fast) var(--out);
}
.seg button + button{border-inline-start:1px solid var(--line-strong)}
.seg button[aria-pressed="true"]{background:var(--ink);color:var(--s0)}

/* ---- detail dock -------------------------------------------------------
   Opening a row must land on the thing itself. Reps were copying a request
   number and searching for it, which is the queue failing at its one job.
   Laptop: the dock takes a column, the table keeps working beside it.
   Phone: it becomes a sheet, because there is no room for two things. */
.app.detail-open{grid-template-columns:var(--rail) minmax(0,1fr) var(--detail)}

.dock{
  grid-column:3;
  background:var(--panel);
  border-inline-start:1px solid var(--line);
  display:none;flex-direction:column;min-height:0;
}
.app.detail-open .dock{display:flex}

.dock-head{
  padding:14px 16px;border-bottom:1px solid var(--line);flex:none;
  display:flex;align-items:flex-start;gap:4px;
}
/* The edit control sits with Close, not in the body: it acts on the whole
   record rather than on any one field. */
.dock-head .x:first-of-type{margin-inline-start:auto}
.dock-head .x + .x{margin-inline-start:0}
.dock-title{font-size:var(--t-mid);line-height:var(--lh-mid);font-weight:600;letter-spacing:-.01em;margin:0}
.dock-sub{font-size:var(--t-micro);line-height:var(--lh-micro);color:var(--ink-3);margin-top:2px}

.dock-body{overflow:auto;flex:1;min-height:0}

/* Actions sit above everything: on a queue row the next move is a call. */
.acts{display:flex;gap:6px;padding:12px 16px;border-bottom:1px solid var(--line)}
.act{
  flex:1;display:flex;align-items:center;justify-content:center;gap:6px;
  padding:8px;border-radius:var(--r);
  border:1px solid var(--line-strong);color:var(--ink);
  font-size:var(--t-body);
  transition:background var(--t-fast) var(--out),border-color var(--t-fast) var(--out);
  text-decoration:none;
}
.act:hover{background:var(--s10)}
.act svg{width:15px;height:15px;stroke-width:1.8}
.act[data-primary]{background:var(--ink);border-color:var(--ink);color:var(--s0)}
.act[data-primary]:hover{opacity:.88;background:var(--ink)}
.act[aria-disabled="true"]{opacity:.4;pointer-events:none}

/* Facts. A definition grid, not sentences: the label is the smallest thing
   on screen and the value carries the weight. */
.facts{display:grid;grid-template-columns:76px 1fr;gap:7px 12px;padding:14px 16px}
.facts dt{font-size:var(--t-micro);line-height:var(--lh-micro);color:var(--ink-3);margin:0}
.facts dd{margin:0;font-size:var(--t-body)}

.sec{border-top:1px solid var(--line);padding:12px 16px}
.sec-h{
  display:flex;align-items:baseline;gap:8px;margin-bottom:8px;
}
.sec-h span{font-size:var(--t-micro);color:var(--ink-3)}
.sec-h b{font-size:var(--t-body);font-weight:600}

.bid-row{
  display:flex;align-items:baseline;gap:10px;
  padding:7px 0;border-bottom:1px solid var(--line);
}
.bid-row:last-child{border-bottom:0}
.bid-who{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bid-amt{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:var(--t-body)}
.bid-unit{font-size:var(--t-micro);color:var(--ink-3)}

/* Timeline. One rail, events hanging off it, newest first. */
.tl{position:relative;padding-inline-start:16px}
.tl::before{
  content:"";position:absolute;inset-inline-start:3px;top:4px;bottom:4px;
  width:1px;background:var(--line);
}
.tl-item{position:relative;padding:6px 0}
.tl-item::before{
  content:"";position:absolute;inset-inline-start:-16px;top:11px;
  width:7px;height:7px;border-radius:var(--r-pill);
  background:var(--s30);
}
.tl-item[data-tone="blemish"]::before{background:var(--signal)}
.tl-item[data-tone="positive"]::before{background:var(--good)}
.tl-what{font-size:var(--t-body)}
.tl-when{font-family:var(--mono);font-size:var(--t-micro);color:var(--ink-3)}

.mini-empty{font-size:var(--t-micro);color:var(--ink-3);padding:2px 0}

@media (max-width:860px){
  .app.detail-open{grid-template-columns:1fr}
  .dock{
    position:fixed;inset-inline:0;bottom:0;top:auto;z-index:30;
    height:min(84dvh,640px);
    border-inline-start:0;border-top:1px solid var(--line);
    border-radius:var(--r) var(--r) 0 0;
    box-shadow:0 -8px 32px rgba(20,23,27,.18);
  }
}

/* ---- phone -------------------------------------------------------------
   Not the design target, but it must not break. The rail leaves, a bottom
   bar arrives with the + in the middle, and the table becomes rows. */
.bar{display:none}

@media (max-width:860px){
  input,select,textarea{font-size:16px}
  .app{grid-template-columns:1fr}
  .rail{display:none}
  .search{width:auto;flex:1;max-width:none}
  .strip{padding-inline:12px}

  /* A wrapping flex line, NOT a grid. Every meta cell is its own <td>, so
     assigning them all to one named grid area stacks them in the same cell
     and they render on top of each other. Flex + an explicit break element
     lets them flow onto a second line instead, and it works for all three
     tables without knowing their columns. */
  .q thead{display:none}
  .q,.q tbody,.q tr,.q td{display:block;width:100%}
  .q tbody tr{
    background:var(--panel);
    border:1px solid var(--line);border-radius:var(--r);
    margin:8px 12px;padding:10px 12px;
    display:flex;flex-wrap:wrap;align-items:center;
    column-gap:10px;row-gap:4px;
    width:auto;
  }
  /* Zero-height full-width item: forces everything after it onto line two. */
  .q tbody tr::after{content:"";flex-basis:100%;height:0;order:3}

  .q td{padding:0;border:0;width:auto;flex:none;order:4}
  .q td:empty{display:none}
  .q td[data-cell="img"]{order:0}
  .q td[data-cell="lead"]{order:1;flex:1 1 auto;min-width:0}
  .q td[data-cell="tick"]{order:2;margin-inline-start:auto}
  .equip{width:44px;height:34px}

  .scroll{padding-bottom:78px}

  .bar{
    display:flex;align-items:center;justify-content:space-around;
    position:fixed;inset-inline:0;bottom:0;z-index:20;
    height:62px;padding-bottom:env(safe-area-inset-bottom);
    background:var(--panel);border-top:1px solid var(--line);
  }
  .bar-item{
    display:flex;flex-direction:column;align-items:center;gap:3px;
    color:var(--ink-3);font-size:var(--t-micro);padding:6px 10px;
    text-decoration:none;
  }
  .bar-item svg{width:19px;height:19px;stroke-width:1.7}
  .bar-item[aria-current="page"]{color:var(--ink)}
  .bar-new{
    width:44px;height:44px;border-radius:var(--r-pill);
    background:var(--ink);color:var(--s0);
    display:grid;place-items:center;
    box-shadow:0 4px 14px rgba(20,23,27,.22);
  }
  .bar-new svg{width:20px;height:20px;stroke-width:2.2}
}
