shelley: fix shell-mode indicator positioning in input bar

Philip Zeyliger and Shelley created

Wrap textarea and shell-mode indicator (>_) in a .textarea-wrapper with
position:relative so the indicator is anchored to the input field,
not the outer container. Previously the indicator floated at the left
edge of the full-width container, drifting away from the centered
input on wide viewports.

Prompt: The > thing should be in the input bar, not weirdly outside. It moves around depending on the width, and that's wrong.
Co-authored-by: Shelley <shelley@exe.dev>

Change summary

ui/src/components/MessageInput.tsx | 72 ++++++++++++++++---------------
ui/src/styles.css                  | 13 ++++-
2 files changed, 47 insertions(+), 38 deletions(-)

Detailed changes

ui/src/components/MessageInput.tsx 🔗

@@ -436,41 +436,43 @@ function MessageInput({
           accept="image/*,video/*,audio/*,.pdf,.txt,.md,.json,.csv,.xml,.html,.css,.js,.ts,.tsx,.jsx,.py,.go,.rs,.java,.c,.cpp,.h,.hpp,.sh,.yaml,.yml,.toml,.sql,.log,*"
           aria-hidden="true"
         />
-        {isShellMode && (
-          <div className="shell-mode-indicator" title="This will run as a shell command">
-            <svg
-              width="16"
-              height="16"
-              viewBox="0 0 24 24"
-              fill="none"
-              stroke="currentColor"
-              strokeWidth="2"
-            >
-              <polyline points="4 17 10 11 4 5" />
-              <line x1="12" y1="19" x2="20" y2="19" />
-            </svg>
-          </div>
-        )}
-        <textarea
-          ref={textareaRef}
-          value={message}
-          onChange={(e) => setMessage(e.target.value)}
-          onKeyDown={handleKeyDown}
-          onPaste={handlePaste}
-          onFocus={() => {
-            // Scroll to bottom after keyboard animation settles
-            if (onFocus) {
-              requestAnimationFrame(() => requestAnimationFrame(onFocus));
-            }
-          }}
-          placeholder={placeholderText}
-          className="message-textarea"
-          disabled={isDisabled}
-          rows={1}
-          aria-label="Message input"
-          data-testid="message-input"
-          autoFocus={autoFocus}
-        />
+        <div className="textarea-wrapper">
+          {isShellMode && (
+            <div className="shell-mode-indicator" title="This will run as a shell command">
+              <svg
+                width="16"
+                height="16"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                strokeWidth="2"
+              >
+                <polyline points="4 17 10 11 4 5" />
+                <line x1="12" y1="19" x2="20" y2="19" />
+              </svg>
+            </div>
+          )}
+          <textarea
+            ref={textareaRef}
+            value={message}
+            onChange={(e) => setMessage(e.target.value)}
+            onKeyDown={handleKeyDown}
+            onPaste={handlePaste}
+            onFocus={() => {
+              // Scroll to bottom after keyboard animation settles
+              if (onFocus) {
+                requestAnimationFrame(() => requestAnimationFrame(onFocus));
+              }
+            }}
+            placeholder={placeholderText}
+            className="message-textarea"
+            disabled={isDisabled}
+            rows={1}
+            aria-label="Message input"
+            data-testid="message-input"
+            autoFocus={autoFocus}
+          />
+        </div>
         <button
           type="button"
           onClick={handleAttachClick}

ui/src/styles.css 🔗

@@ -1679,7 +1679,8 @@ button {
 }
 
 .message-textarea {
-  flex: 1;
+  width: 100%;
+  box-sizing: border-box;
   min-height: 46px;
   max-height: 200px;
   padding: 0.625rem 1rem;
@@ -1872,6 +1873,13 @@ button {
   font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
   background: transparent;
   padding-left: 36px;
+  width: 100%;
+}
+
+.textarea-wrapper {
+  position: relative;
+  flex: 1;
+  min-width: 0;
 }
 
 .message-input-container.shell-mode .message-textarea::placeholder {
@@ -1881,8 +1889,7 @@ button {
 .shell-mode-indicator {
   position: absolute;
   left: 12px;
-  top: 50%;
-  transform: translateY(-50%);
+  top: 14px;
   display: flex;
   align-items: center;
   justify-content: center;