/* L3D8 styles.
   Split out of index.html: the page was 163 KB with everything inside it,
   which made every change a search through one enormous file. Markup lives
   in index.html, behaviour in app.js, and this is the styling. */

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
  --bg:#09090b;--surface:#111113;--surface2:#17171a;--surface3:#1d1d21;
  --border:#232328;--border-l:#2c2c32;
  --text:#e4e4e8;--text2:#a8a8b4;--muted:#9a9aa8;--dim:#9a9aa8;
  --accent:#4a8cff;--accent2:#5a9aff;--accent-bg:rgba(74,140,255,.08);
  --silver:#9898a8;
  --err:#ef4444;--green:#22c55e;
  --sidebar-w:260px;
  --mono:'IBM Plex Mono',monospace;--sans:'Inter',system-ui,-apple-system,sans-serif;
  --r:6px;--r2:10px;--r3:14px;
  --accent-rgb:74,140,255;
  /* Stacking, lowest to highest. One place to see what sits over what. */
  --z-float:4;--z-header:5;--z-overlay:13;--z-scrim:14;--z-rail:14;--z-panel:15;
  --z-preview:16;--z-modal:20;--z-login:30;--z-banner:40;--z-toast:50;
}
html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--sans);font-size:15px;line-height:1.6;overflow:hidden;-webkit-font-smoothing:antialiased;
  /* Stops iOS double-tap zoom, which makes every button feel like it missed */
  touch-action:manipulation;
  /* Prevents the rubber-band scroll revealing white behind the app */
  overscroll-behavior:none}
/* 100dvh accounts for the mobile browser chrome that appears and disappears;
   100vh does not, and leaves the input bar under the address bar. */
@supports (height:100dvh){ html,body{height:100dvh} }
/* --app-h / --app-top come from visualViewport (see syncViewport in the
   script). iOS does not resize the layout when the keyboard opens, it only
   shrinks what you can see, so without this the input bar sits under the
   keyboard. Falls back to 100dvh where visualViewport is missing. */
#shell{position:fixed;left:0;right:0;top:var(--app-top,0);height:var(--app-h,100dvh)}
html{-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%}
.sb-scroll,#messages,#welcome,.mp-body,#plan-panel,.modal{overscroll-behavior:contain}
button{font-family:var(--sans)}

/* ═══ LAYOUT ═══ */
/* No height here: --app-h above is what follows the iPhone keyboard. */
#shell{display:flex}
#shell.hidden{display:none}

/* ═══ SIDEBAR ═══ */
#sidebar{width:var(--sidebar-w);background:var(--surface);display:flex;flex-direction:column;flex-shrink:0;border-right:1px solid var(--border);padding-left:env(safe-area-inset-left)}
.sb-top{padding:14px 16px 10px;display:flex;align-items:center;gap:8px}
.sb-top .logo{font-size:18px;font-weight:700;letter-spacing:-.03em;flex:1}
.sb-top .logo .a{color:var(--text)}
.sb-top .logo .i{color:var(--accent)}

/* sections */
.sb-scroll{flex:1;overflow-y:auto;padding:0 8px;-webkit-overflow-scrolling:touch}
.sb-label{font-size:10px;font-weight:600;color:var(--dim);text-transform:uppercase;letter-spacing:.08em;padding:12px 8px 4px}

/* projects */
.proj-item{display:flex;align-items:flex-start;gap:10px;padding:10px 8px 10px 14px;border-radius:var(--r2);cursor:pointer;
  margin-bottom:14px;transition:background .12s,border-color .15s;border:1px solid var(--border)}
.proj-item:hover{border-color:var(--border-l)}
.proj-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
/* One line, always present: every row is name, description, repository, so
   they all come out the same height. The full text is in the row's title. */
