/* ── the dock: collapsible sections in the frame's own material ─────────── */
.osDock{display:none}
body.os.inthread .osDock{
  position:fixed;top:54px;right:0;bottom:0;width:324px;z-index:11;overflow:auto;
  display:flex;flex-direction:column;gap:4px;padding:14px 12px 92px;
  border-left:1px solid var(--line);background:var(--glass);
  backdrop-filter:blur(26px) saturate(1.3)}
body.os.inthread .osSec{padding:6px 0}
body.os.inthread .osSec + .osSec{border-top:1px solid var(--line)}
body.os.inthread .osSec h4{margin:0}
body.os.inthread .osTog{
  width:100%;display:flex;align-items:center;gap:8px;padding:9px 6px;
  background:none;border:0;cursor:pointer;text-align:left;
  font:500 10px/1 var(--f-body,Inter,sans-serif);letter-spacing:.14em;text-transform:uppercase;
  color:var(--faint)}
body.os.inthread .osTog:hover{color:var(--muted)}
body.os.inthread .osTog .c{
  margin-left:auto;font:400 10px var(--osMono);letter-spacing:0;color:var(--faint)}
body.os.inthread .osTog[aria-expanded="false"] .c::after{content:' ▸'}
body.os.inthread .osBody{display:flex;flex-direction:column;gap:4px;padding:2px 0 6px}

body.os.inthread .osRow{
  display:grid;grid-template-columns:26px minmax(0,1fr) auto;gap:10px;align-items:center;
  padding:7px 8px;border-radius:10px;border:1px solid var(--line);
  text-decoration:none;color:inherit;transition:border-color .14s,background .14s}
/* ⛔ An openable row is a <button> now (it opens the module INSIDE the
   conversation — see row() in os-dock.js), and a button brings its own
   background, font and centred text with it. Reset those, keep the row's own
   grid, and give it the pointer a person expects. The hover rule was written
   for `a.osRow` and would have silently stopped applying. */
body.os.inthread button.osRow{
  width:100%;background:none;font:inherit;text-align:left;cursor:pointer;
  appearance:none;-webkit-appearance:none}
