:root{
  /* TRACKING IS SIZE-SPECIFIC. One letter-spacing across a whole interface is
     wrong somewhere: large text reads too loose as it grows, small text too
     tight to separate. So the ramp is negative at the top, zero through body,
     and slightly positive at the floor — paired with leading that tightens as
     size grows. (Apple, The Details of UI Typography.) */
  --track-display:-0.022em;
  --track-xl:-0.015em;
  --track-lg:-0.01em;
  --track-md:0em;
  --track-sm:0em;
  --track-xs:0.006em;
  --lead-display:1.04;
  --lead-heading:1.2;
  --lead-body:1.55;
  --lead-dense:1.45;
  /* One hairline, everywhere. A border is either structure or it is noise. */
  /* A 4px RHYTHM. MEASURED before this: 35 distinct pixel values across
     padding, margin and gap — every panel picked what looked right next to
     whatever was beside it, so nothing lined up with anything a row away.
     Six steps, and the containers below read from them. */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  /* One elevation, not five hand-mixed shadows. */
  --lift:0 18px 50px -20px rgba(0,0,0,.6);
  --hairline:1px solid var(--border-subtle);

  --bg:#08090a;--panel:#0f1011;--surface:#151617;--raised:#191a1b;--hover:#202124;
  --text:#f7f8f8;--secondary:#d0d6e0;--muted:#8a8f98;--subtle:#62666d;
  --accent:#5e6ad2;--accent-hi:#7170ff;--green:#10b981;--red:#ef6b73;
  --border:rgba(255,255,255,.08);--border-subtle:rgba(255,255,255,.05);

  /* THE TYPE SCALE. Five steps, and everything reads from them.

     MEASURED before this: 20 distinct sizes across 88 declarations, from 8px
     to 31px, with seventeen of them between 8 and 18. That is not a scale, it
     is accumulation — each screen picked a size that looked right next to the
     one beside it, and nothing ever picked the same one twice.

     The floor is 11.5px. Below that was .fine-print at 8px in #4b4e54 on a
     #08090a ground, which is not small text, it is hidden text; and 9px on
     .message-time, .composer-hint and .project-state — the last of which now
     carries the state label, the single most important word on the screen.

     Fewer sizes means weight and colour have to carry hierarchy instead. That
     is the point: --secondary/--muted/--subtle already exist and were doing
     almost nothing, while size was doing everything. */
  --text-xs:11.5px;    /* meta, labels, chips, timestamps — the floor */
  --text-sm:13px;      /* secondary UI: list rows, buttons, notes */
  --text-md:14.5px;    /* body: messages, inputs, anything read in prose */
  --text-lg:17px;      /* leads and subheads */
  --text-xl:21px;      /* section and dialog titles */

  /* Display is a separate role, not a sixth step: these are set once each, on
     a hero, and they scale with the viewport rather than sitting on the ramp. */
  --text-display:clamp(32px,4vw,48px);
  --text-display-lg:clamp(40px,5.2vw,68px);
  --text-display-sm:clamp(26px,3.2vw,31px);
}
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:var(--bg);color:var(--text);font-family:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;font-feature-settings:"cv01","ss03";overflow:hidden}
button,input,textarea{font:inherit}
button{color:inherit}
[hidden]{display:none!important}
.brand{display:inline-flex;align-items:center;gap:10px;color:var(--text);text-decoration:none;font-size:var(--text-md);font-weight:590;letter-spacing:-.15px}
.brand-mark{width:28px;height:28px;display:grid;place-items:center;border-radius:8px;background:linear-gradient(145deg,#7f83ff,#4f55bc);box-shadow:inset 0 1px rgba(255,255,255,.22),0 8px 24px rgba(94,106,210,.22);font-size:var(--text-sm);font-weight:600}
.brand.compact .brand-mark{width:25px;height:25px;border-radius:7px;font-size:var(--text-sm)}
.overline{font-family:'JetBrains Mono',monospace;font-weight:500;font-size:var(--text-xs);line-height:1.4;letter-spacing:.12em;color:var(--muted);margin:0 0 12px}
.live-dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--green);box-shadow:0 0 0 3px rgba(16,185,129,.12)}
.primary,.ghost{border:1px solid var(--border);border-radius:7px;padding:10px 16px;font-size:var(--text-sm);font-weight:510;cursor:pointer;transition:.18s ease}
.primary{background:var(--accent);border-color:var(--accent);color:white;box-shadow:inset 0 1px rgba(255,255,255,.16)}
.primary:hover{background:var(--accent-hi);transform:translateY(-1px)}
.primary:disabled{opacity:.5;transform:none;cursor:not-allowed}
.primary.full{width:100%;padding:12px 16px}
.ghost{background:rgba(255,255,255,.03)}
.ghost:hover{background:rgba(255,255,255,.06)}
.auth-layout{min-height:100%;display:grid;grid-template-columns:minmax(0,1.1fr) minmax(430px,.9fr)}
.auth-story{position:relative;display:flex;flex-direction:column;padding:34px 48px 40px;overflow:hidden;border-right:1px solid var(--border-subtle);background:
 radial-gradient(700px 500px at 70% 40%,rgba(94,106,210,.16),transparent 62%),
 radial-gradient(500px 400px at 20% 95%,rgba(57,73,171,.10),transparent 68%),var(--bg)}
.auth-story:after{content:"";position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,.018) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.018) 1px,transparent 1px);background-size:48px 48px;mask-image:linear-gradient(to bottom,transparent,black 25%,black 75%,transparent);pointer-events:none}
.story-copy{position:relative;z-index:1;margin:auto 0;max-width:720px}
.eyebrow{display:flex;align-items:center;gap:10px;color:var(--secondary);font-size:var(--text-sm);margin-bottom:25px}
.story-copy h1{margin:0;font-size:var(--text-display-lg);line-height:var(--lead-display);letter-spacing:var(--track-display);font-weight:510;text-wrap:balance}
.story-copy h1 span{color:var(--muted)}
.story-copy>p{max-width:610px;margin:28px 0 0;font-size:var(--text-lg);line-height:1.65;color:var(--muted);font-weight:300}
.story-proof{position:relative;z-index:1;display:grid;grid-template-columns:repeat(3,1fr);gap:20px;padding-top:28px;border-top:1px solid var(--border-subtle)}
.story-proof div{display:flex;flex-direction:column;gap:5px}
.story-proof strong{font-size:var(--text-sm);font-weight:510;color:var(--secondary)}
.story-proof span{font-size:var(--text-xs);line-height:1.5;color:var(--subtle)}
.auth-panel{display:grid;place-items:center;padding:40px;background:var(--panel)}
.auth-card{width:min(370px,100%)}
.mobile-brand{display:none;margin-bottom:56px;font-weight:590;align-items:center;gap:10px}
.auth-card h2{font-size:var(--text-display-sm);line-height:var(--lead-heading);letter-spacing:var(--track-display);font-weight:510;margin:0 0 8px}
.auth-sub{font-size:var(--text-md);color:var(--muted);margin:0 0 30px}
label{display:block;font-size:var(--text-sm);font-weight:510;color:var(--secondary);margin:0 0 15px}
input,textarea{width:100%;background:rgba(255,255,255,.025);color:var(--text);border:1px solid var(--border);border-radius:7px;outline:none;transition:.16s ease}
input{display:block;margin-top:7px;padding:11px 12px;font-size:var(--text-md)}
input:focus,textarea:focus{border-color:rgba(113,112,255,.68);box-shadow:0 0 0 3px rgba(113,112,255,.1)}
input::placeholder,textarea::placeholder{color:var(--subtle)}
.form-error{min-height:18px;color:var(--red);font-size:var(--text-sm);margin:-4px 0 9px}
.switch-copy{text-align:center;color:var(--muted);font-size:var(--text-sm);margin:19px 0 0}
.text-button{border:0;background:none;color:var(--secondary);font-size:var(--text-sm);font-weight:510;padding:0;cursor:pointer}
.text-button:hover{color:var(--text)}
.shell{display:grid;grid-template-columns:220px minmax(0,1fr) 320px;height:100%}
.sidebar{display:flex;flex-direction:column;background:var(--panel);border-right:1px solid var(--border-subtle);min-width:0}
.sidebar-top{padding:var(--s3) var(--s3) var(--s2);border-bottom:1px solid var(--border-subtle)}
.sidebar-top .brand{padding:2px 8px 16px}
.new-project{display:flex;align-items:center;gap:9px;width:100%;border:1px solid var(--border);background:rgba(255,255,255,.025);padding:9px 10px;border-radius:7px;font-size:var(--text-sm);font-weight:510;cursor:pointer;color:var(--secondary)}
.new-project:hover{background:rgba(255,255,255,.055);color:var(--text)}
svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.project-nav{flex:1;overflow:auto;padding:var(--s3) var(--s2)}
/* MEASURED at a 220px rail: "YOUR PROJECTS" plus the "2 need you" badge came to
   191px against 188px of room, so the badge broke onto a second line and the
   heading became two ragged rows. Narrowing the rail from 252px is what did it.
   The badge never wraps — it is a count, and a count on two lines is not one —
   and the label gives way first. */
.nav-heading{display:flex;align-items:center;gap:8px;min-width:0;
 padding:0 7px 8px;color:var(--subtle);font-size:var(--text-xs);font-weight:510;
 text-transform:uppercase;letter-spacing:.08em;white-space:nowrap;overflow:hidden}
.project-link{display:flex;align-items:flex-start;gap:var(--s2);width:100%;padding:var(--s2) var(--s2);border:0;border-radius:7px;
 background:none;color:var(--muted);text-align:left;cursor:pointer;overflow:hidden}