.proj-desc{font-size:11.5px;line-height:1.4;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.proj-repo{display:flex;align-items:center;gap:4px;font-family:var(--mono);font-size:10.5px;color:var(--accent);opacity:.85;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:1px}
.proj-repo svg{flex-shrink:0;opacity:.8}
.proj-repo.none{color:var(--dim)}
.proj-item:hover{background:var(--surface2)}
/* Selected project lights up: tinted fill, and an accent border drawn all the
   way round the inside of the row (border plus an inset ring), with a soft
   glow. No icon or edge bar needed to tell which one is active. */
.proj-item.active{background:rgba(var(--accent-rgb),.13);border-color:var(--accent);
  box-shadow:inset 0 0 0 1px rgba(var(--accent-rgb),.35),0 4px 18px rgba(var(--accent-rgb),.14)}
.proj-item.active .proj-name{color:#fff}
.proj-item.active .proj-desc{color:var(--text2)}
.proj-name{font-size:13.5px;font-weight:600;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.35}
.proj-item.active .proj-name{color:var(--text)}
.sb-label-row{display:flex;align-items:center;justify-content:space-between;padding:8px 2px 6px 8px}
.sb-label-row .sb-label{padding:0}
.proj-add{display:inline-flex;align-items:center;gap:4px;padding:4px 9px;border-radius:var(--r);cursor:pointer;
  font-size:12px;font-weight:600;color:var(--text2);background:transparent;border:1px solid var(--border);transition:all .15s}
.proj-add:hover{color:var(--accent);border-color:rgba(var(--accent-rgb),.45);background:rgba(var(--accent-rgb),.08)}
.proj-add span{font-size:14px;line-height:1}

/* divider */

/* chats */
.conv-item{padding:8px 10px;border-radius:var(--r);cursor:pointer;font-size:13px;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:1px;transition:all .1s}
.conv-item:hover{background:var(--surface2)}
.conv-item.active{background:var(--accent-bg);color:var(--text)}
.proj-cog{width:28px;height:28px;border-radius:var(--r);display:flex;align-items:center;justify-content:center;cursor:pointer;
  flex-shrink:0;margin-left:auto;align-self:center;color:var(--muted);background:transparent;border:1px solid transparent;
  transition:color .15s,background .15s,border-color .15s}
.proj-cog:hover{color:var(--text);background:var(--surface3);border-color:var(--border-l)}
.proj-cog svg{transition:transform .3s ease}
.proj-cog:hover svg{transform:rotate(60deg)}
.conv-del{position:absolute;right:8px;top:50%;transform:translateY(-50%);color:var(--dim);font-size:14px;cursor:pointer;opacity:0;transition:all .15s;padding:2px 4px;border-radius:3px}
.conv-item,.proj-item{position:relative}
.conv-item:hover .conv-del{opacity:1}
.conv-del:hover{color:var(--err);background:rgba(239,68,68,.1)}
.conv-item{padding-right:28px}
.conv-time{font-family:var(--mono);font-size:12px;color:var(--dim);display:block;margin-top:1px}

/* footer */
.sb-foot{padding:10px 12px;border-top:1px solid var(--border);display:flex;align-items:center;gap:8px;position:relative}
.user-home{display:flex;align-items:center;gap:8px;flex:1;min-width:0;background:none;border:none;cursor:pointer;padding:4px 6px;border-radius:var(--r);transition:background .15s;text-align:left}
.user-home:hover,.user-home[aria-expanded=true]{background:var(--surface2)}
/* Account/settings menu that lifts up from the sidebar foot, so Home, Memory,
   Account, GitHub and Install are one tap away from inside any chat. */
.sb-menu{position:absolute;left:12px;right:12px;bottom:calc(100% - 4px);z-index:40;
  background:var(--surface);border:1px solid var(--border);border-radius:10px;
  box-shadow:0 10px 30px rgba(0,0,0,.45);padding:6px;display:flex;flex-direction:column;gap:2px}
.sb-menu.hidden{display:none}
.sb-mi{display:flex;align-items:center;gap:10px;width:100%;background:none;border:none;cursor:pointer;
  color:var(--text2);font-size:13px;font-weight:500;text-align:left;padding:9px 10px;border-radius:8px;transition:background .12s,color .12s}
/* A menu item carrying .hidden (the Agents item for non-admins) must actually
   hide: .sb-mi sets display:flex, and there is no generic .hidden rule, so
   without this the class is inert and the button shows for everyone. */
.sb-mi.hidden{display:none}
.sb-mi:hover{background:var(--surface2);color:var(--text)}
.sb-mi-ico{display:flex;color:var(--dim);flex-shrink:0}
.sb-mi:hover .sb-mi-ico{color:var(--accent)}
.sb-foot .av{width:28px;height:28px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#fff;flex-shrink:0;text-shadow:0 1px 2px rgba(0,0,0,.4)}
.sb-foot .uname{font-size:13px;color:var(--text2);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sb-foot .gear{background:none;border:none;color:var(--dim);cursor:pointer;font-size:15px;padding:4px;transition:color .15s}
.sb-foot .gear:hover{color:var(--text2)}

/* ═══ MAIN ═══ */
#main{flex:1;display:flex;flex-direction:column;min-width:0;overflow-x:hidden}
.main-head{min-height:44px;padding:10px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;background:var(--surface)}
.main-head .title{font-size:13px;font-weight:600;color:var(--text2);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.main-head .badge{font-family:var(--mono);font-size:10px;color:var(--dim);background:var(--surface2);border:1px solid var(--border);border-radius:10px;padding:2px 8px}
/* Lives in the chat header, far right, so it is in the same place on every
   screen. It used to sit in the sidebar, which is a hidden drawer on phones -
   exactly where an update prompt cannot be seen. */
/* Deep green, the same darkness as the working blue, so the two read as one
   family rather than a neon badge next to a navy row. */
#update-pill{display:none;align-items:center;gap:4px;margin-left:auto;flex-shrink:0;background:#14632f;color:#e8f7ee;border:1px solid #1d7a3c;
  border-radius:14px;font-size:12px;font-weight:600;padding:5px 12px;cursor:pointer;font-family:var(--sans);
  animation:pill-pulse 1.8s ease-in-out infinite;box-shadow:0 0 0 0 rgba(29,122,60,.6)}
#update-pill.show{display:inline-flex!important}
#update-pill.updating{cursor:default;opacity:.92}
@keyframes pill-pulse{
  0%{box-shadow:0 0 0 0 rgba(29,122,60,.6)}
  70%{box-shadow:0 0 0 8px rgba(29,122,60,0)}
  100%{box-shadow:0 0 0 0 rgba(29,122,60,0)}
}

/* Preview: the project's own app, running in a throwaway container, shown
   beside the chat rather than described. */
/* One control for the project: preview, publish, rename, take down. */
#proj-cog{display:none;align-items:center;justify-content:center;background:transparent;color:var(--text2);
  border:1px solid var(--border);border-radius:var(--r);padding:6px 9px;cursor:pointer;
  flex-shrink:0;margin-left:8px;transition:all .15s;position:relative}
/* Alone in the corner, the cog takes the spare room itself. */
.main-head > #proj-cog:first-of-type{margin-left:auto}
#proj-cog.show{display:inline-flex}
/* Try the project here, without publishing it. Shown inside a project. */
#pv-open{display:inline-flex;align-items:center;gap:5px;background:transparent;color:var(--text2);
  border:1px solid var(--border);border-radius:var(--r);padding:6px 11px;cursor:pointer;flex-shrink:0;
  margin-left:8px;font-size:12.5px;font-weight:600;font-family:var(--sans);transition:all .15s}
#pv-open:hover{color:var(--accent);border-color:rgba(var(--accent-rgb),.45);background:rgba(var(--accent-rgb),.08)}
#pv-open.hidden{display:none}
@media(pointer:coarse){#pv-open{min-height:40px}}
.hub-section-row{display:flex;align-items:center;justify-content:space-between;gap:10px}
.hub-section-row .proj-add{text-transform:none;letter-spacing:0}
.tool-line{font-size:13px;color:var(--text2);margin:6px 0}
.tool-line code{font-size:12px}
#proj-cog:hover{color:var(--accent);border-color:rgba(var(--accent-rgb),.45);background:rgba(var(--accent-rgb),.08)}
#proj-cog svg{transition:transform .3s ease;display:block}
/* #proj-cog is the globe/Live button now, not a cog - a spinning globe on
   hover looked accidental, so no rotate here (the sidebar .proj-cog gear keeps
   its own hover). */
/* A dot rather than a colour change: the cog still has to read as a cog. */
#proj-cog.live::after{content:"";position:absolute;top:-3px;right:-3px;width:8px;height:8px;
  border-radius:50%;background:var(--green);border:2px solid var(--surface)}
@media(pointer:coarse){#proj-cog{min-height:40px;min-width:42px}}

#preview-panel{position:fixed;top:0;right:0;width:46%;min-width:360px;max-width:760px;height:100%;
  background:var(--surface);border-left:1px solid var(--border);z-index:var(--z-preview);display:flex;flex-direction:column;
  transform:translateX(100%);transition:transform .25s ease;padding-right:env(safe-area-inset-right)}
#preview-panel.open{transform:translateX(0)}
@media(max-width:900px){#preview-panel{width:100%;max-width:100%;min-width:0}}
.pv-head{display:flex;align-items:center;gap:8px;padding:max(12px,env(safe-area-inset-top)) 14px 12px;
  border-bottom:1px solid var(--border)}
.pv-head h3{font-size:13px;font-weight:600;color:var(--text2);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pv-btn{background:var(--surface2);border:1px solid var(--border);border-radius:var(--r);color:var(--text2);
  font-size:11px;font-weight:600;padding:6px 10px;cursor:pointer}
.pv-btn:hover{border-color:var(--accent);color:var(--text)}
@media(pointer:coarse){.pv-btn{min-height:40px;font-size:13px;padding:8px 12px}}
#preview-frame{flex:1;border:none;background:#fff;width:100%}
.pv-status{padding:12px 14px;font-size:12px;color:var(--muted);line-height:1.6;border-top:1px solid var(--border);
  font-family:var(--mono);white-space:pre-wrap;max-height:180px;overflow:auto;display:none}
.pv-status.show{display:block}

/* task plan checklist */
#plan-rail{position:fixed;top:0;right:0;width:340px;max-width:88vw;height:100%;background:var(--surface);border-left:1px solid var(--border);z-index:var(--z-rail);display:flex;flex-direction:column;transition:transform .25s ease;transform:translateX(100%);pointer-events:none;padding-right:env(safe-area-inset-right)}
#plan-rail.open{transform:translateX(0);pointer-events:auto}
/* On a wide screen, make room so the rail sits beside the chat instead of over
   it - the plan is always-on, so it should not cover the conversation. */
@media(min-width:1100px){ #main{transition:margin-right .25s ease} body.plan-open #main{margin-right:340px} body.agents-open #main{margin-right:440px} }
/* On a wide screen the Agents panel sits beside the chat, like the task rail -
   no dimming scrim, so the conversation and the review panel are both usable. */
@media(min-width:1100px){ #ag-overlay{display:none!important} }
/* On a phone the 340px cap above still leaves an awkward sliver of chat
   showing behind the scrim - make it a proper full-width sheet instead. */
@media(max-width:480px){ #plan-rail{width:100%;max-width:100%} }
.rail-head{display:flex;align-items:center;padding:14px 16px;border-bottom:1px solid var(--border)}
.rail-head h3{font-size:13px;font-weight:600;flex:1;color:var(--text2)}
/* The close ("Done") control shows on every size now, so the task plan can be
   opened and closed from its pill on desktop as well as mobile. */
.rail-toggle{display:block;background:none;border:none;color:var(--dim);cursor:pointer;
  font-size:20px;line-height:1;padding:2px 6px;border-radius:6px}
.rail-toggle:hover{color:var(--text2);background:var(--surface2)}
#plan-panel{flex:1;overflow-y:auto;padding:14px 16px;font-size:13px;-webkit-overflow-scrolling:touch}
.rail-overlay{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:var(--z-overlay);opacity:0;pointer-events:none;transition:opacity .2s}
.rail-overlay.open{opacity:1;pointer-events:auto}
/* On a wide screen the rail sits beside the chat without an overlay; on
   narrow screens it slides over with a scrim, like the sidebar drawer. */
@media(min-width:1100px){.rail-overlay{display:none}}
.plan-goal{font-weight:600;color:var(--text);margin-bottom:8px;display:flex;align-items:center;gap:7px}
.plan-goal::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--accent);flex-shrink:0}
.plan-note{display:block;font-size:11.5px;color:var(--dim);margin-top:2px;line-height:1.35}
.plan-step{display:flex;align-items:flex-start;gap:8px;padding:3px 0;color:var(--text2);line-height:1.5}
.plan-step.done{color:var(--dim)}
.plan-box{width:14px;height:14px;border:1.5px solid var(--border-l);border-radius:3px;flex-shrink:0;margin-top:2px;display:flex;align-items:center;justify-content:center;font-size:10px}
.plan-step.done .plan-box{background:var(--accent);border-color:var(--accent);color:#fff}
.plan-step.done .plan-text{text-decoration:line-through}
/* Task history: finished plans, folded shut, newest first. */
.plan-hist-head{font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);padding:12px 2px 4px;margin-top:8px;border-top:1px solid var(--border)}
.plan-hist{border-bottom:1px solid var(--border)}
.plan-hist-top{display:flex;align-items:center;gap:8px;width:100%;background:none;border:none;color:var(--text);text-align:left;padding:10px 2px;cursor:pointer;font:inherit;min-height:44px}
.plan-hist-caret{color:var(--muted);font-size:11px;width:12px;flex:none}
.plan-hist-goal{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:13px;font-weight:600}
.plan-hist-meta{color:var(--muted);font-size:11px;white-space:nowrap;flex:none}
.plan-hist-steps{padding:0 2px 10px 24px}
/* The collapsed state: a small tappable pill instead of the full drawer.
   Desktop never shows this - the rail just stays docked beside the chat. */
/* Bottom right, above the composer. Solid enough to read at a glance - the
   translucent version faded into the dark background and could not be found.
   It still sits over the chat, so it stays small and rounded rather than
   spanning the width, and the progress bar carries the state without needing
   more words. */
/* In the header, top right. Over the chat it was in the way wherever it sat,
   because the bottom of the chat is where the answer arrives. Up here it is
   out of the reading path and always in the same place.
   It shares that corner with the update button and gives way to it: an update
   is a thing to act on, a plan is a thing to glance at. */
.plan-fab{display:none;flex-direction:column;align-items:stretch;gap:3px;cursor:pointer;
  background:transparent;border:1px solid rgba(var(--accent-rgb),.35);border-radius:var(--r);
  padding:4px 10px;flex-shrink:0;margin-left:auto;
  font-size:11.5px;font-weight:600;color:var(--text2);font-family:var(--sans);
  transition:border-color .15s,color .15s}
.plan-fab:hover{border-color:var(--accent);color:var(--text)}
.plan-fab:active{transform:scale(.97)}
.plan-fab-top{display:flex;align-items:center;gap:6px;white-space:nowrap}
/* A hairline under the label: progress without another number to read. */
.plan-fab-bar{height:2px;border-radius:2px;background:rgba(255,255,255,.12);overflow:hidden}
.plan-fab-fill{display:block;height:100%;background:var(--accent);border-radius:2px;
  transition:width .4s ease}
@media(max-width:360px){.plan-fab{font-size:11px;padding:4px 8px}}
.plan-fab.show{display:inline-flex}
/* The task-plan pill belongs to a project. On the home screen (no project
   selected) it is hidden outright, whatever any show logic does. */
html.no-project .plan-fab{display:none!important}
.plan-fab-dot{width:7px;height:7px;border-radius:50%;background:var(--accent);flex-shrink:0}


/* GitHub project hub on the landing screen */
/* Publish: prefix and name read as one address */
.pub-addr{display:flex;align-items:stretch;background:var(--bg);border:1px solid var(--border);
  border-radius:var(--r);overflow:hidden;transition:border-color .15s}
.pub-addr:focus-within{border-color:var(--accent)}
.pub-prefix{display:flex;align-items:center;padding:0 1px 0 11px;font-family:var(--mono);
  font-size:12.5px;color:var(--dim);white-space:nowrap;flex-shrink:0}
.pub-addr input{border:none!important;background:transparent!important;margin:0!important;
  padding-left:2px!important;min-width:0}
@media(max-width:480px){.pub-prefix{font-size:11px;padding-left:8px}}

/* "Still working" while the page waits for a run it lost the stream to. A
   quiet pulse rather than a spinner: it is waiting, not loading. */
.working{display:inline-flex;align-items:center;gap:8px;color:var(--text2)}
.working-dot{width:8px;height:8px;border-radius:50%;background:var(--accent);flex-shrink:0;
  animation:workingpulse 1.4s ease-in-out infinite}
.working-what{display:inline-flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.working-doing{color:var(--accent);font-size:12.5px}

/* The dots sit with the text rather than above it. */
.working .thinking-dots{align-self:center}

/* The page you just made, showing. Bordered and a little bigger than the text
   around it, because it is the point of everything above it. */
.live-card{margin:16px 0 6px;padding:16px 18px;border:1px solid rgba(34,197,94,.30);
  border-radius:var(--r2);background:var(--surface)}
.live-title{font-size:17px;font-weight:600;color:var(--text);line-height:1.3}
/* The address, as text. Something later in the pipeline turns a bare URL into
   a link and styles it like code; here it is a caption under a heading, so it
   is overridden back to plain. */
.live-card .live-url,.live-card .live-url a,.live-card .live-url code{
  font-size:12.5px;color:var(--muted);margin-top:4px;font-family:var(--mono);
  word-break:break-all;background:none;border:0;padding:0;text-decoration:none;
  display:inline}
.live-actions{display:flex;gap:9px;margin-top:14px}
.live-card .live-open,.live-card .live-share{flex:1;text-align:center;padding:12px 14px;
  border-radius:var(--r);font-size:14.5px;font-weight:600;cursor:pointer;
  border:1px solid transparent;min-height:46px;display:inline-flex;
  align-items:center;justify-content:center;line-height:1}
.live-card .live-open{background:var(--accent);color:#fff;text-decoration:none}
.live-card .live-open:hover{background:var(--accent2);color:#fff}
.live-card .live-share{background:transparent;color:var(--text2);border-color:var(--border-l)}
.live-card .live-share:hover{color:var(--text);border-color:var(--muted)}

/* Disabled while it works. Dimmed rather than greyed out like a broken
   control: nothing is wrong, it is simply not this moment's job. */
#prompt:disabled{opacity:.55;cursor:default;background:transparent}

/* Something the app did on its own, explained. Not a message from anyone, so
   no name above it and no bubble around it. */
.thread-note{max-width:700px;margin:6px auto 10px;padding:0 14px;
  font-size:12.5px;color:var(--muted);font-style:italic}

/* Asking whether to carry on, where the reply stopped. A question and a
   button, not an error: nothing has gone wrong that cannot be continued. */
.carry-on{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  max-width:700px;margin:2px auto 14px;padding:0 14px}
.carry-why{font-size:13px;color:var(--text2);flex:1 1 220px;line-height:1.5}
.carry-go{background:var(--accent);color:#fff;border:0;border-radius:var(--r);
  padding:10px 20px;font-size:14px;font-weight:600;cursor:pointer;min-height:44px}
.carry-go:hover{background:var(--accent2)}

/* The single waiting notice. No name above it and no separator: it is a
   status line at the end of the thread, not a message from anyone. */
#waiting-row .who{display:none}
#waiting-row{border-top:none;background:none;padding-top:4px}

/* What it has done so far, above the line saying what it is doing now. Quiet
   and small: a record, not the headline. */
.did{list-style:none;margin:0 0 10px;padding:0 0 0 12px;border-left:2px solid var(--border)}
.did li{font-size:12.5px;color:var(--muted);line-height:1.8;position:relative}
.did li::before{content:'';position:absolute;left:-17px;top:10px;width:4px;height:4px;
  border-radius:50%;background:var(--border-l)}
.did li:last-child{color:var(--text2)}
.working-time{color:var(--muted);font-variant-numeric:tabular-nums;font-size:12px}
@keyframes workingpulse{0%,100%{opacity:.3;transform:scale(.85)}50%{opacity:1;transform:scale(1.1)}}
@media(prefers-reduced-motion:reduce){.working-dot{animation:none;opacity:.9}}

/* Why a field looks the way it does - an empty repository box, say. Quiet,
   because it is an explanation rather than an error. */
.field-note{font-size:12px;color:var(--muted);line-height:1.5;margin-top:6px}
.field-note.hidden{display:none}

/* A file being written right now. The same dots as everywhere else, the name
   of the file, and a size that counts up so a long write reads as progress. */
.writing{display:flex;align-items:center;gap:10px;margin:10px 0;padding:11px 13px;
  border:1px solid var(--border);border-radius:var(--r2);background:var(--surface2)}
.writing-what{flex:1;font-size:13px;color:var(--text2);min-width:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.writing-what b{font-family:var(--mono);font-size:12.5px;color:var(--text);font-weight:600}
.writing-size{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums;flex-shrink:0}

/* A file the assistant wrote. Closed by default, because the interesting
   thing is usually that it wrote index.html, not the 400 lines inside it -
   and open on a tap, with the same highlighting as any code block. */
.filecard{border:1px solid var(--border);border-radius:var(--r2);background:var(--surface);
  margin:10px 0;overflow:hidden}
.filecard:hover{border-color:var(--border-l)}
.fc-head{display:flex;align-items:center;gap:9px;padding:10px 12px;cursor:pointer;
  background:var(--surface2);user-select:none}
.fc-head:hover{background:rgba(255,255,255,.04)}
.fc-chev{color:var(--muted);flex-shrink:0;transition:transform .18s ease}
.filecard.open .fc-chev{transform:rotate(90deg)}
.fc-name{font-family:var(--mono);font-size:12.5px;color:var(--text);font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:50%}
.fc-meta{font-size:11.5px;color:var(--muted);flex:1;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.fc-copy{flex-shrink:0;background:transparent;border:1px solid var(--border);border-radius:var(--r);
  color:var(--muted);font-family:var(--sans);font-size:11px;font-weight:600;padding:4px 9px;cursor:pointer}
.fc-copy:hover{color:var(--text);border-color:var(--accent)}
/* Collapsed by height so opening animates instead of jumping. */
.fc-body{max-height:0;overflow:hidden;transition:max-height .25s ease}
.filecard.open .fc-body{max-height:70vh;max-height:70dvh;overflow:auto}
.fc-body pre{margin:0;border:none;border-radius:0;border-top:1px solid var(--border)}
@media(max-width:480px){
  .fc-meta{flex-basis:100%;order:3;flex:none;padding-left:23px}
  .fc-head{flex-wrap:wrap;row-gap:4px}
  .fc-name{max-width:none;flex:1}
}

/* The live-site card that follows a reply which published something */
/* A turn that produced nothing at all. Says so, and offers the one thing
   worth doing about it. */
.stalled{display:flex;flex-direction:column;gap:10px;align-items:flex-start;
  background:rgba(234,179,8,.07);border:1px solid rgba(234,179,8,.26);
  border-radius:var(--r2);padding:13px 15px;font-size:13px;color:var(--text2);line-height:1.5}
.stalled button{align-self:flex-start}


/* Live confirmation */
.live-top{display:flex;align-items:center;gap:9px;margin-bottom:14px}
.live-dot{width:9px;height:9px;border-radius:50%;background:var(--green);flex-shrink:0;
  box-shadow:0 0 0 4px rgba(34,197,94,.16)}
.live-url{display:block;font-family:var(--mono);font-size:13px;color:var(--accent);
  background:var(--bg);border:1px solid var(--border);border-radius:var(--r);
  padding:12px 13px;text-decoration:none;overflow-wrap:anywhere;line-height:1.5}
.live-url:hover{border-color:var(--accent)}
.live-note{font-size:11.5px;color:var(--muted);line-height:1.6;margin-top:9px}

/* Account modal */
.acct-head{display:flex;align-items:center;gap:12px;margin-bottom:18px}
.acct-av{width:44px;height:44px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;
  font-size:18px;font-weight:700;color:#fff;flex-shrink:0;text-shadow:0 1px 2px rgba(0,0,0,.4)}
.acct-who{flex:1;min-width:0}
.acct-name{font-size:16px;font-weight:700;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.acct-sub{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.modal-x{background:none;border:none;color:var(--muted);font-size:22px;line-height:1;cursor:pointer;padding:6px 8px;border-radius:var(--r);margin:-6px -8px 0 0;align-self:flex-start}
.modal-x:hover{color:var(--text);background:var(--surface2)}
.acct-section{font-size:11px;font-weight:600;color:var(--dim);text-transform:uppercase;letter-spacing:.08em;padding-top:14px;border-top:1px solid var(--border)}
.acct-ok{color:var(--green)!important}
/* Sign out sits with the other buttons, pushed to the far side - it is a
   different kind of action, not a bigger one. */
.acct-btns{align-items:center}
.acct-signout{margin-right:auto;background:none;border:1px solid rgba(239,68,68,.3);color:var(--err);
  border-radius:var(--r);font-size:12px;font-weight:600;padding:8px 14px;cursor:pointer;transition:all .15s}
.acct-signout:hover{background:rgba(239,68,68,.1);border-color:var(--err)}
@media(pointer:coarse){.acct-signout{min-height:44px;font-size:13px}}
@media(max-width:380px){.acct-signout{padding:8px 10px}}
/* Fills the dashboard so the footer sits at the bottom of the screen, not
   just after the last card. */
#gh-hub{width:100%;max-width:760px}
/* Home screen settings bar. Built like the sidebar footer and the chat header
   - surface background, single hairline, full width of the area - so the app
   has one bar treatment rather than three. */
#hub-foot{display:none;flex-shrink:0;background:var(--surface);border-top:1px solid var(--border);
  padding:8px 24px max(8px,env(safe-area-inset-bottom))}
#hub-foot.show{display:block}
.hf-inner{max-width:760px;margin:0 auto;display:flex;gap:6px}
.hf-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:7px;
  background:transparent;border:1px solid transparent;border-radius:var(--r);
  color:var(--text2);font-family:var(--sans);font-size:12.5px;font-weight:600;
  padding:9px 10px;cursor:pointer;transition:all .15s;white-space:nowrap}
.hf-btn:hover{color:var(--text);background:var(--surface2);border-color:var(--border)}
.hf-ico{display:flex;align-items:center;justify-content:center;color:var(--muted);transition:color .15s}
.hf-btn:hover .hf-ico{color:var(--accent)}
.hub-head{display:flex;align-items:center;gap:12px;margin-bottom:20px}
.hub-head h2{font-size:20px;font-weight:700;letter-spacing:-.02em;flex:1}
.gh-connect{display:inline-flex;align-items:center;gap:7px;background:#238636;color:#fff;border:none;border-radius:var(--r);font-size:13px;font-weight:600;padding:8px 16px;cursor:pointer;transition:all .15s}
.gh-connect:hover{background:#2ea043}
/* The persistent "GitHub connected" status card on the home hub. */
.gh-status{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);padding:12px 14px;margin-bottom:20px;max-width:440px}
/* Brief highlight when "GitHub" is tapped in the menu, so the jump is obvious. */
#hub-gh.gh-flash>*{animation:ghFlash 1.4s ease}
@keyframes ghFlash{0%,100%{box-shadow:0 0 0 0 transparent}15%{box-shadow:0 0 0 3px var(--accent)}}
.gh-status-head{display:flex;align-items:center;gap:7px;font-size:13px;font-weight:700;color:var(--text);margin-bottom:8px}
.gh-check{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background:#238636;color:#fff;font-size:11px;font-weight:700}
.gh-acct{display:flex;align-items:center;gap:8px;padding:5px 0;font-size:13px}
.gh-acct-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
.gh-acct-dot.ok{background:#2ea043}
.gh-acct-dot.warn{background:#d29922}
.gh-acct-name{font-weight:600;color:var(--text)}
.gh-acct-note{color:var(--dim);font-size:11.5px;margin-left:auto}
.gh-mini{margin-left:auto;background:#238636;color:#fff;border:none;border-radius:8px;padding:5px 11px;font-size:12px;font-weight:600;cursor:pointer}
.gh-mini:hover{background:#2ea043}
.gh-add{margin-top:8px;background:none;border:none;color:var(--accent);font-size:12.5px;font-weight:500;cursor:pointer;padding:4px 0}
.gh-add:hover{text-decoration:underline}
.hub-note{color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:20px}
.hub-section{font-size:11px;font-weight:600;color:var(--dim);text-transform:uppercase;letter-spacing:.08em;margin:22px 0 9px}
.hub-section:first-child{margin-top:0}

/* Home hero: the calm focal point of the home screen. One heading, one line,
   one clear button - the projects the person already has sit below it. */
.hub-hero{margin:2px 0 26px;padding:26px 24px;border-radius:calc(var(--r) + 6px);
  background:radial-gradient(130% 150% at 0% 0%, var(--accent-bg), transparent 62%), var(--surface);
  border:1px solid var(--border)}
.hub-hero h1{margin:0 0 6px;font-size:24px;font-weight:700;color:var(--text);letter-spacing:-.01em}
.hub-hero p{margin:0 0 18px;color:var(--text2);font-size:14px;line-height:1.5;max-width:52ch}
.hero-cta{display:inline-flex;align-items:center;gap:7px;padding:11px 20px;border:none;cursor:pointer;
  border-radius:999px;font-size:15px;font-weight:600;color:#fff;
  background:linear-gradient(135deg,var(--accent),var(--accent2));
  box-shadow:0 6px 18px rgba(var(--accent-rgb),.35);transition:transform .12s ease,box-shadow .12s ease}
.hero-cta:hover{transform:translateY(-1px);box-shadow:0 8px 22px rgba(var(--accent-rgb),.45)}
.hero-cta:active{transform:translateY(0)}
.hero-cta span{font-size:18px;line-height:1}
.hero-ideas{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.idea-chip{background:var(--surface2);border:1px solid var(--border);color:var(--text2);cursor:pointer;
  font-size:13px;font-weight:500;padding:8px 13px;border-radius:999px;transition:background .12s,color .12s,border-color .12s}
.idea-chip:hover{background:var(--surface3);color:var(--text);border-color:var(--border-l)}
@media (max-width:640px){
  .hub-hero{padding:20px 16px;margin-bottom:20px}
  .hub-hero h1{font-size:20px}
  .hero-cta{width:100%;justify-content:center;min-height:48px}
}
@media(pointer:coarse){.idea-chip{min-height:44px;padding:10px 15px}}
/* project cards on the landing screen */
.proj-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px;max-width:720px;width:100%}
.proj-card{text-align:left;background:var(--surface);border:1px solid var(--border);border-radius:var(--r2);padding:14px;cursor:pointer;transition:all .15s}
.proj-card:hover{border-color:var(--accent);transform:translateY(-2px)}
.proj-card-top{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.proj-card-icon{width:28px;height:28px;border-radius:var(--r);background:linear-gradient(135deg,rgba(var(--accent-rgb),.14),rgba(106,171,255,.08));border:1px solid rgba(var(--accent-rgb),.2);display:flex;align-items:center;justify-content:center;font-size:14px;flex-shrink:0}
.proj-card-name{font-size:14px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.proj-card-repo{font-family:var(--mono);font-size:11px;color:var(--accent);margin-bottom:6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.proj-card-repo.none{color:var(--dim)}
.repo-tag{margin-left:auto;font-size:9px;font-weight:600;padding:2px 7px;border-radius:8px;text-transform:uppercase;letter-spacing:.04em;background:var(--surface2);color:var(--dim);flex-shrink:0}
.repo-tag.new{background:rgba(var(--accent-rgb),.12);color:var(--accent)}
.proj-card.is-project{cursor:default;opacity:.7}
.proj-card.is-project:hover{border-color:var(--border);transform:none}
.proj-card-desc{font-size:12px;color:var(--muted);line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

/* Empty state for a project with no chats yet - the home hub belongs to the
   home screen, not inside a project. */
.chat-empty{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;padding:40px 24px;gap:6px}
.chat-empty h3{font-size:17px;font-weight:700;color:var(--text)}
.chat-empty p{font-size:13px;color:var(--muted);max-width:340px;line-height:1.6}
.chat-empty .ce-repo{font-family:var(--mono);font-size:11.5px;color:var(--accent);opacity:.9;margin-top:2px}

/* messages */
#messages{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overflow-anchor:none}
#messages.hidden{display:none}
/* End-of-thread marker the jump-to-latest observer watches. Takes no visible
   space; it only needs a measurable box at the very bottom of the thread. */
#msg-end{height:1px;width:100%;margin:0;padding:0;pointer-events:none;flex:none}
.msg-row{padding:18px 24px}
.msg-row.user{background:var(--surface)}
.msg-row.assistant{background:transparent}
.msg-inner{max-width:700px;margin:0 auto;position:relative}
.msg-who{font-size:11px;font-weight:600;margin-bottom:5px;letter-spacing:.02em}
.msg-who.user{color:var(--accent2)}
.msg-who.assistant{color:var(--silver)}
.msg-text{font-size:14.5px;line-height:1.7;color:var(--text);word-break:break-word;overflow-wrap:anywhere;max-width:100%}
.msg-text p{margin:0 0 8px}
.msg-text p:last-child{margin-bottom:0}
.msg-text pre{background:#0d0d12;border:1px solid var(--border);border-radius:var(--r);padding:14px 16px;overflow-x:auto;max-width:100%;margin:8px 0;font-size:13px;line-height:1.5;
  /* Tool output is shown in full rather than truncated - a shortened trace is
     as useless as none when something goes wrong. Capping the height keeps a
     long one from swamping the page without hiding any of it. */
  max-height:340px}
.msg-text pre code{background:none;border:none;padding:0;font-size:12.5px;line-height:1.65;
  display:block;tab-size:2;-moz-tab-size:2}
/* Syntax colours, tuned against the surface rather than pure hues so a long
   block does not glow. */
.t-key{color:#c792ea}
.t-str{color:#a5e88a}
.t-num{color:#f5a97f}
.t-com{color:#6b7280;font-style:italic}
.t-fn{color:#82aaff}
.t-tag{color:#ff8b8b}
.t-attr{color:#ffcb6b}
.msg-text code{font-family:var(--mono);font-size:12.5px;background:var(--surface2);border:1px solid var(--border);border-radius:3px;padding:1px 5px}
.msg-text ul,.msg-text ol{margin:6px 0;padding-left:20px}
.msg-text li{margin:2px 0}
.msg-text strong{font-weight:600;color:var(--text)}
.msg-text em{font-style:italic;color:var(--text2)}
.msg-text a{color:var(--accent);text-decoration:none}
.msg-text a:hover{text-decoration:underline}
.msg-text blockquote{border-left:3px solid var(--border-l);padding-left:12px;margin:8px 0;color:var(--text2)}
.msg-text h1,.msg-text h2,.msg-text h3{font-weight:600;margin:12px 0 6px;color:var(--text)}
.msg-text h1{font-size:18px}
.msg-text h2{font-size:16px}
.msg-text h3{font-size:14.5px}
.msg-text hr{border:none;border-top:1px solid var(--border);margin:12px 0}
.msg-text table{border-collapse:collapse;margin:8px 0;font-size:13px}
.msg-text th,.msg-text td{border:1px solid var(--border);padding:6px 10px;text-align:left}
.msg-text th{background:var(--surface2);font-weight:600}
.copy-btn{position:absolute;top:6px;right:6px;background:var(--surface3);border:1px solid var(--border);border-radius:4px;color:var(--muted);font-size:11px;padding:2px 8px;cursor:pointer;opacity:0;transition:opacity .15s;font-family:var(--mono)}
pre:hover .copy-btn{opacity:1}
/* Wide tables scroll inside the message instead of widening the page */
.msg-text table{display:block;max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}
/* The service restarts itself to deploy. For the seconds that takes, say so
   plainly rather than showing whatever error the browser invents. */
/* Part of the conversation, not a panel bolted under it. A box with a border
   and a tinted background reads as an alert - something has gone wrong, deal
   with it - when the message is simply that the work is still going. So: the
   same dots, the same muted text, the same left-aligned column as a reply. */
#offline-bar{display:flex;align-items:baseline;gap:9px;max-width:700px;
  /* No padding of its own: the same 700px column as a message, centred by the
     input bar's own padding, so its first word lines up with the reply above
     it rather than sitting 38px to the right. */
  /* The same 700px column as a message, centred by the input bar it sits in.
     Not pixel-matched to the message column on a wide screen: it sits inside a
     container with its own padding, and chasing that with negative margins
     broke the centring for a difference nobody would notice. */
  margin:0 auto 10px;padding:0;background:none;border:none;
  font-size:13px;color:var(--text2);line-height:1.5;flex-wrap:wrap}
#offline-bar.hidden{display:none}
.ob-text{flex:1;line-height:1.5}
.ob-try{color:var(--muted);font-size:12px;white-space:nowrap;font-variant-numeric:tabular-nums}
/* The reload is a quiet offer, not a call to action: the page comes back by
   itself, and this is only for the impatient. */
#offline-bar .wb-btn{background:none;border:none;color:var(--accent);
  font-size:12.5px;font-weight:600;padding:0;text-decoration:underline;
  text-underline-offset:3px}
#offline-bar .wb-btn:hover{color:var(--accent2)}
#offline-bar .thinking-dots{position:relative;top:-2px}
/* Wrapping is fine; the time and the reload should follow the sentence rather
   than being pushed to the far side of an empty row. */
/* One line: dots, sentence, clock. It is a status, not a paragraph, and
   wrapping it over three lines made it look like an error report. */
#offline-bar{flex-wrap:nowrap;align-items:center}
#offline-bar .ob-text{flex:0 1 auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#offline-bar .thinking-dots{top:0}
@media(max-width:600px){#offline-bar{row-gap:2px;padding:0;flex-wrap:wrap}#offline-bar .ob-text{white-space:normal}}

/* Working: the whole row breathes. A soft accent wash fading left to right,
   slowly rising and falling, with the border brightening in time. Slow and
   low contrast on purpose - it should read as "busy" from across the room
   without pulling the eye every second. Drawn on ::after behind the content
   (isolation keeps it above the row's own fill and below the text). The
   selected row keeps its solid border; only the wash breathes there. */
.proj-item{isolation:isolate}
.proj-item::after{content:"";position:absolute;inset:0;border-radius:inherit;z-index:-1;pointer-events:none;opacity:0;
  background:linear-gradient(100deg,rgba(22,48,140,.50) 0%,rgba(22,48,140,.20) 50%,rgba(22,48,140,0) 100%);
  transition:opacity .4s}
.proj-item.is-running::after{animation:row-breathe 2.8s ease-in-out infinite}
.proj-item.is-running:not(.active){animation:row-border 2.8s ease-in-out infinite}
@keyframes row-breathe{0%,100%{opacity:.25}50%{opacity:1}}
@keyframes row-border{0%,100%{border-color:rgba(28,58,165,.25)}50%{border-color:rgba(28,58,165,.85)}}
/* Finished since they last looked: the same breathing, in a deep green of the
   same darkness as the working navy. It stops once they open the project. */
.proj-item.is-done::after{background:linear-gradient(100deg,rgba(20,99,47,.55) 0%,rgba(20,99,47,.22) 50%,rgba(20,99,47,0) 100%);
  animation:row-breathe 2.8s ease-in-out infinite}
.proj-item.is-done:not(.active){animation:row-border-done 2.8s ease-in-out infinite}
@keyframes row-border-done{0%,100%{border-color:rgba(29,122,60,.25)}50%{border-color:rgba(29,122,60,.85)}}
@media(prefers-reduced-motion:reduce){
  .proj-item.is-running::after,.proj-item.is-done::after{animation:none;opacity:.6}
  .proj-item.is-running:not(.active){animation:none;border-color:rgba(28,58,165,.6)}
  .proj-item.is-done:not(.active){animation:none;border-color:rgba(29,122,60,.6)}
}

/* Shown when a reply ended on a question. It answers itself after a while
   rather than leaving a half-built thing waiting for someone who walked away. */
#waiting-bar{display:flex;align-items:center;gap:10px;max-width:700px;margin:0 auto 8px;
  background:rgba(234,179,8,.08);border:1px solid rgba(234,179,8,.28);border-radius:var(--r2);
  padding:10px 13px;font-size:12.5px;color:var(--text2)}
#waiting-bar.hidden{display:none}
.wb-dot{width:7px;height:7px;border-radius:50%;background:#eab308;flex-shrink:0}
.wb-text{flex:1;line-height:1.45}
.wb-text b{color:var(--text);font-variant-numeric:tabular-nums}
.wb-btn{background:var(--surface2);border:1px solid var(--border);border-radius:var(--r);
  color:var(--text2);font-family:var(--sans);font-size:11.5px;font-weight:600;
  padding:6px 10px;cursor:pointer;flex-shrink:0}
.wb-btn:hover{color:var(--text);border-color:var(--accent)}
@media(max-width:600px){#waiting-bar{flex-wrap:wrap}.wb-text{flex-basis:100%}
  .wb-btn{flex:1;min-height:40px}}

/* Jump-to-latest, shown only when scrolled up during or after a reply */
#jump-latest{position:absolute;left:50%;transform:translateX(-50%);bottom:calc(100% + 8px);
  width:36px;height:36px;border-radius:50%;background:var(--surface2);border:1px solid var(--border);
  color:var(--text2);font-size:16px;cursor:pointer;display:none;align-items:center;justify-content:center;
  box-shadow:0 4px 14px rgba(0,0,0,.35);z-index:var(--z-float)}
#jump-latest.show{display:flex}
#input-bar{position:relative}
.copy-btn:hover{color:var(--text);border-color:var(--border-l)}

/* Tool output peek. Three lines of the tail while it works, the whole thing on
   click. Showing everything turns the transcript into a terminal log; showing
   nothing leaves you guessing when something goes wrong. */
.peek{background:var(--bg);border:1px solid var(--border);border-radius:var(--r);
      margin:6px 0;cursor:pointer;transition:border-color .15s;overflow:hidden}
.peek:hover{border-color:var(--border-l)}
.peek-tail,.peek-full{font-family:var(--mono);font-size:11.5px;line-height:1.55;
           white-space:pre-wrap;word-break:break-word;padding:8px 12px;color:var(--muted)}
.peek-tail{
  /* Fade the top edge so it reads as a window onto more, rather than text that
     happens to have been cut. */
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 12px);
  mask-image:linear-gradient(180deg,transparent 0,#000 12px)}
.peek-full{display:none;max-height:420px;overflow:auto;color:var(--text2)}
.peek.open .peek-tail{display:none}
.peek.open .peek-full{display:block}
.peek-foot{font-family:var(--mono);font-size:10px;color:var(--dim);
           padding:4px 12px 6px;border-top:1px solid var(--border);background:var(--surface)}
.peek.open .peek-foot::after{content:" (open)"}

/* memory viewer */
#memory-panel,#agents-panel{position:fixed;top:var(--app-top,0);right:-440px;width:440px;height:var(--app-h,100%);background:var(--surface);border-left:1px solid var(--border);z-index:var(--z-panel);display:flex;flex-direction:column;transition:right .25s ease}
.mp-tabs{display:flex;padding:0 12px;gap:2px;border-bottom:1px solid var(--border)}
.mp-tab{flex:1;padding:8px;font-size:11px;font-weight:600;color:var(--muted);background:none;border:none;border-bottom:2px solid transparent;cursor:pointer;transition:all .15s}
.mp-tab:hover{color:var(--text2)}
.mp-tab.active{color:var(--text);border-bottom-color:var(--accent)}
.conf-badge{font-size:9px;font-weight:700;padding:1px 6px;border-radius:3px;text-transform:uppercase;letter-spacing:.04em}
.conf-high{background:rgba(34,197,94,.12);color:#4ade80;border:1px solid rgba(34,197,94,.25)}
.conf-medium{background:rgba(234,179,8,.12);color:#facc15;border:1px solid rgba(234,179,8,.25)}
.conf-low{background:rgba(239,68,68,.12);color:#f87171;border:1px solid rgba(239,68,68,.25)}
.verif-badge{font-size:9px;color:var(--dim);font-family:var(--mono)}
.mem-src{font-size:10px;color:var(--dim);font-style:italic;margin-top:4px;padding-left:8px;border-left:2px solid var(--border)}
.evidence-list{margin-top:8px;padding-top:8px;border-top:1px solid var(--border);display:none}
.evidence-list.open{display:block}
.ev-item{font-size:11px;padding:6px 8px;margin-bottom:4px;border-radius:4px;line-height:1.4}
.ev-supports{background:rgba(34,197,94,.06);border-left:2px solid #4ade80;color:var(--text2)}
.ev-contradicts{background:rgba(239,68,68,.06);border-left:2px solid #f87171;color:var(--text2)}
.ev-type{font-family:var(--mono);font-size:9px;color:var(--dim);text-transform:uppercase}
.mem-toggle{font-size:11px;color:var(--accent);cursor:pointer;margin-top:4px;display:inline-block;background:none;border:0;padding:0;font-family:var(--sans)}
.mem-toggle:hover{text-decoration:underline}
.review-reason{font-size:10px;font-weight:600;padding:2px 8px;border-radius:3px;background:rgba(239,68,68,.12);color:#f87171;border:1px solid rgba(239,68,68,.25)}
.mem-btn{background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--text2);font-size:10px;padding:3px 8px;cursor:pointer;margin-right:4px}
.mem-btn:hover{border-color:var(--accent);color:var(--text)}
.mem-btn.uphold:hover{border-color:#4ade80;color:#4ade80}
.mem-btn.retire:hover{border-color:var(--err);color:var(--err)}
#memory-panel.open,#agents-panel.open{right:0}
/* One build row on the agents page: title/meta on the left, star + open on the right. */
.ag-row{display:flex;align-items:center;gap:10px;padding:10px;border-bottom:1px solid var(--border)}
.ag-main{flex:1;min-width:0}
.ag-title{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ag-sub{font-size:11.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ag-star{background:none;border:none;cursor:pointer;font-size:20px;line-height:1;padding:4px;color:var(--muted)}
.ag-star.on{color:#eab308}
.ag-open{background:none;border:1px solid var(--border);color:var(--text);border-radius:8px;padding:6px 10px;font-size:12px;cursor:pointer}
.ag-review-head{padding:10px 12px 4px;font-size:12px;font-weight:700;color:var(--text);text-transform:uppercase;letter-spacing:.04em}
.ag-review-row{background:rgba(234,179,8,.06)}
.ag-review-row .ag-sub{white-space:normal}
.ag-keep{background:#eab308;border:none;color:#1a1a1a;border-radius:8px;padding:6px 12px;font-size:12px;font-weight:600;cursor:pointer}
/* Keep on the recent-builds list: an outline until kept, filled once kept. */
.ag-keep.ag-star{background:none;border:1px solid #eab308;color:#eab308;padding:6px 10px;font-size:12px;white-space:nowrap}
.ag-keep.ag-star.on{background:#eab308;color:#1a1a1a}
/* A build that did not finish (the server carries it on by itself). */
.ag-stuck-row .ag-sub{color:#f59e0b;white-space:normal;overflow:visible}
.ag-trash{background:none;border:1px solid var(--border);color:var(--muted);border-radius:8px;padding:6px 10px;font-size:12px;cursor:pointer;transition:all .15s}
.ag-trash:hover{border-color:#e5484d;color:#e5484d}
.mp-head{padding:14px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px}
.mp-head h3{font-size:14px;font-weight:600;flex:1}
.mp-head .close-btn{background:none;border:none;color:var(--muted);font-size:18px;cursor:pointer;padding:2px 6px}
.mp-head .close-btn:hover{color:var(--text)}
.mp-body{flex:1;overflow-y:auto;padding:8px}
.mem-item{padding:10px 12px;border:1px solid var(--border);border-radius:var(--r);margin-bottom:6px;background:var(--bg)}
.mem-content{font-size:13px;color:var(--text);line-height:1.5;margin-bottom:6px;overflow-wrap:anywhere;word-break:break-word}
.mem-meta{display:flex;align-items:center;gap:6px;font-size:10px;color:var(--dim);font-family:var(--mono);flex-wrap:wrap}
.mem-cat{background:var(--surface2);border:1px solid var(--border);border-radius:3px;padding:1px 6px;font-size:10px;color:var(--accent)}
.mem-actions{margin-left:auto;display:flex;gap:4px}
.mem-actions button{background:none;border:none;color:var(--dim);cursor:pointer;font-size:12px;padding:2px 4px}
.mem-actions button:hover{color:var(--text)}
.mem-actions button.del:hover{color:var(--err)}
.mp-add{display:flex;gap:6px;padding:12px;border-top:1px solid var(--border)}
.mp-add input{flex:1;background:var(--bg);border:1px solid var(--border);border-radius:var(--r);color:var(--text);font-size:12px;padding:8px 10px;outline:none;font-family:var(--sans)}
.mp-add input:focus{border-color:var(--accent)}
.mp-add button{background:var(--accent);color:#fff;border:none;border-radius:var(--r);font-size:12px;font-weight:600;padding:8px 14px;cursor:pointer}
.mp-overlay{position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:var(--z-scrim);display:none}
.mp-overlay.open{display:block}
.cursor{display:inline-block;width:2px;height:14px;background:var(--accent);vertical-align:text-bottom;animation:blink .6s step-end infinite}
@keyframes blink{50%{opacity:0}}

/* Before the first word arrives there is nothing to look at, and a 2px
   blinking bar reads as a frozen page. Three dots that move say it is alive,
   which for a long build is the only thing on screen for a while. */
.thinking{display:inline-flex;align-items:center;gap:9px;color:var(--muted);font-size:13px}
.thinking-dots{display:inline-flex;gap:4px}
.thinking-dots i{width:6px;height:6px;border-radius:50%;background:var(--accent);
  animation:thinkbounce 1.2s ease-in-out infinite}
.thinking-dots i:nth-child(2){animation-delay:.16s}
.thinking-dots i:nth-child(3){animation-delay:.32s}
@keyframes thinkbounce{0%,80%,100%{transform:translateY(0);opacity:.35}
  40%{transform:translateY(-4px);opacity:1}}
@media(prefers-reduced-motion:reduce){.thinking-dots i{animation:none;opacity:.8}}

/* welcome */
#welcome{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:22px 24px 24px}
#welcome.hidden{display:none!important}

/* input */
#input-bar{padding:10px 24px 18px;flex-shrink:0}
.file-preview{max-width:700px;margin:0 auto;padding:0 0 6px;display:flex;flex-wrap:wrap;gap:6px}
.file-preview:empty{display:none}
.input-wrap{max-width:700px;margin:0 auto;display:flex;gap:6px;align-items:center;background:var(--surface);border:1px solid var(--border);border-radius:var(--r2);padding:6px 10px;transition:border-color .2s,box-shadow .2s}
.input-wrap:focus-within{border-color:var(--accent);box-shadow:0 0 8px rgba(var(--accent-rgb),.12),0 0 0 1px rgba(var(--accent-rgb),.08)}
/* Attach and send sit on the first line of the prompt (44px tall), and stay
   pinned to the bottom as the prompt grows, like other chat apps. */
.ibtn{width:36px;height:36px;margin-bottom:4px;flex-shrink:0;display:flex;align-items:center;justify-content:center;
  background:none;border:none;border-radius:50%;color:var(--muted);cursor:pointer;padding:0;line-height:1;
  transition:color .15s,background .15s}
.ibtn:hover{color:var(--text);background:var(--surface2)}
.ibtn svg{display:block}
#prompt{flex:1;background:transparent;border:none;color:var(--text);font-family:var(--sans);font-size:14px;padding:5px 0;resize:none;min-height:44px;max-height:300px;line-height:1.6;outline:none}
#prompt::placeholder{color:var(--muted)}
#send{background:var(--accent);border:none;color:#fff;cursor:pointer;font-size:18px;padding:0;transition:color .15s;line-height:1;
  width:36px;height:36px;margin-bottom:4px;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:50%}
#send:hover{color:#fff;background:var(--accent2)}
/* Stop has to be findable by a child mid-build: solid red, not a grey square. */
#send[data-stop="1"]{background:var(--err);color:#fff;opacity:1}
#send:disabled{opacity:.15;cursor:not-allowed}
#file-input{display:none}


/* ═══ MODALS ═══ */
.modal-bg{position:fixed;inset:0;top:var(--app-top,0);height:var(--app-h,100%);background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;z-index:var(--z-modal);backdrop-filter:blur(3px)}
.modal-bg.hidden{display:none}
.modal{background:var(--surface);border:1px solid var(--border);border-radius:var(--r3);padding:28px;max-width:420px;width:92%}
.modal h2{font-size:16px;font-weight:700;margin-bottom:14px}
/* The styled confirm dialog (replaces the browser's native confirm box). */
.confirm-card{max-width:400px;padding:24px}
.confirm-card h2{margin-bottom:8px}
.confirm-body{font-size:13px;color:var(--muted);line-height:1.6;margin:0 0 14px}
.confirm-label{display:block;font-size:11px;font-weight:600;color:var(--muted);margin:0 0 5px}
.confirm-input{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:var(--r);color:var(--text);font-family:var(--sans);font-size:12.5px;padding:9px 11px;outline:none;resize:vertical;min-height:62px;margin-bottom:18px;transition:border-color .15s}
.confirm-input:focus{border-color:var(--accent)}
.confirm-row{display:flex;gap:10px;justify-content:flex-end}
.confirm-row button{font-family:var(--sans);font-size:13px;font-weight:600;border-radius:var(--r);padding:9px 18px;cursor:pointer;border:1px solid transparent;transition:all .15s}
.confirm-row .btn-ghost{background:transparent;border-color:var(--border);color:var(--text2)}
.confirm-row .btn-ghost:hover{background:var(--surface2);color:var(--text)}
.confirm-row .btn-primary{background:var(--accent);color:#fff}
.confirm-row .btn-primary:hover{filter:brightness(1.08)}
.confirm-row .btn-danger{background:#e5484d;color:#fff}
.confirm-row .btn-danger:hover{background:#f2555a}
.confirm-row button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.modal label{display:block;font-size:11px;font-weight:600;color:var(--muted);margin-bottom:3px;margin-top:10px}
.modal select{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:var(--r);color:var(--text);font-family:var(--sans);font-size:13px;padding:9px 11px;outline:none;cursor:pointer}
.modal select:focus{border-color:var(--accent)}
.modal input,.modal textarea{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:var(--r);color:var(--text);font-family:var(--sans);font-size:13px;padding:9px 11px;outline:none;margin-bottom:2px;transition:border-color .15s}
.modal textarea{resize:vertical;min-height:70px;font-size:12px}
.modal input:focus,.modal textarea:focus{border-color:var(--accent)}
.modal input::placeholder,.modal textarea::placeholder{color:var(--dim)}
.modal-btns{display:flex;gap:8px;margin-top:16px;justify-content:flex-end}
.btn-c{background:var(--surface2);color:var(--text2);border:1px solid var(--border);border-radius:var(--r);padding:8px 16px;font-size:12px;font-weight:500;cursor:pointer}
.btn-c:hover{background:var(--surface3)}
.btn-p{background:var(--accent);color:#fff;border:none;border-radius:var(--r);padding:8px 16px;font-size:12px;font-weight:600;cursor:pointer;text-shadow:0 1px 2px rgba(0,0,0,.2)}
.btn-p:hover{background:var(--accent2)}
.modal .err{color:var(--err);font-size:11px;margin-top:6px}

/* ═══ LOGIN ═══ */
#login-screen{position:fixed;left:0;right:0;top:var(--app-top,0);height:var(--app-h,100%);overflow-y:auto;background:var(--bg);display:flex;align-items:center;justify-content:center;z-index:var(--z-login)}
#login-screen.hidden{display:none}
#login-box{background:var(--surface);border:1px solid var(--border);border-radius:var(--r3);padding:44px 36px;max-width:360px;width:90%;text-align:center}
#login-box .logo{font-size:36px;font-weight:700;letter-spacing:-.04em;margin-bottom:24px}
#login-box .logo .a{color:var(--text)}
#login-box .logo .i{color:var(--accent)}
#login-box input{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:var(--r);color:var(--text);font-size:13px;padding:12px 13px;outline:none;margin-bottom:10px}
#login-box input:focus{border-color:var(--accent)}
#login-box input::placeholder{color:var(--muted)}
.login-btn{width:100%;background:var(--accent);color:#fff;border:none;border-radius:var(--r);font-size:14px;font-weight:600;padding:12px;cursor:pointer;margin-top:6px;transition:all .15s}
.login-btn:hover{background:var(--accent2)}
.login-btn:disabled{opacity:.15;cursor:not-allowed}
.login-err{color:var(--err);font-size:12px;margin-top:12px;min-height:18px}

::-webkit-scrollbar{width:4px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:2px}

/* Sits with the other buttons, pushed to the far side - a different kind of
   action, not a bigger one. Same treatment as Sign out in the account dialog. */
.ep-delete{margin-right:auto;background:none;border:1px solid rgba(239,68,68,.3);color:var(--err);
  border-radius:var(--r);font-size:12px;font-weight:600;padding:8px 14px;cursor:pointer;transition:all .15s}
.ep-delete:hover{background:rgba(239,68,68,.1);border-color:var(--err)}
@media(pointer:coarse){.ep-delete{min-height:44px;font-size:13px}}
@media(max-width:380px){.ep-delete{padding:8px 10px}}

/* ═══ MOBILE ═══
   The sidebar becomes a slide-over drawer rather than disappearing, so
   projects and chat history stay reachable. Touch targets go to 44px, which
   is the smallest reliably hittable size with a thumb. Inputs go to 16px
   because iOS zooms the viewport on focus for anything smaller, and that zoom
   does not undo itself. */
.hamburger{display:none;background:none;border:none;color:var(--text2);font-size:20px;
           padding:8px;margin:-8px 4px -8px -8px;cursor:pointer;line-height:1}
/* Deploy banner. This app serves its own frontend, so deploying it makes the
   page you are reading stale - it stays up while the service is down, then
   reloads itself once the new build answers. */
#deploy-banner{position:fixed;top:calc(14px + env(safe-area-inset-top));left:50%;z-index:var(--z-banner);
               background:var(--accent);color:#fff;font-size:13px;font-weight:500;
               padding:10px 20px;border-radius:20px;box-shadow:0 4px 20px rgba(0,0,0,.4);
               transform:translateX(-50%) translateY(-200%);transition:transform .3s ease}
#deploy-banner.show{transform:translateX(-50%) translateY(0)}
.db-inner{max-width:700px;margin:0 auto;display:flex;align-items:center;gap:10px}
.db-spin{width:13px;height:13px;border:2px solid rgba(255,255,255,.35);border-top-color:#fff;
         border-radius:50%;animation:db-rot .7s linear infinite;flex-shrink:0}
@keyframes db-rot{to{transform:rotate(360deg)}}

.drawer-scrim{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:var(--z-scrim);
              opacity:0;pointer-events:none;transition:opacity .2s}
.drawer-scrim.open{opacity:1;pointer-events:auto}

@media(max-width:760px){
  .hamburger{display:block}

  /* Sidebar as a drawer */
  #sidebar{position:fixed;top:0;left:0;bottom:0;z-index:var(--z-panel);width:84%;max-width:320px;
           transform:translateX(-100%);transition:transform .22s ease;
           box-shadow:2px 0 24px rgba(0,0,0,.5)}
  #sidebar.open{transform:translateX(0)}

  .main-head{padding:10px 14px;position:sticky;top:0;z-index:var(--z-header)}
  .main-head .title{font-size:14px}
  .main-head .badge{display:none}
  /* Stays in the header on phones, thumb-sized */
  #update-pill{padding:8px 12px;font-size:12px;min-height:36px}
  /* Icon-only actions: at this width the labels cost more than they explain,
     and the project name is what you actually need to read. */

  .msg-row{padding:16px 14px}
  .msg-inner{max-width:100%}
  .msg-text{font-size:15px}

  /* Bigger touch targets throughout */
  .conv-item,.proj-item{padding-top:12px;padding-bottom:12px;font-size:14px}
  .proj-add{padding:7px 12px;font-size:13px}
  .conv-del{opacity:1;padding:8px;right:4px}
  .proj-cog{opacity:1;margin-left:auto;flex-shrink:0}
  .sb-foot{padding:14px 16px}
  .sb-foot .av{width:34px;height:34px}
  .sb-foot .gear{font-size:18px;padding:8px}

  /* Input: 16px stops iOS zooming on focus, and that zoom does not revert */
  #input-bar{padding:8px 12px calc(10px + env(safe-area-inset-bottom))}
  .input-wrap{border-radius:22px;padding:6px 8px 6px 12px}
  #prompt{font-size:16px}
  #send{padding:10px 14px;border-radius:18px;min-width:44px}
  .ibtn{width:40px;height:40px;margin-bottom:2px}

  /* Welcome */
  #welcome{padding:14px 14px 16px}

  /* Modals become bottom sheets - easier to reach one-handed */
  .modal-bg{align-items:flex-end}
  .modal{max-width:100%;width:100%;border-radius:18px 18px 0 0;
         padding:24px 20px calc(24px + env(safe-area-inset-bottom));
         max-height:88vh;max-height:88dvh;overflow-y:auto}
  .modal input,.modal textarea,.modal select{font-size:16px;padding:12px}
  /* Buttons share the row evenly and never wrap their label onto two lines */
  .modal-btns{gap:8px}
  .modal-btns button{white-space:nowrap;padding-left:10px;padding-right:10px}
  /* Grab handle, the usual bottom-sheet cue */
  .modal::before{content:"";display:block;width:36px;height:4px;border-radius:2px;
                 background:var(--border-l);margin:-10px auto 14px}
  .modal-btns button{padding-top:12px;padding-bottom:12px;font-size:14px;flex:1}

  #hub-foot{padding-left:10px;padding-right:10px}
  .hf-btn{min-height:46px;font-size:13px;gap:7px}

  /* Memory panel full width, with thumb-sized controls */
  #memory-panel,#agents-panel{width:100%;right:-100%}
  .mem-item{padding:14px}
  .mp-tab{padding:12px 8px;font-size:13px}
  .mp-head .close-btn{font-size:24px;padding:6px 10px}
  .mem-actions button{font-size:16px;padding:8px 10px}
  .mem-btn{font-size:12px;padding:8px 12px}
  .mp-add{padding:10px 12px calc(10px + env(safe-area-inset-bottom))}
  .mp-add input{font-size:16px;padding:11px 12px}
  .mp-add button{padding:11px 16px;font-size:14px}
  .rail-toggle{font-size:26px;padding:6px 12px}

  /* Home hub: let the header buttons wrap under the title */
  .hub-head{flex-wrap:wrap;gap:8px}
  .hub-head h2{flex-basis:100%}
  .hub-head .gh-connect{flex:1;justify-content:center;padding:11px 14px;font-size:14px}
  .proj-cards{grid-template-columns:1fr}

  #login-box{padding:36px 24px}
  #login-box input{font-size:16px;padding:14px}
  .login-btn{padding:14px}
}

/* Landscape phones: reclaim vertical space */
@media(max-height:500px) and (orientation:landscape){
  #welcome{padding:12px}
}

/* ═══ ALL SCREEN SIZES ═══ */
/* Notches and home indicators. The installed app uses a translucent status
   bar, so anything pinned to the top edge has to clear it. */
.main-head{padding-top:max(10px,env(safe-area-inset-top))}
.sb-top{padding-top:max(14px,env(safe-area-inset-top))}
.mp-head,.rail-head{padding-top:max(14px,env(safe-area-inset-top))}
@media(min-width:761px){#input-bar{padding-bottom:max(18px,env(safe-area-inset-bottom))}}
#main{padding-right:env(safe-area-inset-right);padding-left:env(safe-area-inset-left)}

/* Touch screens have no hover, so anything that only appears on hover has to
   be visible all the time, and hover lifts would stick after a tap. */
@media(hover:none){
  .copy-btn{opacity:1;padding:5px 10px}
  .conv-del{opacity:1}
  .proj-cog{opacity:1}
  .proj-card:hover{transform:none;box-shadow:none}
}

/* Tablets: slightly narrower sidebar leaves the chat more room */
@media(min-width:761px) and (max-width:1099.98px){
  :root{--sidebar-w:232px}
  .main-head{padding-left:18px;padding-right:18px}
  .msg-row{padding:16px 18px}
  #input-bar{padding-left:18px;padding-right:18px}
}

/* Small phones (iPhone SE, older Androids) */
@media(max-width:380px){
  .hf-btn{flex-direction:column;gap:4px;font-size:11px;padding:7px 4px}
  .main-head{padding-left:10px;padding-right:10px;gap:6px}
  .msg-row{padding:14px 12px}
  .msg-text pre,.msg-text pre code{font-size:12px}
  #input-bar{padding-left:8px;padding-right:8px}
  #welcome{padding:12px 10px 14px}
  .modal{padding-left:16px;padding-right:16px}
  .hub-head .gh-connect{font-size:13px;padding:10px}
}

/* Keyboard open on a phone: hide the floating plan pill so it does not sit
   on top of what you are typing */
.kb-open .plan-fab{display:none!important}

/* Any touch screen, whatever its width (a phone turned sideways is wider than
   the phone breakpoint): 16px fields so iOS does not zoom on tap, and
   44px-ish targets for thumbs. */
@media(pointer:coarse){
  input,textarea,select,.modal input,.modal textarea,.modal select,.mp-add input{font-size:16px}
  .modal-btns button,.btn-c,.btn-p{min-height:44px}
  #send,.ibtn{min-width:44px;min-height:44px;margin-bottom:0}
  .proj-cog{width:44px;height:44px;opacity:1}
  /* Small controls that were 24-36px under a thumb - lifted to the 44px
     minimum so a fingertip lands them reliably. */
  /* #jump-latest is deliberately NOT in this list: the display:inline-flex here
     beat its display:none, so on every phone the arrow showed all the time,
     whatever the scroll position. Its 44px size is set in its own rule. */
  .fc-copy,.copy-btn,.mem-toggle,.modal-x,.plan-fab,.file-chip .rm,
  .mp-head .close-btn,.mem-actions button{min-height:44px;min-width:44px;
    display:inline-flex;align-items:center;justify-content:center}
  .copy-btn{opacity:1}
}
/* Keyboard users see where they are. Nothing had a focus style of its own. */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.copy-btn:focus-visible{opacity:1}
/* Phones turned sideways keep the sidebar as a drawer, like portrait */
@media(max-height:500px) and (orientation:landscape) and (pointer:coarse){
  .hamburger{display:block}
  #sidebar{position:fixed;top:0;left:0;bottom:0;z-index:var(--z-panel);width:300px;max-width:84vw;
           transform:translateX(-100%);transition:transform .22s ease;box-shadow:2px 0 24px rgba(0,0,0,.5)}
  #sidebar.open{transform:translateX(0)}
}
/* Dialogs never taller than the screen; scroll inside instead */
.modal{max-height:calc(100dvh - 32px);overflow-y:auto}

/* Landscape phones: every vertical pixel counts */
@media(max-height:500px) and (orientation:landscape){
  .main-head{min-height:38px;padding-top:max(6px,env(safe-area-inset-top));padding-bottom:6px}
  #input-bar{padding-top:4px;padding-bottom:max(6px,env(safe-area-inset-bottom))}
  #prompt{min-height:36px;max-height:120px}
  .msg-row{padding-top:10px;padding-bottom:10px}
  .modal{max-height:94dvh}
}

/* Large desktop monitors: use more of the width for reading */
@media(min-width:1600px){
  .msg-inner,.input-wrap,.file-preview{max-width:820px}
  #gh-hub{max-width:900px}
  .proj-cards{max-width:880px}
}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
}

/* Short messages that go away by themselves (toast() in app.js). */
#toast{position:fixed;left:50%;bottom:calc(88px + env(safe-area-inset-bottom,0px));transform:translate(-50%,12px);
  max-width:min(92vw,440px);background:var(--surface3);color:var(--text);border:1px solid var(--border-l);
  border-radius:var(--r2);padding:11px 16px;font-size:13.5px;line-height:1.45;box-shadow:0 8px 28px rgba(0,0,0,.45);
  opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;z-index:var(--z-toast)}
#toast.show{opacity:1;transform:translate(-50%,0);pointer-events:auto;display:flex;align-items:center;gap:12px}
.toast-act{flex-shrink:0;background:none;border:none;color:var(--accent);font-weight:700;font-size:13.5px;
  cursor:pointer;padding:6px 8px;margin:-6px -4px -6px 0;border-radius:8px;min-height:36px}
.toast-act:hover{background:var(--surface2)}
@media(pointer:coarse){.toast-act{min-height:44px;padding:10px 12px}}

/* ═══ MOBILE AUDIT (2026-09-25) ═══ */
/* The streaming reply is plain text until it finishes; keep its line breaks. */
.stream-plain{white-space:pre-wrap;word-break:break-word}
/* Home, labelled: a title attribute is never seen on a touch screen. */
.home-hint{margin-left:auto;font-size:12px;color:var(--dim);white-space:nowrap;padding-left:8px}
#proj-cog .pc-label{font-size:13px;font-weight:500;margin-left:5px}
/* No display here: the button shows only once the site is live (#proj-cog.show). */
#proj-cog{align-items:center;width:auto!important;padding:0 10px;min-height:30px}
.rail-toggle{font-size:15px;font-weight:600;min-height:44px;padding:0 14px}
@media(max-width:480px){
  #proj-cog .pc-label{display:none}
  .plan-fab-top #plan-fab-label{display:none}
  .main-head .title{min-width:72px}
}
@media(pointer:coarse){
  .hamburger{min-width:44px;min-height:44px}
  .proj-add,.mem-btn,#pv-open,#proj-cog,.pv-btn,.user-home,.sb-mi{min-height:44px}
  #jump-latest{width:44px;height:44px}
  #cp-adv-toggle a{display:inline-block;padding:14px 0;font-size:14px!important}
}
@media(max-width:760px){
  .modal .err,.login-err,#login-error{font-size:14px}
  .modal label,.msg-who,.hub-section,.sb-label,.acct-section{font-size:12.5px}
  .repo-tag,.mem-cat,.review-reason,.file-chip,.pub-prefix{font-size:12px}
  .review-reason{font-family:var(--sans)}
  .proj-repo,.proj-card-repo{display:none}
}
/* A short screen (a phone with the keyboard up): the sign-in box starts at the
   top instead of the middle, so the fields are not the part pushed off screen. */
@media(max-height:600px){#login-screen{align-items:flex-start;padding:16px 0}#login-box{padding:24px 20px}#login-box .logo{margin-bottom:14px}}
/* A destructive button beside two others does not fit a phone's width: it ran
   off the left edge. On its own row, last, where it is not tapped by mistake. */
@media(max-width:760px){
  .modal-btns{flex-wrap:wrap}
  .modal-btns .ep-delete{order:3;flex:1 1 100%;margin-right:0}
}
/* A small spinner inside a button that is working. */
.btn-spin{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:-1px;border:2px solid rgba(255,255,255,.35);
  border-top-color:#fff;border-radius:50%;animation:btnspin .8s linear infinite}
@keyframes btnspin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.btn-spin{animation-duration:2.4s}}

/* A build's batch in the line: just a number beside the working dots. */
.queue-num{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:22px;
  padding:0 6px;margin:0 6px 0 2px;border-radius:11px;background:var(--accent);color:#fff;
  font-size:12px;font-weight:600;line-height:1;vertical-align:middle}

/* A reply's steps: one "What I did" row, closed; friendly lines inside, the
   raw detail behind each. */
details.steps{margin:8px 0;border:1px solid var(--border,#2a2a33);border-radius:10px;background:rgba(255,255,255,.02)}
details.steps>summary{cursor:pointer;padding:10px 12px;font-size:14px;color:var(--muted);list-style:none;min-height:24px}
details.steps>summary::-webkit-details-marker{display:none}
details.steps>summary::before{content:'\25B8';display:inline-block;margin-right:8px;transition:transform .15s}
details.steps[open]>summary::before{transform:rotate(90deg)}
details.step{border-top:1px solid var(--border,#2a2a33)}
details.step>summary{cursor:pointer;padding:9px 12px;font-size:14px;list-style:none;display:flex;gap:8px;align-items:baseline}
details.step>summary::-webkit-details-marker{display:none}
.step-mark{color:#3fb950;font-weight:700;min-width:14px}
.step-bad .step-mark{color:#e3b341}
.step-out{padding:0 12px 10px 34px}
.step-raw{font-size:12px;color:var(--muted);margin-bottom:6px;word-break:break-word}
.step-out pre{max-height:none;font-size:12.5px;white-space:pre-wrap;word-break:break-word}
/* A line the assistant said between two steps ("Now the change."), kept in
   its place inside the list. */
.step-note{border-top:1px solid var(--border,#2a2a33);padding:8px 12px 8px 34px;font-size:13.5px;color:var(--text2);font-style:italic}

/* ---- The code viewer ---------------------------------------------------- */
#code-open{display:none;align-items:center;justify-content:center;background:transparent;color:var(--text2);
  border:1px solid var(--border);border-radius:var(--r);padding:0 10px;min-height:30px;cursor:pointer;flex-shrink:0;
  font-family:var(--sans);transition:all .15s}
#code-open.show{display:inline-flex}
#code-open:hover{color:var(--accent);border-color:rgba(var(--accent-rgb),.45);background:rgba(var(--accent-rgb),.08)}
#code-open svg{display:block}
#code-open .pc-label{font-size:13px;font-weight:500;margin-left:5px}
@media(pointer:coarse){#code-open{min-height:44px;min-width:44px}}
@media(max-width:480px){#code-open .pc-label{display:none}}

#code-panel{position:fixed;top:0;right:0;width:62%;min-width:380px;max-width:1000px;height:100%;
  background:#0d0d10;border-left:1px solid var(--border);z-index:var(--z-preview);display:flex;flex-direction:column;
  transform:translateX(100%);transition:transform .25s ease;padding-right:env(safe-area-inset-right);
  box-shadow:-18px 0 40px rgba(0,0,0,.35);visibility:hidden}
#code-panel.open{transform:translateX(0);visibility:visible}
@media(max-width:900px){#code-panel{width:100%;max-width:100%;min-width:0}}
.cv-head{display:flex;align-items:center;gap:10px;padding:max(12px,env(safe-area-inset-top)) 14px 12px;
  border-bottom:1px solid var(--border);background:var(--surface)}
.cv-icon{color:var(--accent);flex-shrink:0}
.cv-titles{flex:1;min-width:0}
.cv-kicker{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);line-height:1.2}
.cv-head h3{font-size:15px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.35}
.cv-close{font-size:18px;line-height:1;padding:4px 11px}
.cv-files{display:flex;gap:6px;padding:10px 14px;overflow-x:auto;border-bottom:1px solid var(--border);
  background:var(--surface);scrollbar-width:thin;flex-shrink:0}
.cv-file{display:inline-flex;align-items:center;gap:7px;white-space:nowrap;flex-shrink:0;
  background:var(--surface2);border:1px solid var(--border);border-radius:999px;color:var(--text2);
  font:500 12.5px var(--mono);padding:6px 12px;cursor:pointer;transition:all .15s}
.cv-file:hover{border-color:var(--border-l);color:var(--text)}
.cv-file.active{background:rgba(var(--accent-rgb),.14);border-color:rgba(var(--accent-rgb),.6);color:var(--text)}
@media(pointer:coarse){.cv-file{min-height:44px}}
.cv-dot{width:8px;height:8px;border-radius:50%;background:var(--muted);flex-shrink:0}
/* One colour per kind of file, the same on its dot and its badge. */
.cv-dot.cv-html,.cv-dot.cv-htm,.cv-badge.cv-html,.cv-badge.cv-htm{--k:#ff8b6b}
.cv-dot.cv-css,.cv-badge.cv-css{--k:#6bb8ff}
.cv-dot.cv-js,.cv-dot.cv-mjs,.cv-dot.cv-ts,.cv-badge.cv-js,.cv-badge.cv-mjs,.cv-badge.cv-ts{--k:#f5d76e}
.cv-dot.cv-json,.cv-badge.cv-json{--k:#a5e88a}
.cv-dot.cv-md,.cv-badge.cv-md,.cv-dot.cv-txt,.cv-badge.cv-txt{--k:#c0c0cc}
.cv-dot.cv-svg,.cv-badge.cv-svg{--k:#c792ea}
.cv-dot{background:var(--k,var(--muted))}
.cv-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--border);background:#111114;flex-shrink:0}
.cv-meta{display:flex;align-items:center;gap:9px;flex:1;min-width:0;flex-wrap:wrap;row-gap:4px}
.cv-badge{font:700 10.5px var(--sans);letter-spacing:.06em;text-transform:uppercase;padding:3px 8px;border-radius:5px;
  color:var(--k,var(--text2));background:color-mix(in srgb,var(--k,#888) 14%,transparent);border:1px solid color-mix(in srgb,var(--k,#888) 40%,transparent)}
.cv-what{font-size:13px;color:var(--text2)}
.cv-nums{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.cv-actions{display:flex;gap:6px;flex-shrink:0}
.cv-act{background:var(--surface2);border:1px solid var(--border);border-radius:var(--r);color:var(--text2);
  font:600 12px var(--sans);padding:6px 11px;cursor:pointer;transition:all .15s}
.cv-act:hover:not(:disabled){border-color:var(--accent);color:var(--text)}
.cv-act:disabled{opacity:.4;cursor:default}
.cv-act.on{background:rgba(var(--accent-rgb),.14);border-color:rgba(var(--accent-rgb),.6);color:var(--text)}
@media(pointer:coarse){.cv-act{min-height:40px;padding:8px 13px;font-size:13px}}
@media(max-width:560px){.cv-actions{width:100%}.cv-act{flex:1}}
.cv-scroll{flex:1;overflow:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}
.cv-empty{padding:40px 24px;text-align:center;color:var(--muted);font-size:14px}
.cv-empty.hidden{display:none}
.cv-wait{padding:16px;color:var(--muted);font-size:13px}
.cv-files .cv-wait{padding:6px 0}
.cv-lines{font:12.5px/1.65 var(--mono);color:#dcdce4;min-width:max-content;padding:8px 0 24px}
.cv-row{display:flex}
.cv-row:hover{background:rgba(255,255,255,.035)}
.cv-ln{position:sticky;left:0;flex:0 0 auto;min-width:3.4em;text-align:right;padding:0 12px 0 10px;color:#5b5b6c;
  background:#0d0d10;border-right:1px solid var(--border);user-select:none;-webkit-user-select:none}
.cv-row:hover .cv-ln{color:var(--text2)}
.cv-lc{white-space:pre;padding:0 16px 0 14px}
.cv-legend{display:flex;flex-wrap:wrap;gap:6px 14px;padding:8px 14px max(8px,env(safe-area-inset-bottom));
  border-top:1px solid var(--border);background:var(--surface);font-size:11.5px;color:var(--muted);flex-shrink:0}
.cv-legend span{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}
.cv-legend i{width:9px;height:9px;border-radius:2px;background:currentColor;display:inline-block}
.cv-legend span:has(i.t-key){color:#c792ea}.cv-legend span:has(i.t-fn){color:#82aaff}.cv-legend span:has(i.t-str){color:#a5e88a}
.cv-legend span:has(i.t-num){color:#f5a97f}.cv-legend span:has(i.t-com){color:#8b93a1}.cv-legend span:has(i.t-tag){color:#ff8b8b}
.cv-legend span:has(i.t-attr){color:#ffcb6b}

/* ---- Attachments ---------------------------------------------------------
   The paperclip is a real button now, the same size and shape as send and
   stop: a child looking for "how do I add my picture" should find it. */
#file-btn{background:rgba(var(--accent-rgb),.14);border:1.5px solid rgba(var(--accent-rgb),.55);color:var(--accent2);position:relative}
#file-btn:hover:not(:disabled){background:var(--accent);border-color:var(--accent);color:#fff}
#file-btn.has{background:var(--accent);border-color:var(--accent);color:#fff}
#file-btn:disabled{opacity:.3;cursor:not-allowed}
#file-btn:focus-visible,#send:focus-visible{outline:2px solid var(--accent2);outline-offset:2px}
.fb-count{position:absolute;top:-5px;right:-5px;min-width:18px;height:18px;padding:0 5px;border-radius:9px;
  background:var(--green);color:#04210f;font:700 11px/18px var(--sans);text-align:center;border:2px solid var(--surface)}
.fb-count:empty{display:none}
#input-bar.dropping .input-wrap{border-color:var(--accent);border-style:dashed;background:rgba(var(--accent-rgb),.08)}
.file-chip,.sent-file{display:inline-flex;align-items:center;gap:9px;background:var(--surface2);border:1px solid var(--border);
  border-radius:12px;padding:5px 6px 5px 5px;max-width:100%;min-width:0;color:var(--text2)}
.file-chip{margin:0}
.fc-thumb{width:40px;height:40px;border-radius:8px;object-fit:cover;flex-shrink:0;background:var(--surface3)}
.fc-ico{width:40px;height:40px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:20px;
  background:var(--surface3);flex-shrink:0}
.fch-text{display:flex;flex-direction:column;min-width:0;line-height:1.3}
.fch-name{font-size:13px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}
.fch-state{font-size:11.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px}
.file-chip .rm{background:none;border:none;color:var(--muted);font-size:18px;line-height:1;cursor:pointer;
  width:30px;height:30px;border-radius:50%;flex-shrink:0;padding:0}
.file-chip .rm:hover{color:var(--err);background:rgba(239,68,68,.1)}
.file-chip.up{border-color:rgba(var(--accent-rgb),.5)}
.file-chip.up .fch-state{color:var(--accent2)}
.file-chip.up .fc-thumb,.file-chip.up .fc-ico{animation:fc-pulse 1s ease-in-out infinite}
@keyframes fc-pulse{50%{opacity:.45}}
.file-chip.ok{border-color:rgba(34,197,94,.5)}
.file-chip.ok .fch-state{color:var(--green)}
.file-chip.bad{border-color:rgba(239,68,68,.55)}
.file-chip.bad .fch-state{color:var(--err);white-space:normal}
.user-words{white-space:pre-wrap}
.sent-files{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.user-words+.sent-files{margin-top:8px}
.sent-files:first-child{margin-top:0}
.sent-file{padding-right:12px}
.sent-file.link{cursor:pointer}
.sent-file.link:hover{border-color:var(--border-l)}
.sent-file.bad{border-color:rgba(239,68,68,.55)}
@media(pointer:coarse){.file-chip .rm{width:40px;height:40px}}

/* ---- The composer --------------------------------------------------------
   The typing area is a field of its own now, a rounded well between the
   paperclip and send, with its one line of text centred on the buttons.
   It used to be bare text on the bar, sitting 8px high: 44px tall with a
   25px line and 5px of padding, so the words hung above the middle. */
.input-wrap{flex-direction:column;align-items:stretch;gap:2px;padding:10px 10px 8px;border-radius:22px;
  background:var(--surface2);border:1px solid var(--border-l);box-shadow:0 8px 28px rgba(0,0,0,.4)}
#prompt{flex:none;box-sizing:border-box;width:100%;min-height:44px;line-height:24px;padding:6px 8px;
  background:transparent;border:0;border-radius:0;box-shadow:none}
#prompt:focus{background:transparent;outline:none}
#prompt::placeholder{color:var(--text2);opacity:.75}
#prompt:disabled{background:transparent}
.input-wrap:focus-within{border-color:rgba(var(--accent-rgb),.55);box-shadow:0 8px 28px rgba(0,0,0,.4),0 0 0 3px rgba(var(--accent-rgb),.12)}
/* Under the message, Claude style: add on the left, send/stop on the right.
   Fixed circles; they never stretch with the text. */
.input-tools{display:flex;align-items:center;gap:8px}
.input-gap{flex:1}
#send,.ibtn{width:40px;height:40px;min-width:40px;min-height:40px;margin:0;padding:0;border-radius:50%;flex-shrink:0;
  transition:background .15s,border-color .15s,color .15s,opacity .15s}
/* Folder yellow, so "add a file" reads at a glance on the dark bar. */
#file-btn{background:rgba(250,204,21,.14);border:1.5px solid rgba(250,204,21,.55);color:#fde68a}
#file-btn:hover:not(:disabled){background:rgba(250,204,21,.24);border-color:#facc15;color:#fef3c7}
#file-btn:active:not(:disabled){background:rgba(250,204,21,.32)}
#file-btn.has{background:#facc15;border-color:#facc15;color:#1a1400}
#file-btn:disabled{opacity:.35}
@media(max-width:760px){.input-wrap{padding:8px 8px 7px;border-radius:20px}#prompt{padding:6px 8px;font-size:16px}}
@media(max-height:500px) and (orientation:landscape){#prompt{min-height:36px;padding:4px 8px}#send,.ibtn{width:36px;height:36px;min-width:36px;min-height:36px}}

/* A note from L3D8 in a reply - what was saved, a heads-up, a correction.
   Set apart as a small card rather than a quote, so it reads as information
   about the work, not as something the assistant is quoting. */
.msg-text blockquote{margin:12px 0;padding:10px 14px 10px 40px;position:relative;border:1px solid var(--border-l);
  border-left:3px solid var(--accent);border-radius:10px;background:rgba(var(--accent-rgb),.06);
  color:var(--text2);font-size:14px;line-height:1.55}
.msg-text blockquote::before{content:"i";position:absolute;left:12px;top:11px;width:18px;height:18px;border-radius:50%;
  background:rgba(var(--accent-rgb),.2);color:var(--accent2);font:700 11px/18px Georgia,serif;text-align:center;font-style:italic}
.msg-text blockquote a{word-break:break-all}

/* ---- Feels like an app, not a web page ------------------------------------
   The controls behave like an app's: no long-press "copy / look up" menu on a
   button, no text selection when a thumb drags across the header, no 300 ms
   wait for a possible double-tap zoom. Words people might want to copy - the
   messages, the code, anything they typed - stay selectable. */
button,[role="button"],.main-head,#sidebar .sb-top,.sb-label-row,.proj-item,.proj-card,#hub-foot,
.file-chip,.sent-file,.cv-files,.cv-bar,.cv-legend,.cv-head,.plan-fab,.msg-who,details.steps>summary,details.step>summary,.fc-head{
  -webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
button,[role="button"],a,summary,.proj-item,label,input,textarea,select{touch-action:manipulation}
.msg-text,.msg-text *,textarea,input,.cv-lc,.step-out,.live-url{-webkit-user-select:text;user-select:text;-webkit-touch-callout:default}
img{-webkit-user-drag:none}
/* A pressed control answers the finger, the way an app's does. */
@media(pointer:coarse){
  button:active:not(:disabled),.proj-item:active,.proj-card:active,.hf-btn:active{transform:scale(.97);transition:transform .06s}
}
/* On a touch screen scrollbars are clutter: the content scrolls under the thumb. */
@media(pointer:coarse){
  #messages,.sb-scroll,.cv-scroll,.cv-files,.mp-body{scrollbar-width:none}
  #messages::-webkit-scrollbar,.sb-scroll::-webkit-scrollbar,.cv-files::-webkit-scrollbar,.mp-body::-webkit-scrollbar{display:none}
}
/* Opened from the home screen: there is no browser around it to pull down to
   refresh, and nothing should bounce past the edges. */
html.standalone,html.standalone body{overscroll-behavior:none}

#install-btn.hidden{display:none}
.install-modal{text-align:center;max-width:380px}
.im-icon{display:block;margin:4px auto 12px;border-radius:15px;box-shadow:0 6px 20px rgba(0,0,0,.45)}
.install-modal h2{margin:0 0 6px;font-size:19px}
.im-sub{margin:0 0 16px;color:var(--text2);font-size:14px}
.im-steps{text-align:left;margin:0 0 18px;padding:0 0 0 22px;color:var(--text);font-size:15px;line-height:1.5}
.im-steps li{margin:0 0 10px;padding-left:4px}
.im-steps b{color:var(--text)}
/* The bottom bar on a phone is a tab bar, the way apps lay one out: icon over
   a short label, each an equal slice. Four fit on the narrowest phone. */
@media(max-width:760px){
  #hub-foot{padding:4px 6px max(6px,env(safe-area-inset-bottom))}
  .hf-inner{gap:2px}
  .hf-btn{flex:1 1 0;min-width:0;flex-direction:column;gap:3px;font-size:11px;font-weight:600;padding:7px 2px;min-height:54px}
  .hf-btn span:last-child{overflow:hidden;text-overflow:ellipsis;max-width:100%}
  .hf-ico svg{width:21px;height:21px}
}

/* Says what memory is for now: the person, not the project (the README is that). */
.mp-note{margin:0;padding:10px 16px;font-size:12.5px;line-height:1.45;color:var(--muted);border-bottom:1px solid var(--border)}

.plan-empty{padding:16px;color:var(--muted,#9aa0a6);font-size:14px;line-height:1.5}

/* ─── Sign Lab (admin) ─── */
.sl{position:fixed;left:0;right:0;top:var(--app-top,0);height:var(--app-h,100%);z-index:calc(var(--z-preview) + 1);
  background:var(--bg);display:flex;flex-direction:column;opacity:0;transform:translateY(8px);
  transition:opacity .18s ease,transform .18s ease;padding:env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left)}
.sl.open{opacity:1;transform:none}
.sl[hidden]{display:none}
body.signlab-open{overflow:hidden}
.sl-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.sl :focus-visible{outline:2px solid var(--accent2);outline-offset:2px}
.sl-head{display:flex;align-items:center;gap:16px;padding:14px 24px;border-bottom:1px solid var(--border);background:var(--surface)}
.sl-titles{flex:1;min-width:0}
.sl-titles h2{font-size:18px;font-weight:650;letter-spacing:-.01em;margin:0}
#sl-title:focus,#sl-title:focus-visible,#sl-grid:focus{outline:none}
.sl-state{margin:2px 0 0;font-size:13px;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sl-head-actions{display:flex;align-items:center;gap:8px}
.sl-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:var(--r2);
  background:transparent;border:1px solid var(--border);color:var(--text2);cursor:pointer}
.sl-icon-btn:hover{color:var(--text);background:var(--surface2)}
.sl-scroll{flex:1;overflow-y:auto;overscroll-behavior:contain;padding-bottom:env(safe-area-inset-bottom)}
.sl-wrap{max-width:1240px;margin:0 auto;padding:20px 24px 48px;display:flex;flex-direction:column;gap:18px}

.sl-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:40px;padding:0 14px;border-radius:var(--r2);
  font:inherit;font-size:14px;font-weight:600;cursor:pointer;border:1px solid transparent;transition:background .12s,border-color .12s,color .12s}
.sl-btn:disabled{opacity:.55;cursor:not-allowed}
.sl-primary{background:var(--accent);color:#fff}
.sl-primary:hover:not(:disabled){background:#3b7df5}
.sl-ghost{background:transparent;border-color:var(--border-l);color:var(--text)}
.sl-ghost:hover:not(:disabled){background:var(--surface2)}
.sl-small{min-height:32px;padding:0 10px;font-size:13px}
.sl-keep{background:rgba(34,197,94,.14);border-color:rgba(34,197,94,.45);color:#86efac;flex:1}
.sl-keep:hover:not(:disabled){background:rgba(34,197,94,.24)}
.sl-trash{background:transparent;border-color:rgba(239,68,68,.45);color:#fca5a5;flex:1}
.sl-trash:hover:not(:disabled){background:rgba(239,68,68,.12)}

.sl-panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--r3);padding:18px}
.sl-h3{font-size:15px;font-weight:650;margin:0 0 10px}
.sl-label{display:block;font-size:13px;font-weight:600;color:var(--text);margin:0 0 6px}
.sl-inline{display:inline;margin:0}
.sl-optional{font-weight:400;color:var(--text2)}
.sl-hint{font-size:13px;color:var(--text2);margin:6px 0 0;line-height:1.5}
.sl-input{width:100%;background:var(--bg);border:1px solid var(--border-l);border-radius:var(--r2);color:var(--text);
  font:inherit;font-size:15px;padding:10px 12px}
.sl-input:focus{border-color:var(--accent);outline:none;box-shadow:0 0 0 3px rgba(var(--accent-rgb),.25)}
.sl-input[aria-invalid=true]{border-color:var(--err)}
textarea.sl-input{resize:vertical;min-height:84px;line-height:1.5}
.sl-row{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px}
.sl-colors{border:0;padding:0;margin:14px 0 0;display:flex;flex-wrap:wrap;gap:10px 22px;align-items:center}
.sl-colors legend{margin-bottom:6px}
.sl-color{display:flex;align-items:center;gap:8px;font-size:14px}
.sl-color input[type=checkbox]{width:18px;height:18px;accent-color:var(--accent)}
.sl-color input[type=color]{width:44px;height:32px;border:1px solid var(--border-l);border-radius:var(--r);background:var(--bg);padding:2px;cursor:pointer}
.sl-color input[type=color]:disabled{opacity:.35;cursor:not-allowed}
.sl-err{color:#fca5a5;font-size:13px;margin:10px 0 0;min-height:1em}
.sl-err:empty{display:none}
.sl-actions-row{display:flex;justify-content:flex-end;gap:10px;margin-top:16px}

.sl-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.sl-stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--r3);padding:14px 16px;display:flex;flex-direction:column;gap:2px}
.sl-stat-n{font-size:26px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.sl-stat-l{font-size:12.5px;color:var(--text2)}

.sl-auto{display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap}
.sl-auto-main{display:flex;align-items:flex-start;gap:14px;flex:1;min-width:260px}
.sl-auto-title{font-weight:600;font-size:15px}
.sl-auto-side{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.sl-every{width:auto;padding:8px 10px}
.sl-switch{position:relative;flex-shrink:0;width:46px;height:28px;border-radius:14px;border:1px solid var(--border-l);
  background:var(--surface3);cursor:pointer;margin-top:2px;transition:background .15s,border-color .15s}
.sl-switch .sl-knob{position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:var(--text2);transition:transform .15s,background .15s}
.sl-switch[aria-checked=true]{background:var(--accent);border-color:var(--accent)}
.sl-switch[aria-checked=true] .sl-knob{transform:translateX(18px);background:#fff}

.sl-tabs{display:flex;gap:4px;border-bottom:1px solid var(--border);overflow-x:auto;scrollbar-width:none}
.sl-tabs::-webkit-scrollbar{display:none}
.sl-tab{background:none;border:0;border-bottom:2px solid transparent;color:var(--text2);font:inherit;font-size:14px;font-weight:600;
  padding:10px 12px;cursor:pointer;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;margin-bottom:-1px}
.sl-tab:hover{color:var(--text)}
.sl-tab[aria-selected=true]{color:var(--text);border-bottom-color:var(--accent)}
.sl-count{font-size:12px;font-weight:600;background:var(--surface3);color:var(--text);border-radius:10px;padding:0 7px;line-height:20px}
.sl-count:empty{display:none}

.sl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px;align-items:start;outline:none}
.sl-grid[aria-busy=true]{opacity:.6}
.sl-empty{grid-column:1/-1;text-align:center;color:var(--text2);padding:48px 16px;border:1px dashed var(--border-l);border-radius:var(--r3);margin:0}
.sl-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r3);overflow:hidden;display:flex;flex-direction:column}
.sl-card[aria-busy=true]{opacity:.6}
.sl-card.sl-v-keep{border-color:rgba(34,197,94,.4)}
.sl-card.sl-v-trash{opacity:.85}
.sl-media{position:relative;background:#000;max-height:300px;width:100%;display:flex;align-items:center;justify-content:center;overflow:hidden}
.sl-media video,.sl-media img{width:100%;height:100%;object-fit:contain;display:block}
.sl-media-none{background:repeating-linear-gradient(135deg,var(--surface2) 0 10px,var(--surface3) 10px 20px)}
.sl-none-text{font-size:13px;color:var(--text2);padding:12px;text-align:center}
.sl-play{all:unset;position:absolute;inset:0;cursor:pointer;display:flex;align-items:center;justify-content:center}
.sl-play:focus-visible{outline:3px solid var(--accent2);outline-offset:-3px}
.sl-play-ico{position:absolute;width:52px;height:52px;border-radius:50%;background:rgba(0,0,0,.6);color:#fff;display:flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.35);transition:transform .12s,background .12s}
.sl-play:hover .sl-play-ico{transform:scale(1.06);background:rgba(var(--accent-rgb),.85)}
.sl-play.sl-loading .sl-play-ico{opacity:.5}
.sl-media-run{flex-direction:column;gap:10px;background:linear-gradient(180deg,var(--surface2),var(--surface3))}
.sl-run-stage{font-size:13px;color:var(--text)}
.sl-spinner{width:26px;height:26px;border-radius:50%;border:3px solid rgba(255,255,255,.15);border-top-color:var(--accent);animation:sl-spin .9s linear infinite}
@keyframes sl-spin{to{transform:rotate(360deg)}}
.sl-body{padding:14px 16px 16px;display:flex;flex-direction:column;gap:8px}
.sl-meta-top{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:12.5px}
.sl-meta-top time{margin-left:auto}
.sl-dim{color:var(--text2)}
.sl-score{font-weight:700;font-size:15px;border-radius:8px;padding:1px 8px;font-variant-numeric:tabular-nums}
.sl-score small{font-size:11px;font-weight:600;opacity:.75;margin-left:1px}
.sl-good{background:rgba(34,197,94,.16);color:#86efac}
.sl-fair{background:rgba(245,158,11,.16);color:#fcd34d}
.sl-poor{background:rgba(239,68,68,.16);color:#fca5a5}
.sl-tag{font-size:11.5px;font-weight:600;border:1px solid var(--border-l);color:var(--text2);border-radius:6px;padding:0 6px;line-height:20px}
.sl-tag-warn{border-color:rgba(245,158,11,.5);color:#fcd34d}
.sl-tag-ex{border-color:rgba(var(--accent-rgb),.6);color:#9cc2ff}
.sl-words{margin:2px 0 0;font-size:15.5px;font-weight:700;letter-spacing:.01em;line-height:1.3;display:flex;flex-direction:column}
.sl-ask{margin:0;font-size:13.5px;color:var(--text2);line-height:1.5;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.sl-facts{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:4px 14px;font-size:12.5px;color:var(--text2)}
.sl-facts li{display:inline-flex;align-items:center;gap:6px}
.sl-facts a{color:#9cc2ff;text-decoration:underline;text-underline-offset:2px}
.sl-swatch{width:12px;height:12px;border-radius:3px;border:1px solid rgba(255,255,255,.3)}
.sl-why{font-size:13px;border-top:1px solid var(--border);padding-top:8px}
.sl-why summary{cursor:pointer;color:var(--text);font-weight:600;padding:4px 0;list-style-position:inside}
.sl-lost,.sl-steps{margin:6px 0 0;padding-left:18px;color:var(--text2);line-height:1.5}
.sl-sub{margin:10px 0 0;font-size:12px;font-weight:600;color:var(--text);text-transform:uppercase;letter-spacing:.04em}
.sl-verdict{display:flex;align-items:center;gap:8px;margin-top:4px}
.sl-verdict-note{flex:1;margin:0;font-size:13px;line-height:1.4}
.sl-ok strong{color:#86efac}
.sl-bad strong{color:#fca5a5}
.sl-card.sl-failed .sl-words{color:var(--text2)}
.sl-lessons{margin:8px 0 0;padding-left:20px;display:flex;flex-direction:column;gap:6px;font-size:14px;line-height:1.5}

@media(max-width:820px){
  .sl-stats{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:600px){
  .sl-head{padding:10px 14px;gap:10px}
  .sl-head .sl-primary span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .sl-head .sl-primary{width:40px;padding:0}
  .sl-wrap{padding:14px 14px 40px;gap:14px}
  .sl-row{grid-template-columns:1fr}
  .sl-grid{grid-template-columns:1fr}
  .sl-stat-n{font-size:22px}
  .sl-state{white-space:normal}
}
@media(prefers-reduced-motion:reduce){
  .sl{transition:none;transform:none}
  .sl-spinner{animation:none;border-top-color:var(--accent);opacity:.8}
  .sl-play-ico,.sl-switch,.sl-switch .sl-knob{transition:none}
}
@media(forced-colors:active){
  .sl-switch[aria-checked=true] .sl-knob{background:Highlight}
  .sl-score,.sl-tag{border:1px solid CanvasText}
}
/* Sign Lab: the compact make-a-sign bar */
.sl-new{padding:14px}
.sl-desc{font-size:16px;min-height:64px}
.sl-site{font-size:16px;width:100%;box-sizing:border-box;margin-top:8px}
.sl-opts{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px}
.sl-chip-select{width:auto;padding:8px 10px;font-size:14px;border-radius:999px}
.sl-opts-gap{flex:1}
.sl-swatch-pick{position:relative;width:40px;height:40px;flex-shrink:0;--sw:transparent}
.sl-swatch-pick input[type=color]{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:0;padding:0}
.sl-swatch-a{pointer-events:none;display:flex;align-items:center;justify-content:center;width:100%;height:100%;border-radius:50%;
  border:1.5px dashed var(--border-l);color:var(--text2);font-weight:800;font-size:16px;background:var(--sw)}
.sl-swatch-bg .sl-swatch-a{border-radius:10px}
.sl-swatch-pick.on .sl-swatch-a{border:2px solid rgba(255,255,255,.75);color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.8)}
.sl-swatch-pick:focus-within .sl-swatch-a{outline:2px solid var(--accent2);outline-offset:2px}
.sl-swatch-x{position:absolute;top:-6px;right:-6px;width:20px;height:20px;border-radius:50%;border:1px solid var(--border-l);
  background:var(--surface3);color:var(--text);font-size:13px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}
.sl-swatch-x[hidden]{display:none}
.sl-empty{display:flex;flex-direction:column;align-items:center;gap:8px}
.sl-empty svg{color:var(--green)}
#sl-run-now span{font-weight:600}
@media(max-width:600px){
  .sl-opts-gap{flex-basis:100%;height:0}
  .sl-opts #sl-new-cancel,.sl-opts #sl-new-go{flex:1}
  .sl-auto{flex-wrap:nowrap;gap:10px;padding:12px 14px}
  .sl-auto-main{min-width:0;flex:0 0 auto;align-items:center;gap:10px}
  .sl-auto-side{flex:1;min-width:0;justify-content:flex-end;gap:8px}
  .sl-every{flex:1;min-width:0;max-width:170px}
  .sl-opts .sl-chip-select{flex:1 1 0;min-width:0;padding:8px 6px 8px 10px}
  .sl-every{padding:8px 6px 8px 10px}
  .sl-auto-side{width:auto}
  .sl-auto-side .sl-btn{flex:0 0 auto}
}

/* Sign Lab: source site and version comparison */
.sl-source-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;color:var(--text2)}
.sl-biz-help{font-size:13px;margin:0 0 12px}
.sl-biz-form{display:grid;grid-template-columns:2fr 1.2fr .6fr .8fr;gap:8px}
.sl-biz-form .sl-biz-bname{grid-column:1 / 4}
@media (max-width:640px){.sl-biz-form{grid-template-columns:1fr 1fr}.sl-biz-form .sl-biz-street,.sl-biz-form .sl-biz-bname{grid-column:1 / -1}}
.sl-biz-list{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:10px}
.sl-biz-list:empty{display:none}
.sl-biz-item{border:1px solid var(--border);border-radius:var(--r2);padding:12px}
.sl-biz-top{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.sl-biz-top strong{font-size:14px}
.sl-biz-top .sl-icon-btn{margin-left:auto}
.sl-biz-meta{font-size:12.5px;margin:2px 0 6px;overflow-wrap:anywhere}
.sl-biz-prompts{margin:0;padding-left:18px;font-size:13px;line-height:1.5}
.sl-biz-prompts li{margin:2px 0}
.sl-biz-pick{border:0;margin:0;padding:0;min-width:0}
.sl-biz-pick label{display:flex;gap:8px;align-items:flex-start;cursor:pointer;padding:3px 0}
.sl-biz-pick input{margin-top:3px;flex:none}
.sl-biz-create{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:10px 0 4px}
.sl-biz-used{color:var(--text2);font-size:12px}
.sl-biz-for{font-size:12.5px;margin:0 0 4px}
.sl-biz-result{margin-top:12px;border:1px solid var(--accent);border-radius:var(--r2);padding:14px}
.sl-biz-result h4{margin:0 0 2px;font-size:16px}
.sl-biz-facts{display:grid;grid-template-columns:max-content 1fr;gap:4px 12px;margin:10px 0;font-size:13px}
.sl-biz-facts dt{color:var(--text2)}
.sl-biz-facts dd{margin:0;overflow-wrap:anywhere}
.sl-biz-sw{display:inline-block;width:14px;height:14px;border-radius:3px;border:1px solid var(--border-l);vertical-align:-2px;margin-right:4px}
.sl-biz-notes{font-size:12px;margin:8px 0 0}
.sl-biz-more{margin-top:12px;font-size:13px}
.sl-biz-more summary{cursor:pointer;color:var(--text2)}
.sl-biz-agents{font-size:12.5px;margin:10px 0 0}
.sl-biz-agents:empty{display:none}
.sl-opts-list{font-size:12.5px;margin:6px 0 2px}
.sl-opts-list summary{cursor:pointer;color:var(--text2)}
.sl-opts-list ol{margin:6px 0 0;padding-left:18px;line-height:1.45}
.sl-opts-list li{margin:2px 0}
.sl-why{margin:6px 0 0}
.sl-source-head .sl-h3{margin:0;color:var(--text)}
.sl-source-head #sl-source-refresh{margin-left:auto}
.sl-small-icon{width:36px;height:36px}
.sl-src-row{display:grid;grid-template-columns:96px 1fr;gap:10px;align-items:start;margin-top:12px}
.sl-src-row[hidden]{display:none}
.sl-source[hidden]{display:none}
.sl-every[hidden]{display:none}
.sl-src-l{font-size:12.5px;color:var(--text2);padding-top:4px}
.sl-chips{display:flex;flex-wrap:wrap;gap:6px}
.sl-chip{font-size:12.5px;border:1px solid var(--border-l);border-radius:999px;padding:2px 10px;color:var(--text);background:var(--surface2)}
.sl-src-color{width:26px;height:26px;border-radius:8px;border:1px solid rgba(255,255,255,.25);display:inline-block}
.sl-thumbs{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:8px}
.sl-thumb{display:block;aspect-ratio:4/3;border-radius:8px;overflow:hidden;background:var(--surface3);border:1px solid var(--border)}
.sl-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.sl-cmp{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px}
.sl-table{width:100%;border-collapse:collapse;font-size:13px;font-variant-numeric:tabular-nums}
.sl-table caption{text-align:left;font-weight:600;color:var(--text2);padding-bottom:6px;font-size:12.5px}
.sl-table th,.sl-table td{padding:6px 8px;border-bottom:1px solid var(--border);text-align:right}
.sl-table th[scope=row],.sl-table thead th:first-child{text-align:left;font-weight:500;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sl-table thead th{color:var(--text2);font-weight:500}
.sl-table tr.sl-best th,.sl-table tr.sl-best td{color:#86efac;font-weight:600}
@media(max-width:600px){.sl-src-row{grid-template-columns:1fr;gap:6px}}
/* Touch screens: 44px targets win over the composer's 40px circles, and the lab's small buttons. */
@media(pointer:coarse){
  #send,.ibtn{width:44px;height:44px;min-width:44px;min-height:44px}
  .sl-small{min-height:40px}
  .sl-swatch-x{width:26px;height:26px;top:-9px;right:-9px}
}

/* Agents panel: folded groups (in progress, kept, set aside) under the review list */
.ag-group{border-top:1px solid var(--border);margin-top:6px}
.ag-group>summary{cursor:pointer;padding:12px 8px;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--text2);list-style-position:inside}
.ag-group>summary:hover{color:var(--text)}
.ag-group .ag-row{opacity:.85}

/* Agents panel: the Sign Lab team's media waiting for review */
  border:1px solid var(--border-l);position:relative;display:flex;align-items:center;justify-content:center}
.sl-prompt-hist{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:4px;font-size:13px}
.sl-prompt-hist:empty{display:none}
.sl-hist-live strong{color:#fcd34d}