body.os.inthread a.osRow:hover,
body.os.inthread button.osRow:hover{border-color:var(--line2);background:var(--surf)}
body.os.inthread button.osRow:focus-visible{outline:2px solid var(--line2);outline-offset:2px}
body.os.inthread .osRow .ic{width:26px;height:26px;display:block}
body.os.inthread .osRow .ic img{width:100%;height:100%;object-fit:contain;display:block}
body.os.inthread .osRow .tx{min-width:0}
body.os.inthread .osRow .nm{
  display:block;font-size:12.5px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.os.inthread .osRow .d{display:block;font-size:11px;color:var(--muted);margin-top:2px}
/* ⛔ the three states must not look alike */
body.os.inthread .osRow .st{width:7px;height:7px;border-radius:50%;background:var(--surf2)}
body.os.inthread .osRow.s-used{border-color:rgba(94,224,160,.32);background:rgba(94,224,160,.05)}
body.os.inthread .osRow.s-used .st{background:var(--mint)}
body.os.inthread .osRow.s-avail .st{background:var(--line2)}
body.os.inthread .osRow.s-locked{opacity:.72;border-style:dashed}
body.os.inthread .osRow.s-locked .st{background:var(--amber)}
/* ⛔ THIS FILE HELD TWO IDENTICAL COPIES of the whole band/roster block —
   116 lines, byte for byte, at :50 and again at :171. Harmless to render
   (the second simply won) and a trap to edit: a fix applied once looked
   applied and was overridden by its own twin further down. Deleted the
   first copy, 2026-09-10; the comment below survived only there. */
/* ⚡ The door to Team reuses `.osAdd`, the dashed add-control this rail
   already has (work-screen.css:1001 sizes it) — a second one styled the same
   way is a second thing to keep in step. */
/* ── THE THREE BANDS ────────────────────────────────────────────────────────
   Spec: docs/specs/SPEC-RAIL-V4-2026-09-10.md §1. A band is a HEADING over
   sections, not a container that behaves: it does not fold, it does not scroll
   on its own, and it draws nothing when it holds nothing. Sections keep every
   behaviour they had. */
body.os.inthread .osBand{display:flex;flex-direction:column;gap:4px}
body.os.inthread .osBand + .osBand{margin-top:14px}
body.os.inthread .osBandH{
  display:flex;align-items:center;gap:8px;margin:0 0 2px;padding:0 2px;
  font:600 10px/1 var(--osMono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted)}
/* the one mark that says "band", not "section" */
body.os.inthread .osBandH::before{
  content:'';width:14px;height:3px;border-radius:2px;flex:none;
  background:color-mix(in srgb,var(--violet) 55%,transparent)}
body.os.inthread .osBandH .n{
  margin-left:auto;font:400 10px var(--osMono);letter-spacing:0;color:var(--faint)}

/* ── A RUN IN ANOTHER ROOM OF THIS WORKSPACE ────────────────────────────────
   Deliberately shorter and quieter than a run card: it is a pointer to work
   happening elsewhere, and it must never out-shout the work in front of you. */
body.os.inthread .osAway{
  display:grid;grid-template-columns:20px minmax(0,1fr);gap:8px;align-items:center;
  width:100%;background:none;font:inherit;text-align:left;cursor:pointer;
  appearance:none;-webkit-appearance:none;
  padding:6px 8px 7px;border-radius:10px;border:1px solid var(--line);
  transition:border-color .14s,background .14s}
body.os.inthread .osAway:hover{border-color:var(--line2);background:var(--surf)}
body.os.inthread .osAway:focus-visible{outline:2px solid var(--line2);outline-offset:2px}
body.os.inthread .osAway .ic{width:20px;height:20px;display:block}
body.os.inthread .osAway .ic img{width:100%;height:100%;object-fit:contain;display:block}
body.os.inthread .osAway .tx{min-width:0}
body.os.inthread .osAway .nm{
  display:block;font-size:12px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.os.inthread .osAway .d{
  display:block;font:400 10px var(--osMono);color:var(--muted);margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ⛔ A failed run elsewhere still reads as needing a person — it is the one
   thing on this row a person can actually unblock. */
body.os.inthread .osAway.s-needs-you{border-color:var(--amber);background:color-mix(in srgb,var(--amber) 6%,transparent)}
/* the bar spans both columns, under the text */
body.os.inthread .osAwayBar{
  grid-column:1 / -1;height:3px;border-radius:2px;overflow:hidden;
  background:color-mix(in srgb,var(--ink) 8%,transparent);margin-top:5px}
body.os.inthread .osAwayBar i{display:block;height:100%;border-radius:2px;background:var(--violet)}
/* ⛔ NO INVENTED PERCENTAGE. Without a real `pct` the bar sweeps instead of
   filling — an indeterminate bar says "working", a fake 40% says something we
   did not measure. Reuses the boot loader's own sweep. */
body.os.inthread .osAwayBar.ind i{width:38%;animation:bcLoaderSweep 1.15s ease-in-out infinite}
@media (prefers-reduced-motion: reduce){
  body.os.inthread .osAwayBar.ind i{animation:none;width:100%;opacity:.45}
}
body.os.inthread .osMore{
  padding:2px 8px;font:400 10px var(--osMono);color:var(--faint)}

/* ── WHO WORKS IN THIS ROOM ──────────────────────────────────────────────────
   People and hired specialists share ONE row grammar, because they share one
   roster. The face column is 32 px rather than the tool rows' 26: a character
   at 26 is a smudge, and the whole point of the portraits is that a colleague
   is recognisable at a glance. */
body.os.inthread .osMate{
  display:grid;grid-template-columns:32px minmax(0,1fr);gap:10px;align-items:center;
  padding:6px 8px;border-radius:10px;border:1px solid var(--line);
  text-decoration:none;color:inherit;transition:border-color .14s,background .14s}
body.os.inthread button.osMate{
  width:100%;background:none;font:inherit;text-align:left;cursor:pointer;
  appearance:none;-webkit-appearance:none}
body.os.inthread button.osMate:hover{border-color:var(--line2);background:var(--surf)}
body.os.inthread button.osMate:focus-visible{outline:2px solid var(--line2);outline-offset:2px}
body.os.inthread .osMate .tx{min-width:0}
body.os.inthread .osMate .nm{
  display:flex;align-items:center;gap:5px;font-size:12.5px;color:var(--ink);
  overflow:hidden;white-space:nowrap}
body.os.inthread .osMate .d{
  display:block;font-size:11px;color:var(--muted);margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ⛔ A paused colleague is not a dead one, and must not read as an error. */
body.os.inthread .osMate.s-avail{opacity:.66}

/* The clay tile. It ALWAYS carries readable initials; the cast list below
   paints over them for the roles whose portrait is actually on disk. There is
   no <img>, so a role we have not drawn cannot produce a broken picture. */
body.os.inthread .osFace{
  width:32px;height:32px;border-radius:11px;display:grid;place-items:center;flex:none;
  background:color-mix(in srgb,var(--violet) 16%,var(--panel));color:var(--ink);
  font:700 12px var(--osDisp);letter-spacing:.02em;
  background-size:cover;background-position:50% 12%;background-repeat:no-repeat;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6)}
/* ⛔ THE CAST LIST IS DECLARED. Add a role here only when
   /art/os/sp-<role>.png exists — the mechanism os-specialists.css uses, and
   the reason there is no onerror handler anywhere in this lane.
   ⚡ `color:transparent` hides the initials only once a background has
      actually been set, so the fallback survives a failed network fetch. */
body.os.inthread .osFace[data-art="sp-accountant"],
body.os.inthread .osFace[data-art="sp-company-analyst"],
body.os.inthread .osFace[data-art="sp-cto"],
body.os.inthread .osFace[data-art="sp-financial-advisor"],
body.os.inthread .osFace[data-art="sp-lawyer"],
body.os.inthread .osFace[data-art="sp-operations-lead"],
body.os.inthread .osFace[data-art="sp-sales-lead"]{color:transparent}
body.os.inthread .osFace[data-art="sp-accountant"]{background-image:url(/art/os/sp-accountant-64.png)}
body.os.inthread .osFace[data-art="sp-company-analyst"]{background-image:url(/art/os/sp-company-analyst-64.png)}
body.os.inthread .osFace[data-art="sp-cto"]{background-image:url(/art/os/sp-cto-64.png)}
body.os.inthread .osFace[data-art="sp-financial-advisor"]{background-image:url(/art/os/sp-financial-advisor-64.png)}
body.os.inthread .osFace[data-art="sp-lawyer"]{background-image:url(/art/os/sp-lawyer-64.png)}
body.os.inthread .osFace[data-art="sp-operations-lead"]{background-image:url(/art/os/sp-operations-lead-64.png)}
body.os.inthread .osFace[data-art="sp-sales-lead"]{background-image:url(/art/os/sp-sales-lead-64.png)}

/* ⛔ THE `AI` CHIP IS PERMANENT AND IS NOT A HOVER (EU AI Act Art. 50(1)).
   It must survive a narrow rail, so it never shrinks and never ellipses: the
   NAME truncates around it. */
body.os.inthread .osMate .osAI{
  flex:none;font:700 9px/1.5 var(--osMono);letter-spacing:.1em;
  padding:1px 5px;border-radius:var(--r-pill);
  background:color-mix(in srgb,var(--violet) 14%,var(--panel));color:var(--ink);
  border:1px solid color-mix(in srgb,var(--violet) 55%,var(--line2))}

/* ⚡ The door to Team reuses `.osAdd` — the dashed add-control this rail
   already has, at :394 and sized by work-screen.css:1001. A second one styled
   the same way is a second thing to keep in step. */

body.os.inthread .osEmpty{
  border:1px dashed var(--line);border-radius:10px;padding:10px 11px;
  font-size:11.5px;color:var(--faint);line-height:1.45}

/* ── the anonymous shelf ─────────────────────────────────────────────────────
   The same structure an account's rail has, at a smaller size: a heading with
   the count against the cap, one row per topic, and the button that adds one.
   ⛔ The button stays visible at the cap, disabled and titled — a control that
   disappears reads as a feature that broke. */
body.os.inthread .osShelf{margin:14px 0 4px;display:flex;flex-direction:column;gap:4px}
body.os.inthread .osShelfTtl{display:flex;align-items:baseline;justify-content:space-between;
  font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--faint);
  margin:0 2px 6px;font-weight:500}
body.os.inthread .osShelfTtl span{font-family:var(--mono,ui-monospace);font-size:10.5px;letter-spacing:0}
body.os.inthread .osIdea{display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;
  background:none;border:1px solid transparent;border-radius:10px;padding:7px 9px;cursor:pointer;
  color:inherit;font:inherit;transition:background .14s,border-color .14s}
body.os.inthread .osIdea:hover{background:var(--surf);border-color:var(--line)}
body.os.inthread .osIdea.on{background:var(--surf);border-color:var(--line2)}
body.os.inthread .osIdea b{flex:1;min-width:0;font-size:12.5px;font-weight:450;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.os.inthread .osIdea span{font-family:var(--mono,ui-monospace);font-size:10.5px;color:var(--faint)}
body.os.inthread .osNew{width:100%;text-align:left;background:none;border:1px dashed var(--line);
  border-radius:10px;padding:7px 9px;margin-top:2px;font:inherit;font-size:12px;color:var(--muted);
  cursor:pointer}
body.os.inthread .osNew:hover:not([disabled]){border-color:var(--line2);color:var(--ink)}
body.os.inthread .osNew[disabled]{opacity:.45;cursor:default}

/* ── the Notiek / In progress rows ───────────────────────────────────────────
   ⛔ `needs-you` must not look like the others: the one thing a person can
   unblock is the one thing they have to notice. */
body.os.inthread .osRun .ic{position:relative}
body.os.inthread .osRun .ic.spin::after{
  content:'';position:absolute;inset:4px;border-radius:50%;
  border:2px solid var(--line2);border-top-color:var(--acc,var(--ink));
  animation:osRunSpin 1s linear infinite}
@keyframes osRunSpin{to{transform:rotate(360deg)}}
body.os.inthread .osRow.osRun.s-locked{
  border-style:solid;border-color:var(--amber,#e0922f);
  background:color-mix(in srgb,var(--amber,#e0922f) 9%,transparent);opacity:1}
body.os.inthread .osRow.osRun.s-locked .st{background:var(--amber,#e0922f)}
body.os.inthread .osRow.osRun.s-bad{border-color:rgba(224,90,90,.42)}
body.os.inthread .osRow.osRun.s-bad .st{background:#e05a5a}
body.os.inthread .osRun .d{font-family:var(--osMono,ui-monospace)}
body.os.inthread .osRow.osRun{position:relative;overflow:hidden;min-height:66px;
  border-color:color-mix(in srgb,var(--violet,#8b6eff) 28%,var(--line));
  background:linear-gradient(135deg,color-mix(in srgb,var(--violet,#8b6eff) 10%,transparent),
    color-mix(in srgb,var(--sky,#22d3ee) 6%,transparent))}
body.os.inthread .osRun .ic{display:grid;place-items:center;color:var(--violet,#8b6eff);font-size:18px}
body.os.inthread .osRunBar{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px;align-items:center;margin-top:7px}
body.os.inthread .osRunBar::before{content:'';grid-column:1;grid-row:1;height:4px;border-radius:99px;background:var(--surf2)}
body.os.inthread .osRunBar i{grid-column:1;grid-row:1;height:4px;border-radius:99px;z-index:1;
  background:linear-gradient(90deg,var(--violet,#8b6eff),var(--sky,#22d3ee))}
body.os.inthread .osRunBar b{font:500 9px var(--osMono,ui-monospace);color:var(--faint)}

/* A selected goal is a small dashboard, not another grey tool row. The hue is
   bound to its category and never to position, count or progress. */
body.os.inthread .osGoal{--cat:hsl(215 10% 52%);display:grid;grid-template-columns:9px minmax(0,1fr) auto;
  gap:9px;align-items:center;width:100%;padding:9px 10px;border:1px solid color-mix(in srgb,var(--cat) 35%,var(--line));
  border-radius:11px;background:color-mix(in srgb,var(--cat) 7%,transparent);color:inherit;text-align:left;font:inherit;cursor:pointer}
body.os.inthread .osGoal.cat-product{--cat:hsl(268 62% 62%)} body.os.inthread .osGoal.cat-tech{--cat:hsl(199 72% 52%)}
body.os.inthread .osGoal.cat-growth{--cat:hsl(152 52% 45%)} body.os.inthread .osGoal.cat-marketing{--cat:hsl(24 82% 57%)}
body.os.inthread .osGoal.cat-ops{--cat:hsl(212 45% 58%)} body.os.inthread .osGoal.cat-money{--cat:hsl(46 78% 48%)}
body.os.inthread .osGoal.cat-people{--cat:hsl(330 58% 60%)} body.os.inthread .osGoal.cat-risk{--cat:hsl(2 68% 58%)}
body.os.inthread .osGoalDot{width:8px;height:8px;border-radius:3px;background:var(--cat);box-shadow:0 0 14px color-mix(in srgb,var(--cat) 55%,transparent)}
body.os.inthread .osGoalCopy{min-width:0} body.os.inthread .osGoalCopy strong{display:block;font-size:12.5px;font-weight:550;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.os.inthread .osGoalCopy small{display:block;margin-top:2px;font-size:10.5px;color:var(--muted)}
body.os.inthread .osGoalBar{display:block;height:3px;margin-top:7px;border-radius:99px;background:var(--surf2);overflow:hidden}
body.os.inthread .osGoalBar i{display:block;height:100%;border-radius:inherit;background:var(--cat)}
body.os.inthread .osGoalGo{color:var(--cat);font-size:18px}
/* ⚡ v5: a row whose --cat comes from the SERVED field hue sets it INLINE, so
   it already beats every cat-* class above without a rule here.
   ⚠ cat-* paints bc_goal.category (eight values); the inline hue paints
   bc_goal.field (ten). Two real columns — colour was made to mean FIELD so
   one goal is not two colours on two surfaces. ⛔ Do not add a ninth cat-*. */
/* ⛔ THE TITLE TAKES TWO LINES INSTEAD OF ELLIPSING. In a 296px dock column
   "Work system — every goal of the company" rendered as "Work system — every…"
   and every long goal looked like every other one (owner, 2026-09-08). */
body.os.inthread .osGoalCopy strong{white-space:normal;display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.3}

body.os.inthread .osPerson{display:grid;grid-template-columns:38px minmax(0,1fr) auto;gap:10px;align-items:center;
  width:100%;padding:11px;border:1px solid color-mix(in srgb,var(--violet,#8b6eff) 24%,var(--line));border-radius:13px;
  background:linear-gradient(135deg,color-mix(in srgb,var(--violet,#8b6eff) 9%,transparent),color-mix(in srgb,var(--sky,#22d3ee) 5%,transparent));
  color:inherit;text-align:left;font:inherit;cursor:pointer}
body.os.inthread .osPersonAvatar{width:38px;height:38px;border-radius:12px;display:grid;place-items:center;color:#fff;
  font:650 11px var(--osMono,ui-monospace);background:linear-gradient(135deg,var(--violet,#8b6eff),var(--sky,#22d3ee))}
body.os.inthread .osPersonCopy{min-width:0} body.os.inthread .osPersonCopy strong{display:block;font-size:13px;color:var(--ink)}
body.os.inthread .osPersonCopy small{display:block;margin:3px 0;color:var(--muted);font-size:10.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.os.inthread .osPersonCopy span{font:400 9.5px var(--osMono,ui-monospace);color:var(--faint)}
body.os.inthread .osPersonGo{font-size:19px;color:var(--violet,#8b6eff)}


/* ⚡ ONE BUTTON UNDER THE TOOLS, not a second list above them. Adding a lane to
   a room is an ACTION, and an action rendered as a row reads as a thing that is
   already there. */
body.os.inthread .osAdd{display:block;width:100%;margin:6px 0 2px;padding:8px 10px;
  border:1px dashed var(--line2);border-radius:9px;background:none;cursor:pointer;
  color:var(--faint);font:500 11.5px/1.3 var(--f-body,Inter,sans-serif);text-align:left}
body.os.inthread .osAdd:hover{color:var(--ink);border-color:var(--fill-2);background:var(--surf)}

/* ── THE ROOM SUMMARY ──────────────────────────────────────────────────────
   ⚡ Replaces the three context rows that printed the visitor's browser
   language and IP market under a heading that said "in this conversation"
   (2026-09-10). Each row is a picture, a fact, why it is here, and — when it
   goes somewhere — a chevron. ⛔ A row with no door draws no chevron: the
   affordance is the promise, and a promise this panel cannot keep is how a
   person learns the whole rail is decoration. */
body.os.inthread .osSum{display:flex;flex-direction:column;gap:2px}
body.os.inthread .osSumRow{display:flex;align-items:center;gap:8px;width:100%;padding:5px 6px;
  border:0;border-radius:8px;background:transparent;text-align:left;font:inherit;color:inherit}
body.os.inthread button.osSumRow{cursor:pointer}
body.os.inthread button.osSumRow:hover{background:var(--surf2,rgba(0,0,0,.04))}
body.os.inthread button.osSumRow:focus-visible{outline:2px solid var(--violet);outline-offset:1px}
body.os.inthread .osSumRow .ic{flex:0 0 22px;width:22px;height:22px;display:grid;place-items:center}
body.os.inthread .osSumRow .ic img{width:22px;height:22px;object-fit:contain;display:block}
body.os.inthread .osSumRow .tx{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
body.os.inthread .osSumRow .nm{font-size:12.5px;font-weight:550;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.os.inthread .osSumRow .d{font-size:10.5px;color:var(--faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.os.inthread .osSumRow .go{flex:0 0 auto;font-size:13px;color:var(--faint);opacity:.6}
body.os.inthread button.osSumRow:hover .go{opacity:1;color:var(--violet)}
/* ⛔ `avail` is the row whose fact is ABSENT — a room with no goals read, one
   that has never spoken. It is dimmed, never hidden and never a zero. */
body.os.inthread .osSumRow.s-avail .nm{color:var(--faint);font-weight:500}