.project-link .state-dot{margin-top:5px}
.project-body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.project-name{font-size:var(--text-sm);color:var(--secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.project-link.active .project-name{color:var(--text)}
/* The metadata line is the dashboard. It is deliberately the floor step and
   the quietest colour: it is scanned, not read, and it must never compete
   with the project name beside it. */
.project-meta{font-size:var(--text-xs);color:var(--subtle);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.project-link:hover .project-meta{color:var(--muted)}
/* The state now lives on the meta line rather than in a badge that was eating
   the name's width. It keeps the attention tone so the row still answers "does
   this need me?" at a glance, without costing 70px to say it. */
.project-meta.yours{color:var(--tone-attention)}
.project-link:hover .project-meta.yours{color:var(--tone-attention)}
/* The rotated-square marker was replaced by .state-dot — see the block below. */
.project-link span{overflow:hidden;text-overflow:ellipsis}
/* The row exists so the delete control sits beside the open button rather
   than inside it; a nested button would open the project on every click. */
.project-row{display:flex;align-items:center;gap:2px}
.project-row .project-link{flex:1;min-width:0}
.project-delete{flex:none;width:22px;height:22px;padding:0;border:0;border-radius:5px;background:none;color:var(--subtle);font-size:var(--text-md);line-height:1;cursor:pointer;opacity:0;transition:opacity .12s}
/* Revealed on hover or keyboard focus. focus-visible is not optional: an
   opacity-0 control is unreachable by keyboard without it. */
.project-row:hover .project-delete,.project-delete:focus-visible{opacity:1}
.project-delete:hover{background:var(--danger-bg,#3a1c1c);color:var(--danger,#ff6b6b)}
.project-link:hover{background:rgba(255,255,255,.035);color:var(--secondary)}
.project-link.active{background:rgba(255,255,255,.06);color:var(--text)}
.project-link.active{box-shadow:inset 2px 0 var(--accent-hi)}
.empty-projects{font-size:var(--text-xs);color:var(--subtle);padding:8px 9px;line-height:1.55}
.sidebar-user{display:flex;align-items:center;gap:var(--s2);padding:var(--s3);border-top:1px solid var(--border-subtle)}
.avatar{width:27px;height:27px;border-radius:7px;display:grid;place-items:center;background:#25262a;color:var(--secondary);font-size:var(--text-xs);font-weight:600}
.user-meta{min-width:0;display:flex;flex:1;flex-direction:column;gap:1px}
.user-meta span{font-size:var(--text-xs);color:var(--secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.user-meta small{font-size:var(--text-xs);color:var(--subtle)}
.icon-button{display:grid;place-items:center;border:0;background:transparent;color:var(--subtle);padding:6px;border-radius:6px;cursor:pointer}
.icon-button:hover{background:rgba(255,255,255,.05);color:var(--secondary)}
.workspace{position:relative;display:grid;grid-template-rows:58px minmax(0,1fr) auto;background:var(--bg);min-width:0;min-height:0;overflow:hidden}
.topbar{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,auto) minmax(max-content,1fr);align-items:center;gap:var(--s4);padding:0 var(--s2) 0 var(--s3);border-bottom:1px solid var(--border-subtle);background:rgba(8,9,10,.82);backdrop-filter:blur(16px);z-index:3;
 /* The bright inset hairline is what makes a translucent bar read as a pane of
    material catching the light rather than a rectangle of paint. */
 box-shadow:inset 0 1px 0 rgba(255,255,255,.04)}
.project-title{font-size:var(--text-sm);color:var(--secondary);font-weight:510;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.project-state{min-width:150px;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
 /* A budget, so no string a future state invents can grow this track. The full
    text stays reachable as the title. And a FLOOR as well as a ceiling: "Ready"
    is 48px and "Working - 9m 20s" is 82px, so without one the centre group
    changed width the instant a run started and slid the repository pill 17px
    sideways. Reserving the space costs nothing and the bar stops moving. */
 /* Digits that do not change width as they count. An elapsed timer on
    proportional figures reflows the whole centre group every second. */
 font-variant-numeric:tabular-nums;display:flex;align-items:center;gap:7px;font-size:var(--text-xs);color:var(--subtle);margin-top:2px}
.ghost-button{margin-left:auto;border:1px solid var(--border-subtle);background:rgba(255,255,255,.03);color:var(--subtle);font:inherit;font-size:var(--text-xs);padding:5px 10px;border-radius:6px;cursor:pointer;white-space:nowrap}
.ghost-button:hover:not(:disabled){background:rgba(255,255,255,.06);color:var(--secondary)}
.ghost-button:disabled{opacity:.55;cursor:progress}
.ghost-button[hidden]{display:none}
.ghost-button.danger{color:#e5484d;border-color:rgba(229,72,77,.35)}
.ghost-button.danger:hover:not(:disabled){background:rgba(229,72,77,.10);color:#ff6369}
.ghost-button + .ghost-button{margin-left:8px}
/* A GRID, not a flex row with margin-left:auto scattered through it. Three
   tracks: the outer two share what is left after the middle takes what it
   needs, so the centre group is centred against the WINDOW rather than against
   whatever happens to be beside it. A project name growing by ten characters
   no longer slides the status indicator sideways. */
/* EVERY TRACK CAN SHRINK, AND EVERY GROUP CLIPS ITS OWN CONTENT.
   MEASURED: a quiet run puts "Working - 9m 20s - no activity for 5m - you can
   press Stop and try again" in the centre. With an `auto` centre track that
   string grew to 431px, squeezed the outer tracks, and rendered 120px ON TOP OF
   the credit badge. minmax(0,auto) lets the track shrink; overflow:hidden makes
   the group clip rather than spill; and the ellipsis makes the clip legible.
   Nothing in this bar can paint over its neighbour now. */
.topbar-group{display:flex;align-items:center;gap:9px;min-width:0;overflow:hidden}
/* THE RIGHT TRACK NEVER SHRINKS BELOW ITS CONTENT — minmax(max-content,1fr).
   MEASURED: with three symmetric 1fr tracks the centre group asked for 674px,
   squeezed this track to 89px, and its children (226px of badge, button and
   toggle) spilled LEFT out of it — the credit badge landed at x=868, inside the
   centre group's span, painting over the status underneath it. The badge, the
   Upgrade button and the rail toggle are fixed chrome; they are the last thing
   that should give way. When there is slack both outer tracks are equal 1fr and
   the centre is window-centred; when there is not, the centre gives way and
   ellipses, which is the only thing here that can afford to. */
.topbar-group.end{flex:none}
.topbar-group.middle{justify-content:center}
.topbar-group.end{justify-content:flex-end}
/* THE TWO RAIL TOGGLES, one at each end of the same bar. Mirrored glyphs, one
   shape, and neither ever moves — which is the whole point: the control that
   collapses a rail must not be inside the rail it collapses. */
.rail-toggle{display:inline-grid;place-items:center;flex:none;width:28px;height:28px;border:1px solid transparent;border-radius:7px;
 background:none;color:var(--subtle);cursor:pointer;transition:.15s ease}
.rail-toggle:hover{color:var(--text);background:rgba(255,255,255,.05);border-color:var(--border-subtle)}
.rail-toggle svg{width:15px;height:15px}
/* THE REPOSITORY, as a badge rather than a button pretending to be a menu. */
.repo-pill{display:inline-flex;align-items:center;gap:7px;max-width:260px;flex:none;
 border:1px solid var(--border-subtle);background:rgba(255,255,255,.03);border-radius:999px;padding:4px 11px;
 color:var(--muted);font-size:var(--text-xs);font-family:inherit;font-weight:510;cursor:pointer;transition:.15s ease}
.repo-pill:hover{color:var(--text);border-color:var(--border)}
.repo-pill span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.repo-pill .gh-mark{width:13px;height:13px;flex:none;fill:currentColor;stroke:none;opacity:.8}
.repo-pill.connected{color:var(--secondary)}
.mobile-menu{display:none}
/* THE COMPOSER FLOATS OVER THE BOTTOM ~155px of the workspace, and this screen
   never accounted for it. MEASURED at 1280x860: 943px of content in an 802px
   row, `align-self:center` overflowing at both ends and .workspace's
   overflow:hidden clipping it — the orb drawn behind the top bar and the one
   call to action on the first screen a customer ever sees drawn UNDER the
   composer. At 720px it was 100px under.

   Padding could not fix it: padding inside a scroller is only reachable by
   scrolling INTO the area the composer covers. So the box itself stops where
   the composer starts — `margin-bottom` reserves the strip and `max-height`
   keeps the box out of it — and the box centres in what is left. Content that
   still does not fit scrolls, and every pixel it scrolls through is visible. */
/* THE FIRST SCREEN, WITH ROOM TO BREATHE.
   MEASURED at 1600x750 — a real window, not a tall one: the content overflowed
   by 139px and "Connect a repository" sat 20px UNDER the composer, so the one
   action on the screen was the one thing you could not reach. Two causes: the
   clearance was a hard-coded 155px against a composer that is 186px and grows,
   and the content itself was a stack of ten blocks.
   The clearance is now the measured one, shared with the conversation. */
/* THE SAME SHAPE AS THE CONVERSATION, which is what makes the two pages look
   like one product.
   This was a 720px BOX centred in the workspace with its own overflow, so its
   scrollbar drew a hard vertical rule ~330px in from the right and left dead
   space beyond it. That edge reads as a panel — one that cannot be opened or
   closed, because it is not a panel, it is the gap beside a fixed-width box.
   Five rounds of fixing the actual repair panel changed nothing a customer
   could see, because the thing they were pointing at was this.
   It stretches now and centres its content with inline padding, exactly like
   .conversation: the scroll edge is the window edge, and the column lands in
   the same place whether or not a project is open. */
.empty-state{justify-self:stretch;align-self:center;width:100%;text-align:center;
 padding:var(--s6) max(var(--s5),calc((100% - 720px)/2)) var(--s4);
 margin-bottom:var(--composer-clearance,186px);
 max-height:calc(100% - var(--composer-clearance,186px));
 overflow-y:auto}
.engineer-orb{width:44px;height:44px;margin:0 auto var(--s4);border:1px solid var(--border);border-radius:15px;background:radial-gradient(circle at 35% 30%,rgba(139,143,255,.32),rgba(94,106,210,.08) 55%,rgba(255,255,255,.02));display:grid;place-items:center;box-shadow:0 20px 70px rgba(94,106,210,.14),inset 0 1px rgba(255,255,255,.12)}
.engineer-orb span{font-size:var(--text-md);font-weight:600;color:#c5c7ff}
.empty-state h1{font-size:var(--text-display);line-height:1.08;letter-spacing:-1.05px;font-weight:510;margin:0}
.empty-state>p:not(.overline){max-width:540px;margin:var(--s4) auto var(--s5);color:var(--muted);font-size:var(--text-md);line-height:1.65;font-weight:300}
.examples{display:flex;justify-content:center;flex-wrap:wrap;gap:var(--s2)}
.examples button{border:1px solid var(--border-subtle);background:rgba(255,255,255,.018);color:var(--muted);padding:7px 11px;border-radius:999px;font-size:var(--text-xs);cursor:pointer}
.examples button:hover{color:var(--secondary);border-color:var(--border);background:rgba(255,255,255,.04)}
.conversation{min-height:0;overflow:auto;padding:35px max(24px,calc((100% - 760px)/2)) 170px;scroll-behavior:smooth}
.message{display:grid;grid-template-columns:30px minmax(0,1fr);gap:13px;margin-bottom:28px}
.message-avatar{width:27px;height:27px;border-radius:8px;display:grid;place-items:center;font-size:var(--text-xs);font-weight:600;background:#232428;color:var(--secondary)}
.message.assistant .message-avatar{background:linear-gradient(145deg,rgba(113,112,255,.48),rgba(94,106,210,.18));color:#dedfff;border:1px solid rgba(113,112,255,.2)}
.message-head{font-size:var(--text-xs);font-weight:590;color:var(--secondary);margin:1px 0 7px}
.message-time{font-size:var(--text-xs);font-weight:400;color:var(--subtle);margin-left:7px}
.message-body{font-size:var(--text-md);line-height:1.7;color:var(--secondary);white-space:pre-wrap;overflow-wrap:anywhere}
.activity{display:flex;align-items:center;gap:9px;margin:0 0 21px 43px;color:var(--muted);font-size:var(--text-xs)}
.activity-spinner{width:13px;height:13px;border:1px solid var(--border);border-top-color:var(--accent-hi);border-radius:50%;animation:spin .85s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.approval-card{margin:0 0 28px 43px;border:1px solid rgba(113,112,255,.3);background:linear-gradient(135deg,rgba(94,106,210,.10),rgba(255,255,255,.02));border-radius:10px;padding:16px}
.approval-card h3{font-size:var(--text-sm);font-weight:590;margin:0 0 5px}
.approval-card p{font-size:var(--text-xs);line-height:1.55;color:var(--muted);margin:0 0 13px}
/* Why a credential is wanted and how to create one, straight from the skill
   that declared it. Set apart from the prompt so it reads as guidance. */
.approval-card p.prompt-context{margin:-7px 0 12px;padding-left:9px;border-left:2px solid rgba(113,112,255,.3);color:var(--subtle);overflow-wrap:anywhere}
.approval-actions{display:flex;gap:7px}
.approval-actions button{font-size:var(--text-xs);padding:7px 11px}
.run-error{margin:0 0 24px 43px;border:1px solid rgba(239,107,115,.2);background:rgba(239,107,115,.06);color:#efa4aa;border-radius:8px;padding:11px 13px;font-size:var(--text-xs)}
.composer-wrap{position:absolute;z-index:4;left:50%;bottom:0;transform:translateX(-50%);width:min(780px,calc(100% - 40px));padding:0 0 14px;background:linear-gradient(to bottom,transparent,var(--bg) 28%)}
.composer{margin-top:42px;background:rgba(25,26,27,.96);border:1px solid var(--border);border-radius:13px;padding:10px 11px 9px;box-shadow:0 18px 70px rgba(0,0,0,.46),inset 0 1px rgba(255,255,255,.03)}
.composer:focus-within{border-color:rgba(113,112,255,.38);box-shadow:0 18px 70px rgba(0,0,0,.46),0 0 0 3px rgba(113,112,255,.07)}
.composer textarea{min-height:47px;max-height:180px;resize:none;border:0;background:transparent;padding:5px 4px;font-size:var(--text-md);line-height:1.5;box-shadow:none}
.composer textarea:focus{box-shadow:none}
.composer-bottom{display:flex;align-items:center;justify-content:space-between;margin-top:3px}
.composer-hint{font-size:var(--text-xs);color:var(--subtle);padding-left:4px}
.spark{color:var(--accent-hi);margin-right:4px}
.send-button{width:30px;height:30px;display:grid;place-items:center;border:0;border-radius:7px;background:var(--accent);color:white;cursor:pointer;transition:.16s}
.send-button:hover{background:var(--accent-hi);transform:translateY(-1px)}
.send-button:disabled{opacity:.4;transform:none;cursor:not-allowed}
.send-button svg{width:15px;height:15px;stroke-width:2}
.fine-print{text-align:center;font-size:var(--text-xs);color:#4b4e54;margin:7px 0 0}
.dialog{width:min(430px,calc(100% - 32px));border:1px solid var(--border);border-radius:13px;background:var(--raised);color:var(--text);padding:0;box-shadow:0 30px 120px rgba(0,0,0,.7)}
.dialog::backdrop{background:rgba(0,0,0,.75);backdrop-filter:blur(4px)}
.dialog form{padding:25px}
.dialog form{position:relative}
.dialog-close{position:absolute;top:13px;right:13px;color:var(--subtle)}
/* CONNECTED reads differently from an invitation to connect. The label carries
   a repository name now, and names are long: it gets a ceiling and an ellipsis
   so one long org/repo cannot push the credit badge off the topbar. */

.dialog-close:hover{color:var(--text)}
.dialog-icon{width:34px;height:34px;border-radius:9px;background:rgba(113,112,255,.12);border:1px solid rgba(113,112,255,.2);display:grid;place-items:center;color:#c5c7ff;margin-bottom:17px}
.dialog h2{font-size:var(--text-xl);line-height:var(--lead-heading);font-weight:510;letter-spacing:var(--track-xl);margin:0 0 7px;text-wrap:balance}
.dialog p{font-size:var(--text-sm);color:var(--muted);line-height:1.55;margin:0 0 20px}
.dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:21px}
/* The connect dialog carries a three-step flow, not a confirm question. At
   430px the grant list wrapped onto four lines each and the rail had nothing
   left to sit beside. */
#connectionsDialog{width:min(512px,calc(100% - 32px))}
.toast{position:fixed;left:50%;bottom:22px;transform:translate(-50%,18px);background:#27282c;border:1px solid var(--border);border-radius:7px;padding:9px 13px;color:var(--secondary);font-size:var(--text-xs);opacity:0;pointer-events:none;transition:.2s;z-index:10;box-shadow:0 12px 45px rgba(0,0,0,.45)}
.toast.show{opacity:1;transform:translate(-50%,0)}
/* Deliberately not a toast: a toast times out, and the thing this reports
   stays true until the page reloads. It sits above the composer so it cannot
   be scrolled away from, and it is quiet, because nothing is broken. */
.stale-build{position:fixed;left:50%;bottom:22px;transform:translateX(-50%);z-index:11;
 display:flex;align-items:center;gap:var(--s3);background:#27282c;
 border:1px solid var(--border);border-radius:7px;padding:9px 9px 9px 13px;
 color:var(--secondary);font-size:var(--text-xs);box-shadow:0 12px 45px rgba(0,0,0,.45)}
.stale-build[hidden]{display:none}
.stale-build button{background:var(--accent);color:#fff;border:0;border-radius:5px;
 padding:5px 11px;font:inherit;font-weight:500;cursor:pointer}
.stale-build button:active{transform:translateY(1px)}
/* Below this the panel stops being a column and becomes a sheet behind the
   "This repair" button. A 320px rail on a 900px screen leaves the
   conversation too narrow to read, and the conversation is the product. */
@media(max-width:1180px){
 .shell{grid-template-columns:220px minmax(0,1fr)}
 /* The panel is a fixed sheet here, so a collapsed sidebar leaves one item. */
 .shell.sidebar-collapsed,
 .shell.panel-collapsed.sidebar-collapsed{grid-template-columns:minmax(0,1fr)}
 .panel-head .panel-close{display:grid}
 .repair-panel{position:fixed;inset:0 0 0 auto;width:min(340px,88vw);z-index:9;
  transform:translateX(100%);transition:transform .22s ease;box-shadow:-24px 0 60px rgba(0,0,0,.55)}
 .repair-panel.open{transform:none}
 .panel-scrim{position:fixed;inset:0;background:rgba(4,5,6,.55);z-index:8;backdrop-filter:blur(2px)}
}
@media(max-width:900px){
 /* THE REPOSITORY, AS ITS MARK. The name is the first thing inside the dialog
    this pill opens, so at this width it is one tap away rather than gone, and
    the mark keeps the affordance and the connected/not-connected state. What it
    buys is the project name, which was being squeezed to nothing beside it. */
 .repo-pill span{display:none}
 .repo-pill{padding:4px 8px}
 /* THE DELETION THIS REPLACES. `.auth-story{display:none}` took the headline,
    the explanation and all three proof points off every screen under 900px and
    left two input boxes and a Create account button — a stranger on a phone was
    asked to make an account for a product that had not said what it was.

    It stacks instead. Everything survives; what changes is the amount of room
    each part is given, which is the difference between adapting and deleting. */
 /* A COLUMN, not a one-column grid. MEASURED at 375px: as a grid with a definite
    812px height and two auto rows whose content came to 1073px, the browser had to
    shrink one of them — and it shrank the story, because `overflow:hidden` gives a
    box an automatic minimum size of zero. The rail read `193.125px 618.875px`: the
    story was clipped to 193px over 455px of content, and the form was drawn on top
    of the proof points. A flex column with `flex:0 0 auto` items cannot be squeezed,
    and the container scrolls because body{overflow:hidden} means nothing else can. */
 .auth-layout{display:flex;flex-direction:column;height:100%;overflow-y:auto}
 .auth-story,.auth-panel{flex:0 0 auto}
 .auth-story{padding:26px 22px 24px;border-right:0;border-bottom:1px solid var(--border-subtle)}
 .auth-story .brand{margin-bottom:26px}
 .story-copy{margin:0}
 .eyebrow{margin-bottom:15px}
 .story-copy h1{font-size:var(--text-display-sm);letter-spacing:-.7px;line-height:1.12}
 .story-copy h1 br{display:none}
 .story-copy>p{margin-top:14px;font-size:var(--text-sm);line-height:1.6}
 /* Three columns at 375px is three columns of one word each. Stacked, each
    proof point reads as the sentence it is. */
 .story-proof{grid-template-columns:1fr;gap:11px;margin-top:22px;padding-top:19px}
 .story-proof div{flex-direction:row;align-items:baseline;gap:8px;flex-wrap:wrap}
 .story-proof strong{flex:0 0 auto}
 /* The story now carries the brand, so the form must not carry a second one. */
 .mobile-brand{display:none}
 .auth-panel{min-height:auto;padding:30px 22px 44px;place-items:start center}
 .shell{grid-template-columns:220px minmax(0,1fr)}
}
@media(max-width:680px){
 /* THE STATUS GIVES UP ITS RESERVATION FIRST.
    MEASURED at 375px: a 260px status plus the repository mark over-subscribed
    the bar and squeezed the left track to nothing, so the project name and the
    mark ended up in the same pixels. The reservation exists to stop the bar
    reflowing every second on a wide screen; on a phone there is no room to
    reserve, and the name of the project you are looking at outranks the elapsed
    seconds of the run. The full status stays in the title attribute. */
 .topbar .project-state{min-width:0;max-width:118px}
 /* The badge and Upgrade are BOTH already in the account menu inside the
    drawer, under "Credit usage" — the same balance, the same bar and the same
    two buttons. Keeping a second copy in a 375px bar cost 168px and left the
    project name no room at all. */
 /* Specificity, not source order. The base .topbar-billing{display:inline-flex}
    is declared further down the file and a bare class here loses to it however
    well the query matches — MEASURED: it kept its full 168px at 375px and left
    the project name 79px. Naming the parent settles it. */
 .topbar .topbar-billing{display:none}
 body{overflow:hidden}.shell{display:block}.sidebar{position:fixed;inset:0 auto 0 0;width:270px;z-index:8;transform:translateX(-100%);transition:.2s;box-shadow:20px 0 60px rgba(0,0,0,.6)}.sidebar.open{transform:none}
 .workspace{height:100%}.mobile-menu{display:grid}.topbar{padding:0 13px}.empty-state{padding-bottom:var(--s3);margin-bottom:var(--composer-clearance,186px);max-height:calc(100% - var(--composer-clearance,186px))}.empty-state h1{font-size:var(--text-display-sm)}
 /* The examples were deleted here, on the one screen where typing is hardest
    and a ready-made sentence is worth most. They scroll sideways instead. */
 .examples{flex-wrap:nowrap;overflow-x:auto;justify-content:flex-start;
  margin:0 -17px;padding:0 17px 4px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
 .examples::-webkit-scrollbar{display:none}
 .examples button{flex:0 0 auto}
 /* Three cards side by side at 375px is three columns of two words each. */
 .how-it-goes{flex-direction:column;gap:8px;margin-top:22px}
 .how-it-goes li{flex-direction:row;align-items:baseline;flex-wrap:wrap;gap:4px 8px;padding:11px 13px}
 .how-it-goes li:before{margin-bottom:0;align-self:center}
 .conversation{padding:25px 17px 155px}.composer-wrap{width:calc(100% - 22px);padding-bottom:8px} /* `.composer-hint{display:none}` did not hide a hint. The two attach buttons
    live inside it, so it removed the ONLY way to upload a project from a phone —
    on a product whose other route in is a GitHub authorization. The sentence goes;
    the buttons stay. */
 .composer-hint{padding-left:0}
 .composer-hint>span{display:none}
 .composer-keys{display:none}.message{grid-template-columns:26px minmax(0,1fr);gap:10px}.message-avatar{width:25px;height:25px}.activity,.approval-card,.run-error{margin-left:35px}
}
.work-log{margin:0 0 21px 43px;display:flex;flex-direction:column;gap:6px}
.work-line{display:flex;align-items:center;gap:9px;color:var(--muted);font-size:var(--text-xs)}
.work-line:last-child{color:var(--text)}
.work-done{width:13px;text-align:center;color:var(--accent-hi);opacity:.7}
/* STOP, in the seat Send was in. A filled square on red: the one control in the
   product that interrupts rather than starts, and it should not be mistakable
   for the one beside it at a glance. */
.stop-button{display:inline-grid;place-items:center;width:30px;height:30px;border:1px solid rgba(220,80,80,.45);border-radius:8px;
 background:rgba(220,80,80,.16);color:#ff8a8a;cursor:pointer;transition:.15s ease}
.stop-button:hover{background:rgba(220,80,80,.28);color:#ffb3b3}
.stop-button:disabled{opacity:.5;cursor:default}
.stop-button svg{width:15px;height:15px;fill:currentColor;stroke:none}
/* THE QUEUE. Below the composer, above the fine print — between where the
   message was typed and where the answer will arrive, which is where a person
   looks for something they just sent. */
.queue{display:flex;flex-direction:column;gap:6px;margin:9px 2px 0}
.queue-head{color:var(--subtle);font-size:var(--text-xs);padding:0 2px}
.queue-item{display:flex;align-items:flex-start;gap:9px;padding:8px 10px;border:1px dashed var(--border);border-radius:8px;background:rgba(255,255,255,.02)}
.queue-text{flex:1;min-width:0;color:var(--secondary);font-size:var(--text-xs);line-height:1.5;
 display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.queue-actions{display:flex;gap:5px;flex:none}
.queue-actions button{border:0;background:none;padding:2px 4px;color:var(--subtle);font-size:var(--text-xs);font-family:inherit;cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.queue-actions button:hover{color:var(--text)}
/* The relocated recovery action, sized as a nav row rather than a top-bar button. */
.nav-action{display:flex;align-items:center;gap:9px;width:100%;margin-top:6px;padding:8px 9px;border:0;border-radius:7px;
 background:none;color:var(--subtle);font-size:var(--text-xs);font-family:inherit;text-align:left;cursor:pointer}
.nav-action:hover{background:rgba(255,255,255,.045);color:var(--text)}
.nav-action svg{width:14px;height:14px;flex:none}
/* THE WORK LOG, AS ONE ROW INSTEAD OF THIRTY.
   It used to render every step it had ever taken as a sibling of the reply, up
   to thirty lines, re-appended BELOW the streaming text on every update — so
   the answer was pushed off the top of the viewport by a list of the machinery
   that produced it. Collapsed it is a single line: the step happening now, and
   a count of the ones behind it. */
.work-summary{display:flex;align-items:center;gap:9px;width:100%;padding:7px 9px;border:1px solid var(--border-subtle);border-radius:8px;
 background:rgba(255,255,255,.02);color:var(--muted);font-size:var(--text-xs);font-family:inherit;text-align:left;cursor:pointer}
.work-summary:hover{background:rgba(255,255,255,.045);color:var(--text)}
.work-summary .work-now{color:var(--text);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.work-summary .work-count{margin-left:auto;flex:none;color:var(--subtle)}
/* The clock sits at the far end, after the step count when there is one, so
   the row reads: what it is doing, how much came before, how long so far. */
.work-summary .work-elapsed{margin-left:auto;flex:none;color:var(--subtle);
 font-variant-numeric:tabular-nums}
.work-summary .work-count + .work-elapsed{margin-left:9px}
@media(prefers-reduced-motion:reduce){.activity-spinner{animation-duration:2.5s}}
.work-caret{flex:none;width:11px;text-align:center;color:var(--subtle);transition:transform .15s ease}
.work-summary[aria-expanded="true"] .work-caret{transform:rotate(90deg)}
.work-steps{display:flex;flex-direction:column;gap:6px;padding:9px 9px 2px 11px;border-left:1px solid var(--border-subtle);margin:7px 0 0 9px}
.work-detail-toggle{align-self:flex-start;margin-top:2px;border:0;background:none;padding:0;color:var(--subtle);font-size:var(--text-xs);font-family:inherit;cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.work-detail-toggle:hover{color:var(--text)}
.work-stream{max-height:260px;overflow:auto;display:flex;flex-direction:column;gap:9px;margin-top:9px;padding:10px;border:1px solid var(--border-subtle);border-radius:8px;background:rgba(0,0,0,.25)}
.work-stream-row{display:flex;flex-direction:column;gap:5px;min-width:0}
.work-stream-head{color:var(--secondary);font-size:var(--text-xs);font-weight:510}
.work-stream-cmd,.work-stream-out{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--text-xs);line-height:1.5;
 white-space:pre-wrap;overflow-wrap:anywhere;color:var(--muted);max-height:150px;overflow:auto}
.work-stream-cmd{color:var(--text)}
.form-note{font-size:var(--text-sm);line-height:1.55;color:var(--text);background:rgba(94,106,210,.10);border:1px solid rgba(113,112,255,.3);border-radius:9px;padding:11px 13px;margin:0 0 4px}
.attachments{display:flex;flex-wrap:wrap;gap:7px;padding:0 2px 9px}
.chip{display:inline-flex;align-items:center;gap:7px;font-size:var(--text-xs);color:var(--text);background:rgba(94,106,210,.12);border:1px solid rgba(113,112,255,.32);border-radius:999px;padding:5px 6px 5px 11px}
.chip.pending{opacity:.6}
.chip.failed{background:rgba(220,80,80,.12);border-color:rgba(220,80,80,.4)}
.chip button{background:none;border:0;color:inherit;cursor:pointer;font-size:var(--text-md);line-height:1;padding:0 5px;opacity:.65}
.chip button:hover{opacity:1}
.attach-button{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;margin-right:7px;border:1px solid var(--border);background:transparent;border-radius:7px;color:var(--muted);cursor:pointer;vertical-align:middle}
.attach-button:hover{color:var(--text);border-color:var(--accent-hi)}
.attach-button svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.workspace.dropping{outline:2px dashed var(--accent-hi);outline-offset:-10px;border-radius:12px}
/* Layout containment. Without an explicit row the shell grid sizes to its
   content, so the workspace grew past the viewport and pushed the composer —
   and its send button — below the fold. The empty state and the conversation
   share one row: only one is ever visible, and neither may stack. */
.shell{grid-template-rows:minmax(0,1fr);overflow:hidden}
/* Rows are assigned EXPLICITLY, every one of them, and every direct child of
   .workspace must be given one. A child added without a `grid-row` auto-places
   into an implicit row below the 1fr content row — which is where
   `.composer-wrap` sits, position:absolute over the bottom. The result renders
   correctly, reads correctly in the accessibility tree, and is completely
   unclickable: elementFromPoint over the new element returns the composer.
   Measured that way once; nothing but a real click in a real browser finds it. */
.workspace{grid-template-rows:58px minmax(0,1fr)}
.workspace>.topbar{grid-row:1}
/* ONE ROW *AND* ONE COLUMN.
   Both of these are assigned grid-row:2, and with only rows declared on
   .workspace the auto-placer put them in row 2 COLUMN 1 and COLUMN 2 — an
   implicit second column that existed only because two items claimed one row.
   MEASURED on the first screen: the workspace was 1600px, the empty state was
   centred at 629 inside a 1258px first column, and an empty conversation held
   342px beside it. Closing a rail widened the workspace and moved nothing,
   which is exactly what it looked like: a page that ignores its own controls.
   Pinning the column makes them stack, so only one is ever visible and it is
   always centred in the whole workspace. */
.workspace>.empty-state,.workspace>.conversation{grid-row:2;grid-column:1;min-height:0}
.plan-card{margin:14px 0;padding:12px 14px;border:1px solid var(--border-subtle);border-radius:9px;background:rgba(255,255,255,.02)}
.plan-card h4{margin:0 0 9px;font-size:var(--text-xs);font-weight:510;color:var(--secondary);letter-spacing:.01em}
.plan-row{display:flex;gap:9px;align-items:flex-start;font-size:var(--text-sm);color:var(--muted);padding:3px 0;line-height:1.45}
.plan-mark{flex:none;width:12px;text-align:center;color:var(--subtle)}
.plan-row.done{color:var(--subtle)}
.plan-row.done .plan-mark{color:var(--green)}
.plan-row.done span:last-child{text-decoration:line-through;text-decoration-color:rgba(255,255,255,.2)}
.plan-row.active{color:var(--text)}
.plan-row.active .plan-mark{color:var(--accent-hi)}
.prompt-own-answer{display:flex;gap:8px;width:100%;margin-top:10px}
.prompt-own-answer input{margin-top:0;flex:1}

/* Connecting a private repository. No credential field, by design — the only
   thing on screen is a short code that is useless without the device code the
   server keeps. */
.connect-note{font-size:var(--text-sm);line-height:1.6;color:var(--muted);margin:0 0 11px}
.connect-note.tight{font-size:var(--text-xs);margin:0 0 9px}
.connect-code{font-family:'JetBrains Mono',monospace;font-weight:600;font-size:var(--text-display-sm);line-height:1.2;letter-spacing:.18em;color:var(--text);background:rgba(94,106,210,.10);border:1px solid rgba(113,112,255,.3);border-radius:9px;padding:14px;text-align:center;margin:0 0 11px}
.connect-link{display:inline-block;font-size:var(--text-sm);color:var(--accent-hi);margin:0 0 11px}
.connect-link.strong{font-weight:510}
.connect-link:hover{text-decoration:underline}
.connect-list{display:flex;flex-direction:column;gap:6px;max-height:230px;overflow-y:auto}
.connect-row{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:var(--text-sm);border:1px solid var(--border);border-radius:8px;padding:8px 11px}
.connect-row span{overflow-wrap:anywhere}

/* THE THREE STEPS. All of them are on screen whichever one you are on: the rail
   down the left side is the only thing in the flow that says how far this goes,
   and a step you have not reached is information, not clutter. */
.connect-steps{display:flex;flex-direction:column}
.connect-step{position:relative;display:grid;grid-template-columns:24px minmax(0,1fr);gap:13px;padding:0 0 20px}
/* The rail is drawn by each step onto the one below it, so the last step has no
   tail hanging off the bottom of the dialog. */
.connect-step:not(:last-child):before{content:"";position:absolute;left:11px;top:26px;bottom:2px;width:1px;background:var(--border)}
.connect-step.done:not(:last-child):before{background:rgba(16,185,129,.35)}
.connect-step:last-child{padding-bottom:0}
.step-mark{width:23px;height:23px;border-radius:50%;display:grid;place-items:center;font-size:var(--text-xs);font-weight:590;border:1px solid var(--border);color:var(--subtle);background:var(--raised)}
.connect-step.active .step-mark{border-color:rgba(113,112,255,.55);background:rgba(94,106,210,.16);color:#c5c7ff}
.connect-step.done .step-mark{border-color:rgba(16,185,129,.4);background:rgba(16,185,129,.14);color:var(--tone-done)}
.step-body{min-width:0;padding-top:2px}
.step-title{font-size:var(--text-sm);font-weight:590;color:var(--secondary);margin-bottom:7px}
.connect-step.active .step-title{color:var(--text)}
/* A step you have not reached explains itself and then gets out of the way. */
.connect-step.todo .step-title{color:var(--subtle);font-weight:510}
.connect-step.todo .step-detail{opacity:.72}
.step-detail>*:last-child{margin-bottom:0}

/* WHAT THE GRANT ACTUALLY IS. Two things it may do and two it may not, on one
   list, because the two it may not are the ones a customer is looking for. */
.connect-grant{list-style:none;margin:0 0 15px;padding:0;display:flex;flex-direction:column;gap:9px}
.connect-grant li{display:grid;grid-template-columns:17px minmax(0,1fr);gap:9px;align-items:start}
.grant-mark{font-size:var(--text-xs);line-height:1.45;text-align:center}
.connect-grant li.can .grant-mark{color:var(--tone-done)}
.connect-grant li.cannot .grant-mark{color:var(--subtle)}
.grant-text{display:flex;flex-direction:column;gap:1px;min-width:0}
.grant-text strong{font-size:var(--text-sm);font-weight:510;color:var(--secondary)}
.grant-text small{font-size:var(--text-xs);line-height:1.5;color:var(--subtle)}

.connect-waiting{display:flex;align-items:center;gap:8px;margin:0;font-size:var(--text-xs);color:var(--muted)}
.connect-here{display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid rgba(16,185,129,.22);background:rgba(16,185,129,.07);border-radius:8px;padding:8px 11px;margin-bottom:9px}
.connect-here small{font-size:var(--text-xs);color:var(--subtle);flex:0 0 auto}
/* The GitHub mark. A text-only button in the top bar was invisible to the one
   customer who needed it — he never found it, and the engineer never mentioned
   it. Measured 2026-08-15. */
.gh-mark{width:14px;height:14px;fill:currentColor;flex:0 0 auto}
.with-mark{display:inline-flex;align-items:center;gap:7px}
.dialog-icon .gh-mark{width:17px;height:17px}
.empty-cta{margin:var(--s5) auto 0;display:flex;flex-direction:column;align-items:center;gap:var(--s2)}
.empty-cta .primary{padding:11px 20px;font-size:var(--text-sm)}
.empty-cta-note{max-width:430px;margin:0;color:var(--subtle);font-size:var(--text-xs);line-height:1.6}
.empty-state>p.empty-connect{max-width:570px;margin:18px auto 0;color:var(--subtle);font-size:var(--text-xs);line-height:1.6}
.empty-connect .text-button{display:inline-flex;align-items:center;gap:5px;vertical-align:baseline}

/* Terms and privacy. Long-form prose, deliberately not styled like the app: */
/* wider measure, more air, and a link colour that is obviously a link.      */
.legal-page{overflow:auto}
.legal{max-width:720px;margin:0 auto;padding:44px 24px 96px}
.legal .brand{margin-bottom:44px}
.legal h1{margin:0 0 22px;font-size:var(--text-display);line-height:1.1;letter-spacing:-1px;font-weight:510}
.legal h2{margin:44px 0 14px;font-size:var(--text-lg);font-weight:560;letter-spacing:-.1px;color:var(--text)}
.legal p,.legal li{color:var(--muted);font-size:var(--text-md);line-height:1.75;font-weight:300}
.legal p{margin:0 0 14px}
.legal .legal-lede{font-size:var(--text-lg);line-height:1.7;color:var(--secondary);margin-bottom:34px}
.legal ul{margin:0 0 14px;padding-left:20px}
.legal li{margin-bottom:9px}
.legal strong{color:var(--secondary);font-weight:510}
.legal a{color:var(--accent-hi);text-decoration:none;border-bottom:1px solid rgba(113,112,255,.35)}
.legal a:hover{border-bottom-color:var(--accent-hi)}
.legal .brand{border-bottom:none}
.legal .mono{font-family:'JetBrains Mono',monospace;font-size:var(--text-sm);color:var(--secondary)}
.legal-flag{margin:0 0 12px;padding:18px 20px;border:1px solid var(--border);border-left:2px solid var(--accent);
  border-radius:8px;background:var(--surface);color:var(--muted);font-size:var(--text-sm);line-height:1.7;font-weight:300}
.legal-flag strong{display:block;margin-bottom:5px;color:var(--text);font-weight:510}
.legal-foot{display:flex;gap:22px;margin-top:56px;padding-top:22px;border-top:1px solid var(--border-subtle);font-size:var(--text-sm)}

/* The same pair of links on the sign-in card. */
.auth-legal{margin:22px 0 0;text-align:center;font-size:var(--text-xs);line-height:1.6;color:var(--subtle)}
.auth-legal a{color:var(--muted);text-decoration:none;border-bottom:1px solid var(--border)}
.auth-legal a:hover{color:var(--secondary)}
@media (max-width:720px){.legal{padding:32px 20px 72px}}
/* HEIGHT, not width. MEASURED at 1280x860: the primary call to action — the one
   button on the first screen a customer has ever seen — was drawn UNDER the
   composer, which floats over the bottom of the workspace. Short windows are
   common on laptops and the screen has real things to say, so what gives way is
   the decoration: the orb is a badge, not a sentence, and the overline repeats
   what the headline underneath already says. */
@media (max-height:900px){
 .empty-state{padding-top:24px}
 .engineer-orb{display:none}
 .empty-state .overline{display:none}
 .empty-state>p:not(.overline){margin:14px auto 18px}
 .how-it-goes{margin-top:18px}
}

/* === The repair panel === */
.repair-panel{display:flex;flex-direction:column;background:var(--panel);border-left:1px solid var(--border-subtle);min-height:0;overflow:hidden}
.panel-head{height:58px;flex:none;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 10px 0 12px;
 border-bottom:1px solid var(--border-subtle);font-size:var(--text-xs);font-weight:510;letter-spacing:.08em;text-transform:uppercase;color:var(--subtle)}
.panel-close{display:none}
.panel-body{flex:1;min-height:0;overflow:auto;padding:var(--s4);display:flex;flex-direction:column;gap:var(--s5)}
.panel-block{display:flex;flex-direction:column;gap:9px}
.panel-label{font-size:var(--text-xs);font-weight:510;letter-spacing:.07em;text-transform:uppercase;color:var(--subtle)}
.panel-card{border:1px solid var(--border-subtle);border-radius:8px;background:rgba(255,255,255,.02);padding:11px 12px;display:flex;flex-direction:column;gap:10px}
.panel-row{display:flex;align-items:center;justify-content:space-between;gap:10px}
.panel-row span:first-child{font-size:var(--text-xs);color:var(--subtle)}
.panel-mono{font-size:var(--text-xs);font-family:'JetBrains Mono',monospace;color:var(--secondary);overflow-wrap:anywhere}
.panel-mono.unset{color:var(--amber,#e2a336)}
.panel-repo{display:flex;align-items:center;gap:8px}
.panel-repo svg{width:14px;height:14px;fill:currentColor;stroke:none;color:var(--muted);flex:none}
.panel-divider{height:1px;background:var(--border-subtle)}
.panel-empty{font-size:var(--text-xs);line-height:1.6;color:var(--subtle)}

/* the two questions */
.panel-switch{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:-3px -4px;padding:3px 4px;border:0;background:none;border-radius:5px;cursor:pointer;width:calc(100% + 8px);text-align:left;color:inherit}
.panel-switch:hover{background:rgba(255,255,255,.04)}
.panel-switch>span{font-size:var(--text-xs);color:var(--subtle)}
.switch{display:inline-flex;align-items:center;width:30px;height:17px;flex:none;border-radius:999px;padding:2px;background:rgba(255,255,255,.07);border:1px solid var(--border);justify-content:flex-start;transition:.16s ease}
.switch i{width:11px;height:11px;border-radius:50%;background:var(--subtle);display:block;transition:.16s ease}
.switch.on{background:rgba(113,112,255,.35);border-color:rgba(113,112,255,.5);justify-content:flex-end}
.switch.on i{background:#dedfff}
/* The branch field decides where every fix lands, so it is asked like a
   question rather than offered as a bare box: what it is for before the field,
   and the reason a name will not work instead of a toast after the request
   comes back. The server still decides — this only stops the trip. */
.branch-form{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.branch-row{display:flex;gap:6px;justify-content:flex-end}
.branch-form input{flex:1;min-width:0;font-family:'JetBrains Mono',monospace;font-size:var(--text-xs);padding:6px 8px;border-radius:6px;border:1px solid var(--border);background:rgba(255,255,255,.03);color:var(--text);margin:0}
.branch-form input[aria-invalid="true"]{border-color:rgba(239,107,115,.6);box-shadow:0 0 0 3px rgba(239,107,115,.08)}
.branch-form button{font-size:var(--text-xs);padding:6px 10px;border-radius:6px;border:1px solid var(--border);background:rgba(255,255,255,.05);color:var(--secondary);cursor:pointer;flex:0 0 auto}
.branch-form button:hover{background:rgba(255,255,255,.09);color:var(--text)}
.branch-form button[disabled]{opacity:.45;cursor:not-allowed}
.branch-form button[disabled]:hover{background:rgba(255,255,255,.05);color:var(--secondary)}
.branch-hint{margin:0;font-size:var(--text-xs);line-height:1.5;color:var(--subtle)}
.branch-hint.bad{color:var(--red)}
.panel-link-button{border:0;background:none;color:var(--accent-hi);font-size:var(--text-xs);cursor:pointer;padding:0;text-align:left}
.panel-link-button:hover{text-decoration:underline}
/* The key form. A credential field must look like one — monospaced, masked,
   and visibly its own control rather than another line of panel text. */
.panel-form{display:flex;flex-direction:column;gap:var(--s2)}
.panel-input{width:100%;box-sizing:border-box;background:rgba(0,0,0,.28);
 border:1px solid var(--border);border-radius:6px;padding:7px 9px;color:var(--primary);
 font:inherit;font-size:var(--text-xs);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.panel-input::placeholder{color:var(--subtle);font-family:inherit}
.panel-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:transparent}
.panel-form-actions{display:flex;align-items:center;gap:var(--s3)}
.panel-save{background:var(--accent);color:#fff;border:0;border-radius:6px;
 padding:6px 13px;font:inherit;font-size:var(--text-xs);font-weight:500;cursor:pointer}
.panel-save:active{transform:translateY(1px)}
.panel-save[disabled]{opacity:.55;cursor:default;transform:none}
.panel-note{font-size:var(--text-xs);line-height:1.6;color:var(--subtle);margin:0}
select.panel-input{appearance:none;cursor:pointer;font-family:inherit;
 background-image:linear-gradient(45deg,transparent 50%,var(--subtle) 50%),linear-gradient(135deg,var(--subtle) 50%,transparent 50%);
 background-position:calc(100% - 15px) 50%,calc(100% - 10px) 50%;background-size:5px 5px,5px 5px;
 background-repeat:no-repeat;padding-right:28px}
/* A key stored under a name nothing asks for looks identical to a working
   one until someone spends an afternoon on it. */
.panel-warn{font-size:var(--text-xs);color:var(--tone-attention);white-space:nowrap}
.panel-note[hidden]{display:none}

/* progress */
.panel-steps{display:flex;flex-direction:column;gap:10px}
.panel-step{display:flex;gap:10px;align-items:flex-start}
.panel-step .mark{width:14px;flex:none;text-align:center;font-size:var(--text-xs);margin-top:1px;color:#3a3d43}
.panel-step .text{font-size:var(--text-xs);color:#4d5058;line-height:1.45}
.panel-step.done .mark{color:var(--green)}
.panel-step.done .text{color:var(--subtle)}
.panel-step.active .mark{color:var(--accent-hi)}
.panel-step.active .text{color:var(--text)}
.panel-step.stopped .mark{color:#7d818a}
.panel-step.stopped .text{color:var(--secondary)}

/* files */
.panel-file{display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid var(--border-subtle);border-radius:8px;background:rgba(255,255,255,.02);padding:9px 11px}
.panel-file span:first-child{font-size:var(--text-xs);font-family:'JetBrains Mono',monospace;color:var(--secondary);overflow-wrap:anywhere}
.panel-file .gone{font-size:var(--text-xs);color:#ef6b73;flex:none}

/* delivery */
.panel-delivery{border-radius:8px;padding:12px 13px;display:flex;flex-direction:column;gap:7px;border:1px solid var(--border);background:rgba(255,255,255,.02)}
.panel-delivery h4{margin:0;font-size:var(--text-sm);font-weight:510;color:var(--text)}
.panel-delivery p{margin:0;font-size:var(--text-sm);line-height:1.6;color:#7d818a}
.panel-delivery.waiting{border-color:rgba(113,112,255,.3);background:rgba(94,106,210,.08)}
.panel-delivery.merged{border-color:rgba(16,185,129,.28);background:rgba(16,185,129,.06)}
.panel-delivery.held{border-color:rgba(226,163,54,.34);background:rgba(226,163,54,.07)}
.panel-cta{display:inline-flex;align-items:center;justify-content:center;gap:7px;margin-top:3px;padding:8px 12px;border-radius:7px;
 font-size:var(--text-xs);font-weight:510;text-decoration:none;background:var(--accent);border:1px solid var(--accent);color:#fff;box-shadow:inset 0 1px rgba(255,255,255,.16)}
.panel-cta:hover{background:var(--accent-hi)}
.panel-cta.quiet{background:transparent;border-color:var(--border);color:var(--secondary);box-shadow:none}
.panel-cta.quiet:hover{background:rgba(255,255,255,.05)}
.panel-cta svg{width:12px;height:12px}
.panel-foot{margin-top:auto;border-top:1px solid var(--border-subtle);padding-top:13px;display:flex;align-items:center;justify-content:space-between;gap:10px}
.panel-foot span{font-size:var(--text-xs);color:var(--subtle)}

/* Links inside a message. The address stays visible for anything we cannot
   name, because a customer should be able to see where a link goes. */
.message-body a{color:var(--accent-hi);text-decoration:none;border-bottom:1px solid rgba(113,112,255,.3)}
.message-body a:hover{border-bottom-color:var(--accent-hi)}
.message-body a.ref{font-family:'JetBrains Mono',monospace;font-size:var(--text-sm);padding:1px 5px;border-radius:4px;
 background:rgba(113,112,255,.10);border:1px solid rgba(113,112,255,.18);border-bottom-color:rgba(113,112,255,.18)}
.message-body a.ref:hover{background:rgba(113,112,255,.18)}

/* === State, drawn once === */
/* Five tones, not seven colours: two states can share a look when they mean
   the same thing to the person waiting. The mark carries the difference.
   Every value here comes from public/states.js, which the server reads too. */
:root{--tone-calm:#10b981;--tone-active:#7170ff;--tone-attention:#e2a336;
 --tone-done:#10b981;--tone-quiet:#62666d;--tone-trouble:#ef6b73}

.state-dot{width:7px;height:7px;border-radius:50%;flex:none;display:inline-block;background:var(--tone,#62666d)}
.state-dot.calm{--tone:var(--tone-calm)}
.state-dot.active{--tone:var(--tone-active)}
.state-dot.attention{--tone:var(--tone-attention)}
.state-dot.done{--tone:var(--tone-done)}
.state-dot.quiet{--tone:var(--tone-quiet)}
.state-dot.trouble{--tone:var(--tone-trouble)}

/* The marks. A running repair breathes; a finished one is solid; one waiting
   on the customer is hollow, which reads as unfinished at a glance. */
.state-dot.dot{box-shadow:0 0 0 3px color-mix(in srgb,var(--tone) 14%,transparent)}
.state-dot.pulse{box-shadow:0 0 0 3px color-mix(in srgb,var(--tone) 18%,transparent);animation:state-breathe 1.9s ease-in-out infinite}
.state-dot.ring{background:transparent;border:1.5px solid var(--tone)}
.state-dot.ask{background:transparent;border:1.5px solid var(--tone);
 box-shadow:0 0 0 3px color-mix(in srgb,var(--tone) 16%,transparent)}
.state-dot.check{box-shadow:0 0 0 3px color-mix(in srgb,var(--tone) 14%,transparent)}
.state-dot.square{border-radius:2px}
.state-dot.alert{border-radius:2px;box-shadow:0 0 0 3px color-mix(in srgb,var(--tone) 16%,transparent)}
@keyframes state-breathe{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(.82)}}
@media (prefers-reduced-motion:reduce){.state-dot.pulse{animation:none}}

/* The topbar line is now a dot plus a label rather than a sentence. */

/* "your turn" is the whole point of the list: it is what a returning customer
   is scanning for, so it is the only thing in the sidebar that is not grey. */
.your-turn{margin-left:auto;flex:none;font-style:normal;font-size:var(--text-xs);font-weight:510;
 letter-spacing:.04em;color:var(--tone-attention);background:rgba(226,163,54,.10);
 border:1px solid rgba(226,163,54,.26);border-radius:999px;padding:2px 7px}
.project-link{gap:8px}

/* Rhythm to go with the scale. Line-height is a ratio of the step, not a
   number picked per rule, so the same text is equally readable wherever it
   appears. Tight for labels that never wrap, loose for anything read. */
.message-body{line-height:1.7}
.panel-empty,.empty-cta-note,.fine-print{line-height:1.6}
.your-turn{font-size:var(--text-xs);letter-spacing:0}
/* The state label is the most important word in the topbar and was 9px. */
.message-time{font-size:var(--text-xs);color:var(--subtle)}
/* Mapping the old sizes onto the scale was faithful, but some of the old
   sizes were themselves wrong. These two carry a sentence a person has to
   READ before making a decision — the dialog's explanation and the delivery
   card's — and both sat on the floor step under a much larger heading.
   Measured in the browser at 375px: a 21px title above 11.5px body. */

/* "your turn" sits on the first line, beside the name rather than under it,
   so a scan down the left edge finds every project needing the customer
   without reading a word of the metadata. */
.your-turn{align-self:flex-start;margin-top:3px}

/* And the count above the list, so the answer is available before the scan. */
.waiting-count{font-style:normal;text-transform:none;letter-spacing:0;font-size:var(--text-xs);
 font-weight:510;color:var(--tone-attention);background:rgba(226,163,54,.10);
 border:1px solid rgba(226,163,54,.26);border-radius:999px;padding:1px 6px;
 flex:none;white-space:nowrap}

.empty-projects{line-height:1.6}

/* ── Stage 5: what the small screen keeps ─────────────────────────────── */
.lock-mark{width:13px;height:13px;flex:0 0 auto;opacity:.85}

/* ── Stage 6: the first screen, as three steps rather than a paragraph ── */
/* Same shape as the connect dialog and the repair panel on purpose: a customer
   learns one way of reading progress here and meets it twice more. */
.how-it-goes{list-style:none;counter-reset:step;display:flex;gap:var(--s3);
 max-width:700px;margin:22px auto 0;padding:0;text-align:left}
.how-it-goes li{counter-increment:step;flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:4px;
 padding:12px 14px;border:1px solid var(--border-subtle);border-radius:10px;background:rgba(255,255,255,.018)}
.how-it-goes li:before{content:counter(step);width:20px;height:20px;border-radius:50%;
 display:grid;place-items:center;font-size:var(--text-xs);font-weight:590;
 color:var(--muted);border:1px solid var(--border);margin-bottom:3px}
.how-it-goes strong{font-size:var(--text-sm);font-weight:510;color:var(--secondary)}
.how-it-goes span{font-size:var(--text-xs);line-height:1.55;color:var(--subtle)}
.examples-label{margin:var(--s5) 0 var(--s2);font-size:var(--text-xs);color:var(--subtle)}

/* ── Stage 7: what the repair has taken ───────────────────────────────── */
.panel-usage{display:flex;flex-direction:column;gap:7px}
.usage-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;font-size:var(--text-xs);color:var(--muted)}
.usage-row b{font-weight:510;color:var(--secondary);font-variant-numeric:tabular-nums;
 font-family:'JetBrains Mono',monospace;font-size:var(--text-xs)}
.usage-note{margin:9px 0 0;font-size:var(--text-xs);line-height:1.55;color:var(--subtle)}

/* ── Stage 6: the composer says what it will do ────────────────────────── */
/* The two rules Enter obeys were nowhere on screen. A customer writing three
   sentences found that out by sending the first one. */
.composer-right{display:flex;align-items:center;gap:11px;min-width:0}
.composer-keys{font-size:var(--text-xs);color:var(--subtle);white-space:nowrap}
.composer-keys kbd{font-family:inherit;font-size:inherit;color:var(--muted);
 border:1px solid var(--border);border-radius:4px;padding:1px 4px;background:rgba(255,255,255,.03)}
.composer:focus-within .composer-keys{color:var(--muted)}
/* maxlength stops the keystroke and says nothing. The count appears only
   near the limit, which is the only time it is worth the room. */
.composer-count{font-size:var(--text-xs);color:var(--subtle);font-variant-numeric:tabular-nums}
.composer-count.close{color:var(--tone-attention)}
.send-button:disabled{opacity:.35;cursor:default;transform:none}
/* WHAT WAS CHECKED, inside the delivery card that depends on it. Ruled off
   above so it reads as evidence for the state rather than more prose about
   it, and quiet by default: a customer scans for the failures. */
.panel-checks{display:flex;flex-direction:column;gap:5px;margin-top:3px;padding-top:9px;border-top:1px solid var(--border-subtle)}
.panel-checks .check{display:grid;grid-template-columns:13px minmax(0,1fr) auto;gap:8px;align-items:baseline;font-size:var(--text-xs);line-height:1.45}
.check-mark{text-align:center;font-size:var(--text-xs)}
.check-name{color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.check-verdict{font-variant-numeric:tabular-nums;color:var(--subtle)}
/* Only two things are worth colour here: something passed, and something
   broke. 'not run' is the common case and must not read as either. */
.panel-checks .check.pass .check-mark,.panel-checks .check.pass .check-verdict{color:var(--tone-done)}
.panel-checks .check.pass .check-name{color:var(--secondary)}
.panel-checks .check.fail .check-mark,.panel-checks .check.fail .check-verdict{color:var(--tone-trouble)}
.panel-checks .check.fail .check-name{color:var(--secondary)}
.panel-checks .check.not_run .check-mark{color:var(--subtle);opacity:.7}
/* The parent is named deliberately. `.panel-delivery p` is (0,1,1) and a bare
   `.checks-note` is (0,1,0), so the card's own paragraph rule would win and
   this would render at --text-sm in the muted grey — the same specificity
   collision that once silently overrode .empty-connect and .panel-toggle. */
.panel-delivery .checks-note{margin:4px 0 0;font-size:var(--text-xs);line-height:1.5;color:var(--tone-attention)}
/* ── The pricing page ───────────────────────────────────────────────────── */
/* A pricing page is not a terms page. `.legal` is 720px because prose reads
   badly wider than that, and MEASURED at 1280px the three tiers resolved to
   `329px 329px` inside it — two columns, with Team wrapped onto a second row
   472px down the page. The container widens; the prose keeps its measure. */
.legal.pricing{max-width:1020px}
.pricing h1,.pricing h2,.pricing>p,.pricing ul{max-width:68ch}
.pricing-lede{font-size:var(--text-lg);line-height:1.6;color:var(--muted);max-width:60ch;margin:0 0 34px}
.pricing-loading{color:var(--subtle);font-size:var(--text-sm)}
.tiers{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px;margin:0 0 18px}
.tier{position:relative;display:flex;flex-direction:column;gap:10px;padding:22px 20px;border:1px solid var(--border);border-radius:12px;background:var(--surface)}
.tier.featured{border-color:rgba(113,112,255,.45);background:rgba(94,106,210,.07)}
.tier-flag{position:absolute;top:-9px;left:20px;font-size:var(--text-xs);font-weight:510;color:#c5c7ff;background:var(--raised);border:1px solid rgba(113,112,255,.4);border-radius:999px;padding:2px 9px}
.tier h3{margin:0;font-size:var(--text-lg);font-weight:560}
.tier-price{display:flex;align-items:baseline;gap:5px}
.tier-price b{font-size:var(--text-display-sm);font-weight:600;letter-spacing:-.02em;color:var(--text)}
.tier-price span{font-size:var(--text-sm);color:var(--subtle)}
.tier-blurb{margin:0;font-size:var(--text-sm);line-height:1.55;color:var(--muted);min-height:2.8em}
.tier-facts{display:flex;flex-direction:column;gap:3px;padding:11px 0;border-top:1px solid var(--border-subtle);border-bottom:1px solid var(--border-subtle)}
.tier-credits{font-size:var(--text-md);font-weight:510;color:var(--text)}
.tier-repairs{font-size:var(--text-sm);color:var(--secondary)}
.tier-projects{font-size:var(--text-xs);color:var(--subtle)}
.tier-features{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px;flex:1}
.tier-features li{position:relative;padding-left:17px;font-size:var(--text-xs);line-height:1.5;color:var(--muted)}
.tier-features li:before{content:"¹3";position:absolute;left:0;color:var(--tone-done)}
.tier-cta{display:block;text-align:center;padding:10px 14px;border-radius:7px;font-size:var(--text-sm);font-weight:510;text-decoration:none;border:1px solid var(--border);color:var(--secondary);background:rgba(255,255,255,.03)}
.tier-cta:hover{background:rgba(255,255,255,.07);color:var(--text)}
.tier-cta.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.tier-cta.primary:hover{background:var(--accent-hi)}
.pricing-topup{font-size:var(--text-sm);color:var(--muted);margin:0 0 30px}
@media(max-width:720px){.tiers{grid-template-columns:1fr}.tier-blurb{min-height:0}}
/* The way in. A pricing page nothing links to is a URL, not a page — this one
   shipped that way and was found by the person who paid for it. */
.user-meta small a{color:inherit;text-decoration:none}
.user-meta small a:hover{color:var(--secondary);text-decoration:underline}
.user-meta small a.plan-low{color:var(--tone-attention)}
.auth-legal a{color:var(--muted)}
.auth-legal a:hover{color:var(--secondary)}
/* ── Credits in the app ─────────────────────────────────────────────────── */
/* The badge sits with the controls, not with the prose. A balance is something
   you act on, so it lives next to the things you act with. */
.credit-badge{display:inline-flex;align-items:center;gap:8px;margin-left:auto}
.credit-meter{display:inline-flex;align-items:baseline;gap:5px;padding:4px 9px;border-radius:999px;
 border:1px solid var(--border);background:rgba(255,255,255,.03);color:var(--muted);cursor:pointer}
.credit-meter:hover{border-color:var(--accent-hi);color:var(--secondary)}
.credit-meter b{font-size:var(--text-xs);font-weight:600;color:var(--secondary);
 font-variant-numeric:tabular-nums;font-family:'JetBrains Mono',monospace}
.credit-meter span{font-size:var(--text-xs)}
/* Amber at a fifth left, red at empty — a warning before it bites, not
   decoration on a number. */
.credit-meter.low{border-color:rgba(226,163,54,.4);background:rgba(226,163,54,.08)}
.credit-meter.low b{color:var(--tone-attention)}
.credit-meter.empty{border-color:rgba(239,107,115,.45);background:rgba(239,107,115,.09)}
.credit-meter.empty b{color:var(--tone-trouble)}
.credit-topup{font-size:var(--text-xs);color:var(--accent-hi);text-decoration:none;white-space:nowrap}
.credit-topup:hover{text-decoration:underline}

/* The receipt, inside the delivery card it belongs to. */
.panel-cost{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
 margin-top:3px;padding-top:9px;border-top:1px solid var(--border-subtle);font-size:var(--text-xs)}
.panel-cost span{color:var(--muted)}
.panel-cost b{font-weight:600;color:var(--secondary);font-variant-numeric:tabular-nums;
 font-family:'JetBrains Mono',monospace}

/* The statement. */
.dialog.wide{width:min(640px,calc(100% - 32px))}
.billing-body{max-height:46vh;overflow-y:auto;margin:0 0 4px;border:1px solid var(--border);border-radius:9px}
.billing-table{width:100%;border-collapse:collapse;font-size:var(--text-xs)}
.billing-table th{position:sticky;top:0;background:var(--surface);text-align:left;font-weight:600;
 color:var(--subtle);text-transform:uppercase;letter-spacing:.07em;padding:9px 12px;
 border-bottom:1px solid var(--border)}
.billing-table td{padding:9px 12px;border-bottom:1px solid var(--border-subtle);color:var(--muted)}
.billing-table tr:last-child td{border-bottom:0}
.billing-table .n{text-align:right;font-variant-numeric:tabular-nums;
 font-family:'JetBrains Mono',monospace;white-space:nowrap}
.billing-table td.n{color:var(--secondary)}
/* A grant reads as an addition, a charge as an ordinary line. Only the money
   coming IN is coloured, because that is the surprising direction. */
.billing-table td.n.credit{color:var(--tone-done)}
#billingSummary{font-size:var(--text-sm);color:var(--muted);margin:0 0 14px}
@media(max-width:680px){
 /* The word goes, the action stays — the same trade the privacy note makes,
    and for the same reason: a top-up link is a way to spend money and must not
    vanish because the viewport did. */
 .credit-topup .topup-label{display:none}
 .credit-topup{font-size:var(--text-md);line-height:1;padding:0 2px}
 /* And the statement SCROLLS rather than dropping its two most informative
    columns. Hiding tokens and time would leave a table that says what was
    charged and refuses to say what for. */
 .billing-body{overflow-x:auto}
 .billing-table{min-width:460px}
}
/* ── Billing in the top bar and the account menu ────────────────────────── */
/* Zero clicks. The Upgrade button does not wait for a plan to exist, because
   it is the path to getting one; the badge does, because a bar counting
   against nothing is a fault rather than an invitation. */
.topbar-billing{display:inline-flex;align-items:center;gap:9px}
.credit-meter{display:inline-flex;flex-direction:column;align-items:stretch;gap:4px;
 padding:5px 10px;border-radius:8px;border:1px solid var(--border);
 background:rgba(255,255,255,.03);cursor:pointer;min-width:104px}
.credit-meter:hover{border-color:var(--accent-hi)}
.meter-figures{display:flex;align-items:baseline;gap:5px;justify-content:space-between}
.meter-figures b{font-size:var(--text-xs);font-weight:600;color:var(--secondary);
 font-variant-numeric:tabular-nums;font-family:'JetBrains Mono',monospace}
.meter-figures span{font-size:var(--text-xs);color:var(--subtle)}
.meter-bar{display:block;height:3px;border-radius:999px;background:rgba(255,255,255,.09);overflow:hidden}
.meter-bar i{display:block;height:100%;border-radius:999px;background:var(--accent-hi);transition:width .3s ease}
.credit-meter.low .meter-bar i{background:var(--tone-attention)}
.credit-meter.low .meter-figures b{color:var(--tone-attention)}
.credit-meter.empty .meter-bar i{background:var(--tone-trouble)}
.credit-meter.empty .meter-figures b{color:var(--tone-trouble)}
/* The one control on this bar that is meant to be pressed by somebody who is
   not yet a customer, so it is the one that carries the accent. */
.upgrade-button{display:inline-flex;align-items:center;padding:7px 13px;border-radius:7px;
 background:var(--accent);color:#fff;font-size:var(--text-sm);font-weight:510;
 text-decoration:none;border:1px solid var(--accent);white-space:nowrap}
.upgrade-button:hover{background:var(--accent-hi);border-color:var(--accent-hi)}

/* The account block is a menu now, not three things in a row. */
.sidebar-user{position:relative}
.user-trigger{display:flex;align-items:center;gap:10px;width:100%;padding:9px 10px;border:0;
 border-radius:8px;background:none;color:inherit;cursor:pointer;text-align:left}
.user-trigger:hover{background:rgba(255,255,255,.045)}
.user-trigger .user-meta{flex:1;min-width:0}
.trigger-chevron{width:15px;height:15px;flex:0 0 auto;color:var(--subtle);
 transform:rotate(180deg);transition:transform .18s ease}
.user-trigger[aria-expanded="true"] .trigger-chevron{transform:rotate(0deg)}
.user-menu{position:absolute;left:8px;right:8px;bottom:calc(100% + 6px);z-index:12;
 border:1px solid var(--border);border-radius:11px;background:var(--raised);
 box-shadow:0 22px 60px rgba(0,0,0,.6);overflow:hidden}

/* Credit usage leads the menu: it is what a customer opens this to check,
   above the things they open it to change. */
.menu-credits{padding:14px 14px 13px;border-bottom:1px solid var(--border-subtle)}
.menu-credits-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.menu-credits-head strong{font-size:var(--text-sm);font-weight:590;color:var(--text)}
.menu-credits-head span{font-size:var(--text-xs);color:var(--subtle)}
.menu-bar{height:6px;border-radius:999px;background:rgba(255,255,255,.08);overflow:hidden;margin:10px 0 7px}
.menu-bar i{display:block;height:100%;border-radius:999px;background:var(--accent-hi)}
.menu-bar i.low{background:var(--tone-attention)}
.menu-bar i.empty{background:var(--tone-trouble)}
.menu-credits-line{margin:0;font-size:var(--text-xs);color:var(--muted);font-variant-numeric:tabular-nums}
.menu-credits-none{margin:9px 0 0;font-size:var(--text-xs);line-height:1.5;color:var(--subtle)}
.menu-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:12px}
.menu-actions a{display:block;text-align:center;padding:8px 10px;border-radius:7px;
 font-size:var(--text-xs);font-weight:510;text-decoration:none;border:1px solid var(--border)}
.menu-actions a.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.menu-actions a.primary:hover{background:var(--accent-hi)}
.menu-actions a.ghost{background:rgba(255,255,255,.03);color:var(--secondary)}
.menu-actions a.ghost:hover{background:rgba(255,255,255,.07);color:var(--text)}
.menu-actions a[aria-disabled="true"]{opacity:.55}

.menu-links{display:flex;flex-direction:column;padding:6px}
.menu-links a,.menu-links button,.menu-foot button{display:block;width:100%;text-align:left;
 padding:8px 9px;border:0;border-radius:6px;background:none;color:var(--muted);
 font-size:var(--text-sm);text-decoration:none;cursor:pointer}
.menu-links a:hover,.menu-links button:hover,.menu-foot button:hover{background:rgba(255,255,255,.05);color:var(--text)}
.menu-foot{padding:6px;border-top:1px solid var(--border-subtle)}
@media(max-width:680px){
 /* The bar keeps the count; the button keeps the word, because it is the one
    control here a person is meant to press. */
 .credit-meter{min-width:0;padding:5px 8px}
 .upgrade-button{padding:7px 10px}
}
/* ── The collapsible sidebar ────────────────────────────────────────────── */
.sidebar-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 0 16px}
.sidebar-head .brand{padding:0}

/* COLLAPSED: a 56px rail. Everything that navigates survives; only the words
   go, and every row already carries its name in a title. */
/* THE RIGHT PANEL, COLLAPSED.
   To nothing, not to a rail. The left rail keeps a state dot per project, so a
   56px strip there still navigates; this panel is one repair's detail and a
   56px strip of it would say nothing while costing the width it was collapsed
   to reclaim. The way back is #panelToggle, which is pinned to the right end of
   the topbar and is on screen in both states — it used to be a "This repair"
   button that appeared only when the panel was gone, so the control that
   restored the panel was itself the thing that moved. */
.shell.panel-collapsed{grid-template-columns:220px minmax(0,1fr) 0}
.shell.panel-collapsed .repair-panel{display:none}
.shell.panel-collapsed.sidebar-collapsed{grid-template-columns:minmax(0,1fr)}
/* WITH BOTH RAILS GONE the reading column widens, but it does not become the
   window. Prose set to the full width of a 27" monitor is measured in the
   hundreds of characters and is read by nobody; ~90 is the top of what stays
   comfortable. The width that was reclaimed goes to the reading measure and to
   the margins, and the text stays centred under the composer, which is itself
   centred. */
.shell.panel-collapsed.sidebar-collapsed .conversation{padding-left:max(28px,calc((100% - 900px)/2));padding-right:max(28px,calc((100% - 900px)/2))}
.shell.panel-collapsed.sidebar-collapsed .composer-wrap{width:min(920px,calc(100% - 48px))}

/* COLLAPSED MEANS GONE.
   It was a 48px rail keeping a state dot per project, which was my call and the
   wrong one: "collapse" was asked for as "close", and a strip that still costs
   48px and shows nothing readable is neither. The toggle lives in the top bar,
   so it does not vanish with the thing it closed — which is the whole reason it
   was moved there. */
/* TWO TRACKS, NOT THREE WITH A ZERO.
   `display:none` removes the sidebar from the grid entirely, so the remaining
   items AUTO-PLACE from column 1 — the workspace landed in the 0px track and
   rendered at zero width, and the panel took the 1fr. A track list has to
   describe the items that are actually there. */
.shell.sidebar-collapsed{grid-template-columns:minmax(0,1fr) 320px}
.shell.sidebar-collapsed .sidebar{display:none}

/* Below 680px the sidebar is already an overlay drawer with its own control,
   so a second collapse control would fight it. */
@media(max-width:680px){
 .rail-toggle[aria-controls="sidebar"]{display:none}
 /* Below 680px the sidebar is an overlay drawer, so "collapsed" has no meaning
    here and must not hide the drawer the menu button opens. */
 .shell.sidebar-collapsed{grid-template-columns:none}
 .shell.sidebar-collapsed .sidebar{display:flex}
}


/* ===========================================================================
   APPLE DESIGN PASS
   Emil Kowalski's apple-design skill, applied to the parts of it this product
   actually has: response, craft, materials, typography, and the three
   accessibility signals. Every value below is a decision, not a default.
   =========================================================================== */

/* 1. RESPONSE — feedback on the press, not on the release.
   Waiting for `click` to acknowledge a press "falls off a cliff" the moment any
   latency appears. 100ms is under the threshold where a press reads as delayed,
   and scale is compositor-only so it cannot cost a frame. */
button:not(:disabled):active,
.upgrade-button:active,
a.primary:active{transform:scale(.97);transition:transform 100ms ease-out}
button,.upgrade-button{transition:transform 140ms ease-out,background-color .15s ease,border-color .15s ease,color .15s ease}
/* Rows are large targets; scaling a whole sidebar row reads as the row falling
   over rather than as a press. They dim instead. */
.project-link:active,.nav-action:active,.user-trigger:active{transform:none;filter:brightness(1.18)}

/* 2. CRAFT — digits that do not reflow.
   Anything that counts, ticks, or is compared in a column gets tabular figures.
   Proportional digits change the width of a number as its value changes, which
   is a layout shift once per second on a running timer. */
.credit-meter,.meter-figures,.billing-body,.queue-head,.work-count,.work-elapsed,
.message-time,.composer-count,.panel-mono,.panel-cost{font-variant-numeric:tabular-nums}

/* 3. MATERIALS — a floating layer, with the light catching its top edge.
   The bright inset hairline is what makes a translucent surface read as a real
   pane of material rather than a rectangle of paint. */
.composer{box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 18px 50px -20px rgba(0,0,0,.6)}

/* 4. TYPOGRAPHY — leading follows size, inversely.
   Body copy gets room to breathe; dense UI rows are tightened so a list reads
   as a list rather than as paragraphs. */
.message-body{line-height:var(--lead-body)}
.dialog p,.empty-state>p{line-height:var(--lead-body)}
.project-meta,.queue-text,.work-line{line-height:var(--lead-dense)}
/* Uppercase needs the tracking; at 11.5px it sets far too tight otherwise. */
.overline,.panel-label{letter-spacing:.08em}

/* 5. REDUCED MOTION — a gentler equivalent, not an absence of feedback.
   Opacity and colour still change, because they carry meaning; what goes is
   travel, scale and anything with overshoot. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
   transition-duration:.01ms!important;scroll-behavior:auto!important}
  button:active,.upgrade-button:active,a.primary:active{transform:none;filter:brightness(1.2)}
  .sidebar,.repair-panel{transition:none}
}

/* 6. REDUCED TRANSPARENCY — frostier, not blurrier.
   Raise the background to opaque and drop the blur; a translucent surface a
   person has asked not to see through is just illegible text. */
@media (prefers-reduced-transparency: reduce){
  .topbar{background:var(--panel);backdrop-filter:none}
  .composer-wrap{background:var(--bg)}
  .panel-scrim{backdrop-filter:none;background:rgba(4,5,6,.8)}
}

/* 7. INCREASED CONTRAST — near-solid grounds and a defined border.
   The hairlines that read as structure at default contrast disappear at high
   contrast, so they are promoted rather than removed. */
@media (prefers-contrast: more){
  :root{--border:rgba(255,255,255,.24);--border-subtle:rgba(255,255,255,.16);
   --muted:#b6bcc6;--subtle:#989ea8}
  .topbar,.composer{backdrop-filter:none}
  .rail-toggle,.repo-pill,.queue-item{border-color:var(--border)}
}

/* THE STALL HINT, beside the button it is talking about. It sits above the
   composer rather than in the top bar, where it used to grow the centre track
   until it painted over the credit badge. */
.stall-hint{margin:0 2px 8px;padding:7px 10px;border:var(--hairline);border-radius:8px;
 background:rgba(255,255,255,.025);color:var(--muted);font-size:var(--text-xs);line-height:var(--lead-dense)}

/* A 48px RAIL. 6px of padding each side leaves 36px, which holds a 28px control
   with 4px of air — the smallest strip that still reads as a column rather than
   as a cut-off edge. */
.shell.sidebar-collapsed .brand.compact{justify-content:center;padding:2px 0 12px}

/* The build stamp: quiet by default, and legible the moment it matters. */
.build-stamp{margin-left:auto;color:var(--subtle);font-size:var(--text-xs);font-variant-numeric:tabular-nums}
.build-stamp.stale{color:var(--accent-hi)}

/* The two notes under the call to action were 5 lines of grey prose restating
   the button. One line stays — the one that answers the question a stranger
   actually has before pressing it. */
.empty-cta-note{max-width:420px}
.empty-state>p.empty-connect{margin-top:var(--s4)}
/* A shorter window sheds DECORATION and nothing else. The first draft of this
   also hid the three steps, the trust note and the connect line, and the
   mobile-adaptation guard caught it — correctly. Those are the sentences a
   stranger reads before deciding to trust this with their code; the box
   scrolls, so there is no reason to delete them. Only the orb goes, which is a
   badge, and the stack tightens. */
@media(max-height:820px){
 .empty-state{padding-top:var(--s4)}
 .engineer-orb{display:none}
 .empty-state>p:not(.overline){margin:var(--s3) auto var(--s4)}
 .how-it-goes{gap:var(--s2)}
 .how-it-goes li{padding:var(--s2) var(--s3)}
 .examples-label{margin:var(--s4) 0 var(--s2)}
 .empty-cta{margin-top:var(--s4)}
 /* The headline steps down one DECLARED step. MEASURED at 1600x750: at the
    display size it takes two lines and 104px; this is the difference between a
    first screen that fits and one that shows a scrollbar, which reads as a
    panel edge rather than as more content. Still a token, still on the scale. */
 .empty-state h1{font-size:var(--text-display-sm)}
 .empty-state .overline{margin-bottom:var(--s1)}
}

/* Two routes, side by side, neither presented as the only way in. */
.empty-cta .ghost{padding:8px 14px;font-size:var(--text-sm)}
