From 4e8ea337a3d4c6c47b34b4d5e399a428482011b1 Mon Sep 17 00:00:00 2001 From: billy slade Date: Thu, 3 Sep 2026 14:43:19 +0100 Subject: [PATCH 1/2] fix: keep viewport units proportional under the UI scale The Text & UI scale control transforms .shell, but every vh/vw value in the stylesheet still measured against the real, unscaled window, so modals, the code pane, and the splash screen stopped lining up with everything else at any scale other than 100%. Introduces --vh/ --vw custom properties (1% of the true viewport divided by the active scale) and rewrites every vh/vw literal to use them, so viewport units scale in lockstep with the rest of the UI. --- frontend/src/App.tsx | 2 ++ frontend/src/cockpit.css | 28 +++++++++---------- .../src/features/settings/SettingsViews.tsx | 2 ++ frontend/src/main.tsx | 3 ++ frontend/src/security.css | 28 +++++++++---------- frontend/src/styles.css | 22 +++++++-------- frontend/src/viewport.ts | 10 +++++++ 7 files changed, 56 insertions(+), 39 deletions(-) create mode 100644 frontend/src/viewport.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0736acf..8a058c7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -9,6 +9,7 @@ import { HistoryView, ReviewsView, StatsView } from "./features/repository/Repos import { AnalysisView, SecurityView, ToolsView } from "./features/operations/OperationViews"; import { EmptyWorkspace, LogsView, SettingsView, ThemeSwitcher, themes, type LogEntry } from "./features/settings/SettingsViews"; import { Loading, Rail, RemoteRepositoryNotice, Titlebar, WorkspaceHeader, destinations, isEditingTarget } from "./features/shell/Shell"; +import { updateViewportUnits } from "./viewport"; type AppCommand = { id: string; label: string; detail: string; keys: string[]; icon: LucideIcon; run: () => void }; @@ -104,6 +105,7 @@ export default function App() { document.documentElement.style.setProperty("--glass", String(bootstrap.config.glass)); document.documentElement.style.setProperty("--glass-opacity", `${Math.round(bootstrap.config.glass * 100)}%`); document.documentElement.style.setProperty("--scale", String(bootstrap.config.scale)); + updateViewportUnits(); }, [bootstrap]); // updateTheme applies and persists a theme chosen from the desktop chrome. diff --git a/frontend/src/cockpit.css b/frontend/src/cockpit.css index c7e9027..7c0f130 100644 --- a/frontend/src/cockpit.css +++ b/frontend/src/cockpit.css @@ -20,7 +20,7 @@ :root[data-theme="hackerman-ghost"] { --page:#020807;--surface:#06100e;--surface-2:#091b17;--surface-3:#0e2b25;--border:rgba(47,255,193,.24);--text:#e5fff8;--muted:#5d8d80;--accent:#2fffc1;--accent-2:#00a8ff;--cyan:#b8fff1;--green:#2fffc1;--yellow:#adff7d;--red:#64ffda;--ambient-primary:#2fffc1;--ambient-secondary:#00a8ff;--ambient-cyan:#b8fff1;--code-canvas:#010504;--glass-cast:#091b17;--shadow-cast:rgba(47,255,193,.19);--selection:rgba(47,255,193,.24); } body { background: var(--depth-canvas); } -.shell { position:relative; isolation:isolate; grid-template:68px minmax(0,1fr) / 70px minmax(0,1fr); background:radial-gradient(900px 520px at 62% -30%,color-mix(in srgb,var(--ambient-primary) 28%,transparent),transparent 66%),radial-gradient(650px 520px at 105% 100%,color-mix(in srgb,var(--ambient-secondary) 18%,transparent),transparent 70%),var(--depth-canvas); width:calc(100% / var(--scale,1)); height:calc(100vh / var(--scale,1)); transform:scale(var(--scale,1)); transform-origin:top left; } +.shell { position:relative; isolation:isolate; grid-template:68px minmax(0,1fr) / 70px minmax(0,1fr); background:radial-gradient(900px 520px at 62% -30%,color-mix(in srgb,var(--ambient-primary) 28%,transparent),transparent 66%),radial-gradient(650px 520px at 105% 100%,color-mix(in srgb,var(--ambient-secondary) 18%,transparent),transparent 70%),var(--depth-canvas); width:calc(100% / var(--scale,1)); height:calc(calc(100 * var(--vh)) / var(--scale,1)); transform:scale(var(--scale,1)); transform-origin:top left; } .shell::before { content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.22;background-image:linear-gradient(color-mix(in srgb,var(--accent) 10%,transparent) 1px,transparent 1px),linear-gradient(90deg,color-mix(in srgb,var(--accent) 10%,transparent) 1px,transparent 1px);background-size:54px 54px;mask-image:linear-gradient(to bottom,black,transparent 72%); } .titlebar { margin:0;padding:0 18px;border:0;border-bottom:1px solid color-mix(in srgb,var(--cyan) 24%,var(--border));border-radius:0;background:linear-gradient(100deg,color-mix(in srgb,var(--surface-2) 94%,var(--page)),color-mix(in srgb,var(--page) 92%,transparent))!important;box-shadow:0 14px 48px rgba(0,0,0,.38)!important; } @@ -109,11 +109,11 @@ body { background: var(--depth-canvas); } .picker__option--active { border-color:color-mix(in srgb,var(--cyan) 48%,transparent)!important;background:linear-gradient(90deg,color-mix(in srgb,var(--cyan) 18%,transparent),color-mix(in srgb,var(--accent-2) 9%,transparent))!important;box-shadow:inset 3px 0 var(--cyan); } .repo-action { padding:5px 8px;border:1px solid color-mix(in srgb,var(--cyan) 35%,var(--border));border-radius:7px;color:var(--cyan);background:color-mix(in srgb,var(--cyan) 8%,transparent);font:8px var(--mono);white-space:nowrap; } .repo-action--local { color:var(--muted);border-color:var(--border);background:transparent; } -.command-backdrop { position:fixed;inset:0;z-index:1000;display:grid;place-items:start center;padding-top:clamp(70px,12vh,130px);background:rgba(0,1,8,.68);backdrop-filter:blur(8px);animation:command-fade 130ms ease-out; } -.command-palette,.shortcut-help { width:min(680px,calc(100vw - 32px));overflow:hidden;border:1px solid color-mix(in srgb,var(--cyan) 38%,var(--border));border-radius:10px 24px 10px 24px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 98%,var(--page)),color-mix(in srgb,var(--page) 97%,black));box-shadow:var(--shadow-float);animation:command-rise 160ms cubic-bezier(.2,.8,.2,1); } +.command-backdrop { position:fixed;inset:0;z-index:1000;display:grid;place-items:start center;padding-top:clamp(70px,calc(12 * var(--vh)),130px);background:rgba(0,1,8,.68);backdrop-filter:blur(8px);animation:command-fade 130ms ease-out; } +.command-palette,.shortcut-help { width:min(680px,calc(calc(100 * var(--vw)) - 32px));overflow:hidden;border:1px solid color-mix(in srgb,var(--cyan) 38%,var(--border));border-radius:10px 24px 10px 24px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 98%,var(--page)),color-mix(in srgb,var(--page) 97%,black));box-shadow:var(--shadow-float);animation:command-rise 160ms cubic-bezier(.2,.8,.2,1); } .command-palette>header { display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;padding:14px 16px;border-bottom:1px solid var(--border);color:var(--cyan); } .command-palette>header input { width:100%;padding:5px;border:0;outline:0;color:var(--text);background:transparent;font-size:16px; } -.command-list { max-height:min(520px,58vh);overflow:auto;padding:7px; } +.command-list { max-height:min(520px,calc(58 * var(--vh)));overflow:auto;padding:7px; } .command-item { display:grid;grid-template-columns:36px minmax(0,1fr) auto;align-items:center;gap:11px;width:100%;padding:10px;border:1px solid transparent;border-radius:7px 13px 7px 13px;color:var(--text);background:transparent;text-align:left; } .command-item__icon { display:grid;place-items:center;width:34px;height:34px;border-radius:7px;color:var(--muted);background:var(--depth-recessed); } .command-item strong,.command-item small { display:block; } @@ -148,8 +148,8 @@ body { background: var(--depth-canvas); } .header-actions{gap:5px} .header-actions select{min-width:88px;max-width:130px} .header-actions .editor-action,.header-actions .github-action,.pull-status{display:none} - .code-layout{grid-template-columns:minmax(180px,min(var(--tree-pane-width, 300px), 32vw)) minmax(0,1fr)} - .code-layout--chat{grid-template-columns:minmax(180px,28vw) minmax(0,1fr) minmax(260px,36vw)} + .code-layout{grid-template-columns:minmax(180px,min(var(--tree-pane-width, 300px), calc(32 * var(--vw)))) minmax(0,1fr)} + .code-layout--chat{grid-template-columns:minmax(180px,calc(28 * var(--vw))) minmax(0,1fr) minmax(260px,calc(36 * var(--vw)))} .document.markdown{padding:28px 30px 70px} } @media(max-height:650px){ @@ -170,13 +170,13 @@ body { background: var(--depth-canvas); } .splash__binary>div:nth-child(2){animation-delay:-.55s}.splash__binary>div:nth-child(3){animation-delay:-.3s}.splash__binary>div:nth-child(4){animation-delay:-.8s} .splash__binary--upper { animation:binary-harvest-upper 3.2s cubic-bezier(.18,.76,.2,1) both; } .splash__binary--lower { animation:binary-harvest-lower 3.2s cubic-bezier(.18,.76,.2,1) both; } -.splash__scythe { z-index:5;width:min(760px,78vw);transform-origin:76% 23%;animation:scythe-harvest 2.25s .55s cubic-bezier(.12,.74,.18,1) both; } +.splash__scythe { z-index:5;width:min(760px,calc(78 * var(--vw)));transform-origin:76% 23%;animation:scythe-harvest 2.25s .55s cubic-bezier(.12,.74,.18,1) both; } .splash__handle { stroke-width:8;stroke:rgba(225,233,255,.62); } .splash__blade { stroke-width:12;filter:drop-shadow(0 0 5px #38ddff); } .splash__cut { z-index:4;height:4px;animation:harvest-cut 1.05s 1.52s cubic-bezier(.15,.7,.2,1) both; } .splash__impact { position:absolute;z-index:6;width:18px;height:18px;border-radius:50%;background:white;box-shadow:0 0 12px 5px #fff,0 0 35px 14px var(--cyan),0 0 90px 34px var(--accent),0 0 150px 55px var(--accent-2);opacity:0;transform:translate(52px,-20px);animation:harvest-impact .75s 1.72s ease-out both; } .splash__shards { position:absolute;z-index:6;width:10px;height:10px;transform:translate(52px,-20px) rotate(-19deg); } -.splash__shards i { --shard-angle:0deg;position:absolute;width:clamp(28px,5vw,72px);height:2px;background:linear-gradient(90deg,#fff,var(--cyan),transparent);box-shadow:0 0 8px var(--cyan);opacity:0;transform-origin:left center;animation:harvest-shard .82s 1.8s cubic-bezier(.1,.7,.2,1) both; } +.splash__shards i { --shard-angle:0deg;position:absolute;width:clamp(28px,calc(5 * var(--vw)),72px);height:2px;background:linear-gradient(90deg,#fff,var(--cyan),transparent);box-shadow:0 0 8px var(--cyan);opacity:0;transform-origin:left center;animation:harvest-shard .82s 1.8s cubic-bezier(.1,.7,.2,1) both; } .splash__shards i:nth-child(1){--shard-angle:-78deg}.splash__shards i:nth-child(2){--shard-angle:-58deg;animation-delay:1.84s}.splash__shards i:nth-child(3){--shard-angle:-38deg}.splash__shards i:nth-child(4){--shard-angle:-18deg;animation-delay:1.88s}.splash__shards i:nth-child(5){--shard-angle:2deg}.splash__shards i:nth-child(6){--shard-angle:22deg;animation-delay:1.82s}.splash__shards i:nth-child(7){--shard-angle:42deg}.splash__shards i:nth-child(8){--shard-angle:62deg;animation-delay:1.9s}.splash__shards i:nth-child(9){--shard-angle:82deg}.splash__shards i:nth-child(10){--shard-angle:112deg;animation-delay:1.86s}.splash__shards i:nth-child(11){--shard-angle:148deg}.splash__shards i:nth-child(12){--shard-angle:188deg;animation-delay:1.92s} .splash__identity { z-index:7;animation:harvest-identity .92s 2.16s cubic-bezier(.16,.8,.2,1) both; } .splash__identity h1 { margin-top:20px;font-size:40px;letter-spacing:.08em; } @@ -198,8 +198,8 @@ body { background: var(--depth-canvas); } @media(prefers-reduced-motion:reduce){.splash__vignette,.splash__shards,.splash__impact{display:none}.splash__identity>span{animation:none;opacity:1}.splash__identity{animation:none;opacity:1;clip-path:none;filter:none}} .splash-encounter { position:absolute;inset:0;z-index:10;display:grid;place-content:center;justify-items:center;padding:24px;background:radial-gradient(ellipse at center,rgba(5,18,37,.88),rgba(1,3,9,.94) 68%);animation:encounter-reveal .5s ease-out both; } -.encounter-quote { width:min(680px,86vw);margin:0 auto 18px;padding:18px 22px 16px;border:1px solid rgba(111,199,211,.28);border-radius:10px 22px 10px 22px;background:rgba(1,5,13,.72);box-shadow:0 18px 55px rgba(0,0,0,.45),0 0 30px rgba(70,232,255,.1);backdrop-filter:blur(8px); } -.encounter-quote blockquote { margin:0;color:#d9ffff;font:clamp(11px,1.25vw,15px)/1.45 var(--mono);letter-spacing:.015em;text-wrap:balance; } +.encounter-quote { width:min(680px,calc(86 * var(--vw)));margin:0 auto 18px;padding:18px 22px 16px;border:1px solid rgba(111,199,211,.28);border-radius:10px 22px 10px 22px;background:rgba(1,5,13,.72);box-shadow:0 18px 55px rgba(0,0,0,.45),0 0 30px rgba(70,232,255,.1);backdrop-filter:blur(8px); } +.encounter-quote blockquote { margin:0;color:#d9ffff;font:clamp(11px,calc(1.25 * var(--vw)),15px)/1.45 var(--mono);letter-spacing:.015em;text-wrap:balance; } .encounter-quote figcaption { display:flex;flex-wrap:wrap;justify-content:center;gap:5px 12px;margin-top:8px;font:9px/1.35 var(--mono);letter-spacing:.08em;text-transform:uppercase; } .encounter-quote figcaption strong { color:#9ef8ff; } .encounter-quote figcaption span { color:#607d88; } @@ -207,7 +207,7 @@ body { background: var(--depth-canvas); } .splash-encounter>button:hover,.splash-encounter>button:focus-visible { border-color:#9ef8ff;background:rgba(25,69,82,.8);box-shadow:0 0 24px rgba(70,232,255,.25); } .splash-encounter>button span { color:#607d88;font-size:8px; } @keyframes encounter-reveal { from{opacity:0;filter:blur(7px)} to{opacity:1;filter:none} } -@media(max-height:720px){.splash--ascii .splash__identity h1{font-size:clamp(20px,2.5vw,32px)}.encounter-quote{padding:12px 16px}.encounter-quote blockquote{font-size:10px}.splash--ascii .splash__identity>span{display:none}} +@media(max-height:720px){.splash--ascii .splash__identity h1{font-size:clamp(20px,calc(2.5 * var(--vw)),32px)}.encounter-quote{padding:12px 16px}.encounter-quote blockquote{font-size:10px}.splash--ascii .splash__identity>span{display:none}} .picker { display:flex;flex-direction:column; } .picker__list { flex:1;min-height:120px; } @@ -221,7 +221,7 @@ body { background: var(--depth-canvas); } .picker-empty { padding:25px;color:var(--muted);text-align:center;font-size:10px; } .guide-backdrop { position:fixed;inset:0;z-index:100;display:grid;place-items:center;padding:24px;background:rgba(1,3,10,.8);backdrop-filter:blur(12px); } -.first-run-guide { width:min(720px,92vw);padding:28px;border:1px solid color-mix(in srgb,var(--cyan) 35%,var(--border));border-radius:14px 30px 14px 30px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 96%,#07152b),var(--surface));box-shadow:0 34px 100px rgba(0,0,0,.68),0 0 60px color-mix(in srgb,var(--cyan) 10%,transparent); } +.first-run-guide { width:min(720px,calc(92 * var(--vw)));padding:28px;border:1px solid color-mix(in srgb,var(--cyan) 35%,var(--border));border-radius:14px 30px 14px 30px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 96%,#07152b),var(--surface));box-shadow:0 34px 100px rgba(0,0,0,.68),0 0 60px color-mix(in srgb,var(--cyan) 10%,transparent); } .first-run-guide h2 { margin:5px 0 6px;font-size:25px; } .first-run-guide>p { margin:0;color:var(--muted); } .first-run-guide>div { display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin:23px 0; } @@ -231,10 +231,10 @@ body { background: var(--depth-canvas); } .first-run-guide article span { color:var(--muted);font-size:10px;line-height:1.55; } .first-run-guide footer { display:flex;align-items:center;justify-content:space-between;gap:20px; } .first-run-guide footer small { color:var(--muted); } -.first-run-setup { width:min(780px,92vw); } +.first-run-setup { width:min(780px,calc(92 * var(--vw))); } .first-run-setup .workspace-setup-field { display:grid;grid-template-columns:1fr;gap:8px;margin:22px 0 0;color:var(--muted);font:10px var(--mono);letter-spacing:.08em;text-transform:uppercase; } .first-run-setup .workspace-setup-field>div { display:flex;gap:8px; } .first-run-setup .workspace-setup-field input { min-width:0;flex:1;padding:12px 14px;border:1px solid var(--border);border-radius:9px;background:var(--page);color:var(--text);font:12px var(--mono);text-transform:none;letter-spacing:0; } .first-run-setup .workspace-setup-message { margin:12px 0 0;padding:10px 12px;border:1px solid color-mix(in srgb,var(--cyan) 30%,var(--border));border-radius:8px;color:var(--text);background:color-mix(in srgb,var(--cyan) 7%,transparent);font-size:11px; } .first-run-setup footer>div,.empty-actions { display:flex;gap:8px; } -@media(max-width:700px){.first-run-guide>div{grid-template-columns:1fr}.first-run-guide{max-height:90vh;overflow:auto}} +@media(max-width:700px){.first-run-guide>div{grid-template-columns:1fr}.first-run-guide{max-height:calc(90 * var(--vh));overflow:auto}} diff --git a/frontend/src/features/settings/SettingsViews.tsx b/frontend/src/features/settings/SettingsViews.tsx index b2964b7..6a7ac2f 100644 --- a/frontend/src/features/settings/SettingsViews.tsx +++ b/frontend/src/features/settings/SettingsViews.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { ScrollText } from "lucide-react"; import { api } from "../../api"; import type { Bootstrap, ThemeName } from "../../types"; +import { updateViewportUnits } from "../../viewport"; export const themes: { name: ThemeName; label: string; palette: string[] }[] = [ { name: "reaper-dark", label: "Abduction Night", palette: ["#050713", "#315cff", "#19d9ff", "#a449ff"] }, @@ -60,6 +61,7 @@ export function SettingsView({ bootstrap, onSaved, onError }: { bootstrap: Boots document.documentElement.style.setProperty("--glass", String(draft.glass)); document.documentElement.style.setProperty("--glass-opacity", `${Math.round(draft.glass * 100)}%`); document.documentElement.style.setProperty("--scale", String(draft.scale)); + updateViewportUnits(); }, [draft]); // saveSettings validates preferences in Go and refreshes repository discovery. diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 0b0edb5..c14b4e2 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,10 +1,13 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; +import { updateViewportUnits } from "./viewport"; import "./styles.css"; import "./security.css"; import "./cockpit.css"; const applicationRoot = document.getElementById("root"); if (!applicationRoot) throw new Error("Abduction could not find its application root"); +updateViewportUnits(); +window.addEventListener("resize", updateViewportUnits); ReactDOM.createRoot(applicationRoot).render(); diff --git a/frontend/src/security.css b/frontend/src/security.css index 6462a51..a21bb41 100644 --- a/frontend/src/security.css +++ b/frontend/src/security.css @@ -1,5 +1,5 @@ .security-view { - height: calc(100vh - 116px); + height: calc(calc(100 * var(--vh)) - 116px); min-height: 0; display: grid; grid-template-columns: minmax(240px, 310px) minmax(0, 1fr); @@ -111,7 +111,7 @@ body { background:var(--page) } .search-results span { grid-column: 1 / -1; overflow: hidden; color: var(--muted); font: 9px var(--mono); text-overflow: ellipsis; white-space: nowrap; } .search-results p { padding: 16px 8px; color: var(--muted); text-align: center; } -.reviews-view { height: calc(100vh - 116px); overflow: auto; padding: 25px 30px 60px; } +.reviews-view { height: calc(calc(100 * var(--vh)) - 116px); overflow: auto; padding: 25px 30px 60px; } .reviews-view > header { display: flex; align-items: center; justify-content: space-between; max-width: 1100px; margin: 0 auto 15px; } .reviews-view h2 { margin: 0; } .review-list { display: grid; gap: 8px; max-width: 1100px; margin: auto; } @@ -123,7 +123,7 @@ body { background:var(--page) } .review-state { padding: 5px 7px; border: 1px solid var(--border); border-radius: 99px; color: var(--muted); font: 8px var(--mono); text-align: center; text-transform: uppercase; } .review-state--open { border-color: color-mix(in srgb, var(--green) 45%, transparent); color: var(--green); background: color-mix(in srgb, var(--green) 8%, transparent); } .review-toolbar { display:flex;gap:10px;max-width:1100px;margin:0 auto 14px }.review-toolbar input,.card-heading input{width:100%;padding:10px 12px;border:1px solid var(--border);border-radius:10px;color:var(--text);background:color-mix(in srgb,var(--surface-2) 78%,transparent);font:9px var(--mono);outline:none}.review-toolbar input:focus,.card-heading input:focus{border-color:color-mix(in srgb,var(--accent) 55%,var(--border));box-shadow:0 0 18px color-mix(in srgb,var(--accent) 12%,transparent)} -.reviews-layout{display:block;max-width:1100px;margin:auto}.reviews-view--detail .reviews-layout{display:grid;grid-template-columns:minmax(340px,clamp(340px,34vw,460px)) minmax(0,1fr);gap:12px;max-width:min(1500px,calc(100vw - 125px))}.reviews-layout>.review-list{min-width:0;margin:0}.review-item--active{border-color:color-mix(in srgb,var(--accent) 65%,var(--border))!important;background:color-mix(in srgb,var(--accent) 10%,var(--surface))!important}.pr-detail{min-width:0;overflow:hidden;border:1px solid var(--border);border-radius:14px;background:color-mix(in srgb,var(--surface-2) 76%,transparent);box-shadow:var(--edge)}.pr-detail>header{display:flex;align-items:start;justify-content:space-between;gap:14px;padding:18px;border-bottom:1px solid var(--border)}.pr-detail h3{margin:3px 0 0;font-size:14px}.pr-metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--border)}.pr-metrics span{padding:11px;background:var(--surface);color:var(--muted);font:8px var(--mono)}.pr-metrics b{display:block;margin-bottom:4px;color:var(--text);font-size:12px}.diff-add{color:var(--green)!important}.diff-delete{color:var(--danger,#ff5d73)!important}.pr-decision{display:flex;gap:8px;padding:12px 18px}.pr-decision span{padding:5px 8px;border:1px solid color-mix(in srgb,var(--accent-2) 35%,var(--border));border-radius:99px;color:var(--accent-2);font:8px var(--mono);text-transform:lowercase}.pr-body{max-height:120px;overflow:auto;margin:0;padding:0 18px 14px;color:var(--muted);font-size:10px;line-height:1.6;white-space:pre-wrap}.pr-files{padding:0 18px 14px}.pr-detail h4{margin:8px 0 10px;font-size:9px;text-transform:uppercase;letter-spacing:.12em}.pr-files>div{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px;padding:6px 0;border-top:1px solid var(--border);font-size:8px}.pr-files code{overflow:hidden;text-overflow:ellipsis}.pr-diff{border-top:1px solid var(--border)}.pr-diff h4{padding:0 18px}.pr-diff pre{max-height:55vh;overflow:auto;margin:0;padding:10px 0;background:color-mix(in srgb,var(--page) 82%,black);font:8px/1.55 var(--mono)}.diff-line{display:block;min-width:max-content;padding:0 14px;white-space:pre}.diff-line--add{color:color-mix(in srgb,var(--green) 82%,var(--text));background:color-mix(in srgb,var(--green) 9%,transparent)}.diff-line--delete{color:#ff8294;background:rgba(255,70,95,.08)}.diff-line--meta{color:var(--cyan);background:color-mix(in srgb,var(--cyan) 6%,transparent)} +.reviews-layout{display:block;max-width:1100px;margin:auto}.reviews-view--detail .reviews-layout{display:grid;grid-template-columns:minmax(340px,clamp(340px,calc(34 * var(--vw)),460px)) minmax(0,1fr);gap:12px;max-width:min(1500px,calc(calc(100 * var(--vw)) - 125px))}.reviews-layout>.review-list{min-width:0;margin:0}.review-item--active{border-color:color-mix(in srgb,var(--accent) 65%,var(--border))!important;background:color-mix(in srgb,var(--accent) 10%,var(--surface))!important}.pr-detail{min-width:0;overflow:hidden;border:1px solid var(--border);border-radius:14px;background:color-mix(in srgb,var(--surface-2) 76%,transparent);box-shadow:var(--edge)}.pr-detail>header{display:flex;align-items:start;justify-content:space-between;gap:14px;padding:18px;border-bottom:1px solid var(--border)}.pr-detail h3{margin:3px 0 0;font-size:14px}.pr-metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--border)}.pr-metrics span{padding:11px;background:var(--surface);color:var(--muted);font:8px var(--mono)}.pr-metrics b{display:block;margin-bottom:4px;color:var(--text);font-size:12px}.diff-add{color:var(--green)!important}.diff-delete{color:var(--danger,#ff5d73)!important}.pr-decision{display:flex;gap:8px;padding:12px 18px}.pr-decision span{padding:5px 8px;border:1px solid color-mix(in srgb,var(--accent-2) 35%,var(--border));border-radius:99px;color:var(--accent-2);font:8px var(--mono);text-transform:lowercase}.pr-body{max-height:120px;overflow:auto;margin:0;padding:0 18px 14px;color:var(--muted);font-size:10px;line-height:1.6;white-space:pre-wrap}.pr-files{padding:0 18px 14px}.pr-detail h4{margin:8px 0 10px;font-size:9px;text-transform:uppercase;letter-spacing:.12em}.pr-files>div{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:8px;padding:6px 0;border-top:1px solid var(--border);font-size:8px}.pr-files code{overflow:hidden;text-overflow:ellipsis}.pr-diff{border-top:1px solid var(--border)}.pr-diff h4{padding:0 18px}.pr-diff pre{max-height:calc(55 * var(--vh));overflow:auto;margin:0;padding:10px 0;background:color-mix(in srgb,var(--page) 82%,black);font:8px/1.55 var(--mono)}.diff-line{display:block;min-width:max-content;padding:0 14px;white-space:pre}.diff-line--add{color:color-mix(in srgb,var(--green) 82%,var(--text));background:color-mix(in srgb,var(--green) 9%,transparent)}.diff-line--delete{color:#ff8294;background:rgba(255,70,95,.08)}.diff-line--meta{color:var(--cyan);background:color-mix(in srgb,var(--cyan) 6%,transparent)} .pr-review{padding:14px 18px;border-top:1px solid var(--border)}.pr-review textarea{width:100%;box-sizing:border-box;padding:10px;border:1px solid var(--border);border-radius:10px;color:var(--text);background:var(--surface);font:9px/1.5 var(--mono);resize:vertical}.pr-review__actions{display:flex;flex-wrap:wrap;gap:7px;margin-top:8px}.pr-review__actions .danger{border-color:rgba(255,80,100,.35);color:#ff8294}.review-confirm{position:fixed;z-index:100;inset:0;display:grid;place-items:center;padding:24px;background:rgba(0,0,0,.68);backdrop-filter:blur(8px)}.review-confirm>section{width:min(480px,100%);padding:22px;border:1px solid var(--border);border-radius:16px;background:var(--surface);box-shadow:0 30px 80px rgba(0,0,0,.55)}.review-confirm h3{margin:5px 0 10px}.review-confirm p{max-height:160px;overflow:auto;color:var(--muted);font-size:10px;white-space:pre-wrap}.review-confirm footer{display:flex;justify-content:flex-end;gap:8px;margin-top:18px} @media(max-width:1050px){.reviews-layout{grid-template-columns:1fr}.pr-detail{min-height:400px}} @@ -232,9 +232,9 @@ body { background:var(--page) } .history, .tools, .reviews-view, .security-view, .settings-view { margin: 0 10px 10px; border: 1px solid color-mix(in srgb, var(--accent) 16%, var(--border)); border-radius: calc(var(--radius) + 2px); background: color-mix(in srgb, var(--surface) var(--glass-opacity), transparent); box-shadow: var(--edge), 0 26px 55px rgba(0, 0, 0, .24), 0 0 calc(38px * var(--glow)) color-mix(in srgb, var(--accent) 9%, transparent); } /* Settings is a real configuration workspace, not a generic form page. */ -.settings-view { min-height: 0; overflow: auto; padding: 32px clamp(24px, 5vw, 72px) 28px; } +.settings-view { min-height: 0; overflow: auto; padding: 32px clamp(24px, calc(5 * var(--vw)), 72px) 28px; } .settings-view > header { max-width: 820px; margin: 0 auto 26px; } -.settings-view > header h2 { margin: 0; font-size: clamp(25px, 3vw, 38px); letter-spacing: -.045em; } +.settings-view > header h2 { margin: 0; font-size: clamp(25px, calc(3 * var(--vw)), 38px); letter-spacing: -.045em; } .settings-view > header p { max-width: 630px; color: var(--muted); font-size: 12px; line-height: 1.65; } .settings-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; max-width: 1100px; margin: auto; } .settings-card { display: grid; align-content: start; gap: 17px; min-width: 0; padding: 22px; border: 1px solid color-mix(in srgb, var(--accent) 18%, var(--border)); border-radius: var(--radius); background: radial-gradient(circle at 0 0, color-mix(in srgb, var(--accent) 10%, transparent), transparent 42%), linear-gradient(145deg, color-mix(in srgb, var(--surface-2) 88%, transparent), color-mix(in srgb, var(--surface) 78%, transparent)); box-shadow: var(--edge), 0 18px 42px rgba(0, 0, 0, .2); } @@ -260,7 +260,7 @@ body { background:var(--page) } .install-pill summary::-webkit-details-marker { display: none; } .install-pill[open] summary { border-color: color-mix(in srgb, var(--accent) 52%, transparent); color: var(--text); box-shadow: 0 0 calc(18px * var(--glow)) color-mix(in srgb, var(--accent) 18%, transparent); } .install-pill[open] summary span { transform: rotate(180deg); } -.install-menu { position: absolute; top: calc(100% + 8px); right: 0; z-index: 50; display: grid; width: min(420px, 70vw); padding: 6px; border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border)); border-radius: calc(var(--radius) - 3px); background: color-mix(in srgb, var(--surface-2) 96%, transparent); box-shadow: var(--edge), 0 24px 55px rgba(0, 0, 0, .55), 0 0 calc(32px * var(--glow)) color-mix(in srgb, var(--accent) 14%, transparent); backdrop-filter: blur(24px) saturate(150%); } +.install-menu { position: absolute; top: calc(100% + 8px); right: 0; z-index: 50; display: grid; width: min(420px, calc(70 * var(--vw))); padding: 6px; border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border)); border-radius: calc(var(--radius) - 3px); background: color-mix(in srgb, var(--surface-2) 96%, transparent); box-shadow: var(--edge), 0 24px 55px rgba(0, 0, 0, .55), 0 0 calc(32px * var(--glow)) color-mix(in srgb, var(--accent) 14%, transparent); backdrop-filter: blur(24px) saturate(150%); } .install-menu button { display: grid; grid-template-columns: 58px minmax(0, 1fr) 42px; align-items: center; gap: 9px; width: 100%; padding: 10px; border: 0; border-radius: 8px; color: var(--text); background: transparent; text-align: left; } .install-menu button:hover { background: color-mix(in srgb, var(--accent) 11%, transparent); } .install-menu strong { color: var(--accent-2); font-size: 10px; } @@ -285,9 +285,9 @@ body { background:var(--page) } .log-empty p { margin: 6px 0 0; font-size: 10px; } /* Visual theme gallery follows Omarchy's preview-first selection model. */ -.theme-switcher { min-height: 0; overflow: auto; margin: 0 10px 10px; padding: 28px clamp(22px, 4vw, 58px) 50px; border: 1px solid color-mix(in srgb, var(--ambient-primary) 18%, var(--border)); border-radius: calc(var(--radius) + 2px); background: color-mix(in srgb, var(--surface) var(--glass-opacity), transparent); box-shadow: var(--edge), 0 26px 55px rgba(0,0,0,.24), 0 0 calc(42px * var(--glow)) color-mix(in srgb,var(--ambient-primary) 10%,transparent); } +.theme-switcher { min-height: 0; overflow: auto; margin: 0 10px 10px; padding: 28px clamp(22px, calc(4 * var(--vw)), 58px) 50px; border: 1px solid color-mix(in srgb, var(--ambient-primary) 18%, var(--border)); border-radius: calc(var(--radius) + 2px); background: color-mix(in srgb, var(--surface) var(--glass-opacity), transparent); box-shadow: var(--edge), 0 26px 55px rgba(0,0,0,.24), 0 0 calc(42px * var(--glow)) color-mix(in srgb,var(--ambient-primary) 10%,transparent); } .theme-switcher > header { display: flex; align-items: end; justify-content: space-between; gap: 24px; max-width: 1180px; margin: 0 auto 25px; } -.theme-switcher h2 { margin: 0; font-size: clamp(25px,3vw,38px); letter-spacing: -.045em; } +.theme-switcher h2 { margin: 0; font-size: clamp(25px,calc(3 * var(--vw)),38px); letter-spacing: -.045em; } .theme-switcher header p { max-width: 690px; margin: 8px 0 0; color: var(--muted); font-size: 11px; line-height: 1.6; } .theme-count { padding: 7px 10px; border: 1px solid var(--border); border-radius: 99px; color: var(--muted); font: 9px var(--mono); white-space: nowrap; } .theme-gallery { display: grid; grid-template-columns: repeat(auto-fill,minmax(210px,1fr)); gap: 13px; max-width: 1180px; margin: auto; } @@ -360,8 +360,8 @@ body { background:var(--page) } .clone-box>div:first-child strong{display:block;font-size:11px;white-space:nowrap}.clone-box>div:last-child{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px}.clone-box input{min-width:0;width:100%;padding:9px 10px;border:1px solid var(--border);border-radius:9px;color:var(--text);background:var(--page);font:9px var(--mono)}.clone-box .primary{padding:8px 12px} /* Focus Reader overlays all chrome while keeping tree and chat independently optional. */ -.code-layout--focus { position:fixed;inset:10px;z-index:500;height:auto;margin:0;grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), 42vw)) minmax(0,1fr);border-color:color-mix(in srgb,var(--ambient-primary) 40%,var(--border));box-shadow:0 35px 100px rgba(0,0,0,.65),0 0 calc(70px * var(--glow)) color-mix(in srgb,var(--ambient-primary) 18%,transparent);animation:focus-reader-in 180ms cubic-bezier(.2,.8,.2,1) } -.code-layout--focus.code-layout--chat{grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), 42vw)) minmax(0,1fr) minmax(320px,390px)} +.code-layout--focus { position:fixed;inset:10px;z-index:500;height:auto;margin:0;grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), calc(42 * var(--vw)))) minmax(0,1fr);border-color:color-mix(in srgb,var(--ambient-primary) 40%,var(--border));box-shadow:0 35px 100px rgba(0,0,0,.65),0 0 calc(70px * var(--glow)) color-mix(in srgb,var(--ambient-primary) 18%,transparent);animation:focus-reader-in 180ms cubic-bezier(.2,.8,.2,1) } +.code-layout--focus.code-layout--chat{grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), calc(42 * var(--vw)))) minmax(0,1fr) minmax(320px,390px)} .code-layout--focus.code-layout--tree-hidden{grid-template-columns:minmax(0,1fr)} .code-layout--focus.code-layout--tree-hidden.code-layout--chat{grid-template-columns:minmax(0,1fr) minmax(320px,390px)} .code-layout--tree-hidden>.tree{display:none} @@ -417,7 +417,7 @@ body,button,input,select,textarea { font-family:"JetBrains Mono Nerd Font","JetB .ref-list { display:flex;flex-wrap:wrap;gap:4px;margin-top:7px }.ref-list span{padding:3px 6px;border:1px solid color-mix(in srgb,var(--green) 30%,var(--border));border-radius:5px;color:var(--green);background:color-mix(in srgb,var(--green) 7%,transparent);font:8px var(--mono)} /* Repository stats balances concise facts with code-oriented composition detail. */ -.stats-view { min-height:0;overflow:auto;margin:0 10px 10px;padding:26px clamp(22px,4vw,56px) 55px;border:1px solid var(--border);border-radius:calc(var(--radius) + 2px);background:color-mix(in srgb,var(--surface) var(--glass-opacity),transparent);box-shadow:var(--edge),0 26px 55px rgba(0,0,0,.26),0 0 calc(42px * var(--glow)) color-mix(in srgb,var(--accent) 10%,transparent) } +.stats-view { min-height:0;overflow:auto;margin:0 10px 10px;padding:26px clamp(22px,calc(4 * var(--vw)),56px) 55px;border:1px solid var(--border);border-radius:calc(var(--radius) + 2px);background:color-mix(in srgb,var(--surface) var(--glass-opacity),transparent);box-shadow:var(--edge),0 26px 55px rgba(0,0,0,.26),0 0 calc(42px * var(--glow)) color-mix(in srgb,var(--accent) 10%,transparent) } .stats-view>header { display:flex;align-items:end;justify-content:space-between;gap:22px;max-width:1180px;margin:0 auto 20px }.stats-view h2{margin:0;font-size:25px;letter-spacing:-.04em}.stats-view header p{margin:6px 0 0;color:var(--muted);font:9px var(--mono)}.stats-language{padding:7px 10px;border:1px solid color-mix(in srgb,var(--cyan) 35%,var(--border));border-radius:99px;color:var(--cyan);font:9px var(--mono)} .stats-facts { display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:8px;max-width:1180px;margin:auto }.stats-facts article{padding:15px;border:1px solid var(--border);border-radius:12px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 88%,transparent),color-mix(in srgb,var(--surface) 72%,transparent));box-shadow:var(--edge)}.stats-facts span,.stats-facts strong{display:block}.stats-facts span{color:var(--muted);font-size:8px}.stats-facts strong{margin-top:8px;color:var(--text);font-size:17px;letter-spacing:-.04em} .stats-visuals{display:grid;grid-template-columns:minmax(240px,.55fr) minmax(0,1.45fr);gap:12px;max-width:1180px;margin:12px auto}.stats-visuals>article{border:1px solid var(--border);border-radius:var(--radius);background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 84%,transparent),color-mix(in srgb,var(--surface) 70%,transparent));box-shadow:var(--edge)}.language-donut{display:flex;align-items:center;gap:16px;padding:16px}.language-donut>div{position:relative;width:86px;height:86px;flex:none}.language-donut svg{width:100%;height:100%;transform:rotate(-90deg)}.language-donut circle{fill:none;stroke-width:5}.donut-track{stroke:var(--surface-3)}.donut-segment{stroke-linecap:butt}.donut-segment--1{stroke:var(--accent)}.donut-segment--2{stroke:var(--cyan)}.donut-segment--3{stroke:var(--accent-2)}.donut-segment--4{stroke:var(--green)}.donut-segment--5{stroke:#ffb454}.donut-segment--6{stroke:#ff6f91}.language-donut>div>strong{position:absolute;inset:0;display:grid;place-items:center;font-size:16px}.language-donut>span{display:grid;gap:5px;color:var(--muted);font-size:8px}.language-donut>span b{color:var(--text);font-size:12px}.stats-signal{padding:20px}.stats-signal h3{margin:7px 0 18px}.stats-signal>div{height:9px;overflow:hidden;border-radius:99px;background:var(--surface-3)}.stats-signal i{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,var(--accent),var(--cyan),var(--green));box-shadow:0 0 18px color-mix(in srgb,var(--cyan) 35%,transparent)}.stats-signal p{margin:10px 0 0;color:var(--muted);font:8px var(--mono)} @@ -515,7 +515,7 @@ body { background: radial-gradient(900px 560px at 74% -18%, color-mix(in srgb, v .lint-option>.install-pill,.scanner-row>.install-pill,.provider-install .install-pill{display:none} /* Dependencies is the single home for optional host-tool installation. */ -.dependency-view{padding:28px clamp(20px,4vw,54px) 70px}.dependency-hero{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;max-width:1180px;margin:0 auto 18px}.dependency-hero h2{margin:0;font-size:34px;letter-spacing:-.045em}.dependency-hero p{max-width:680px;margin:8px 0 0;color:var(--muted);font-size:10px;line-height:1.6}.dependency-hero>div:last-child{display:grid;justify-items:end}.dependency-hero>div:last-child strong{color:var(--cyan);font-size:25px}.dependency-hero>div:last-child span{color:var(--muted);font-size:8px;text-transform:uppercase;letter-spacing:.14em}.dependency-search{display:block;max-width:1180px;margin:0 auto 22px;padding:12px 14px;border:1px solid var(--border);border-radius:11px;color:var(--text);background:var(--page)} +.dependency-view{padding:28px clamp(20px,calc(4 * var(--vw)),54px) 70px}.dependency-hero{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;max-width:1180px;margin:0 auto 18px}.dependency-hero h2{margin:0;font-size:34px;letter-spacing:-.045em}.dependency-hero p{max-width:680px;margin:8px 0 0;color:var(--muted);font-size:10px;line-height:1.6}.dependency-hero>div:last-child{display:grid;justify-items:end}.dependency-hero>div:last-child strong{color:var(--cyan);font-size:25px}.dependency-hero>div:last-child span{color:var(--muted);font-size:8px;text-transform:uppercase;letter-spacing:.14em}.dependency-search{display:block;max-width:1180px;margin:0 auto 22px;padding:12px 14px;border:1px solid var(--border);border-radius:11px;color:var(--text);background:var(--page)} .dependency-group{max-width:1180px;margin:0 auto 24px}.dependency-group>header{display:flex;align-items:center;justify-content:space-between;margin-bottom:9px;padding:0 3px}.dependency-group>header h3{margin:0;font-size:11px;text-transform:uppercase;letter-spacing:.1em}.dependency-group>header span{color:var(--muted);font:8px var(--mono)}.dependency-group>div{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:10px}.dependency-card{min-width:0;overflow:hidden;border:1px solid var(--border);border-radius:13px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 92%,transparent),color-mix(in srgb,var(--surface) 82%,transparent));box-shadow:var(--edge),0 14px 30px rgba(0,0,0,.18)}.dependency-card--ready{border-color:color-mix(in srgb,var(--green) 25%,var(--border))}.dependency-card>header{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:start;gap:10px;padding:14px}.dependency-card>header h4{margin:0;font:12px var(--mono)}.dependency-card>header p{overflow:hidden;margin:4px 0 0;color:var(--muted);font-size:8px;text-overflow:ellipsis;white-space:nowrap}.dependency-card>header small{display:block;margin-top:5px;color:var(--accent-2);font:7px var(--mono)}.dependency-card>header>b{padding:4px 6px;border:1px solid var(--border);border-radius:5px;color:var(--muted);font:7px var(--mono)}.dependency-card--ready>header>b{color:var(--green);border-color:color-mix(in srgb,var(--green) 35%,var(--border))}.dependency-commands{display:grid;border-top:1px solid var(--border)}.dependency-commands button{display:grid;grid-template-columns:92px minmax(0,1fr) 42px;align-items:center;gap:8px;width:100%;padding:8px 11px;border:0;border-bottom:1px solid color-mix(in srgb,var(--border) 52%,transparent);color:var(--text);background:color-mix(in srgb,var(--page) 28%,transparent);text-align:left}.dependency-commands button:last-child{border-bottom:0}.dependency-commands button:hover{background:color-mix(in srgb,var(--accent) 9%,transparent)}.dependency-commands span{color:var(--accent-2);font-size:7px}.dependency-commands code{min-width:0;overflow:hidden;color:var(--muted);font:8px var(--mono);text-overflow:ellipsis;white-space:nowrap}.dependency-commands b{color:var(--cyan);font:7px var(--mono);text-align:right} @media(max-width:800px){.dependency-group>div{grid-template-columns:1fr}.dependency-hero{align-items:start}.dependency-commands button{grid-template-columns:72px minmax(0,1fr) 38px}} @@ -535,8 +535,8 @@ body { background: radial-gradient(900px 560px at 74% -18%, color-mix(in srgb, v /* File-scoped linting keeps tool selection beside normalized diagnostics. */ .lint-panel{position:relative;z-index:1;width:100%;min-width:0;max-width:100%;overflow:hidden;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--surface-2) 82%,transparent);contain:inline-size} .lint-panel__toggle{width:100%;height:38px;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:10px;padding:0 18px;border:0;color:var(--text);background:transparent;text-align:left}.lint-panel__toggle>span{color:var(--cyan);font-size:10px;font-weight:700}.lint-panel__toggle small{color:var(--muted);font:8px var(--mono)}.lint-panel__toggle b{color:var(--accent-2);font-size:15px} -.lint-panel__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(150px,1fr);height:min(480px,58vh);min-height:300px;min-width:0;max-width:100%;overflow:hidden;border-top:1px solid var(--border);box-shadow:0 16px 32px rgba(0,0,0,.2)}.lint-picker{min-width:0;max-height:230px;overflow-y:auto;overflow-x:hidden;padding:14px;border-right:0;border-bottom:1px solid var(--border)}.lint-picker>header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.lint-picker>header strong{font-size:11px}.lint-picker>header .primary{flex:0 0 auto;padding:7px 10px;font-size:9px}.lint-picker>p,.lint-results p,.lint-empty{color:var(--muted);font-size:9px;line-height:1.55} +.lint-panel__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(150px,1fr);height:min(480px,calc(58 * var(--vh)));min-height:300px;min-width:0;max-width:100%;overflow:hidden;border-top:1px solid var(--border);box-shadow:0 16px 32px rgba(0,0,0,.2)}.lint-picker{min-width:0;max-height:230px;overflow-y:auto;overflow-x:hidden;padding:14px;border-right:0;border-bottom:1px solid var(--border)}.lint-picker>header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.lint-picker>header strong{font-size:11px}.lint-picker>header .primary{flex:0 0 auto;padding:7px 10px;font-size:9px}.lint-picker>p,.lint-results p,.lint-empty{color:var(--muted);font-size:9px;line-height:1.55} .lint-option{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px;padding:8px 0;border-top:1px solid color-mix(in srgb,var(--border) 65%,transparent)}.lint-option label{display:flex;align-items:center;gap:9px;min-width:0;cursor:pointer}.lint-option label>span{min-width:0}.lint-option input{width:14px;height:14px;flex:0 0 14px;accent-color:var(--cyan)}.lint-option strong,.lint-option small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lint-option strong{font-size:9px}.lint-option small{margin-top:3px;color:var(--muted);font-size:7px}.lint-option>.install-pill{grid-column:2;min-width:max-content}.lint-option:has(>.install-pill[open]){grid-template-columns:minmax(0,1fr)}.lint-option:has(>.install-pill[open])>.install-pill{grid-column:1;width:100%}.lint-option>.install-pill[open]>summary{width:max-content;margin-left:auto}.lint-option .install-menu{position:static;width:100%;margin-top:8px;max-width:none}.lint-option .install-menu button{grid-template-columns:76px minmax(0,1fr) 38px}.lint-option .install-menu code{white-space:normal;overflow-wrap:anywhere;line-height:1.4} .lint-results{min-width:0;max-width:100%;overflow:auto;padding:12px 14px;background:var(--code-canvas)}.lint-results>article{max-width:100%;margin-bottom:12px;border:1px solid var(--border);border-radius:10px;overflow:hidden;background:color-mix(in srgb,var(--surface) 78%,transparent)}.lint-results>article>header{display:flex;justify-content:space-between;padding:8px 10px;border-bottom:1px solid var(--border)}.lint-results>article>header strong{font-size:9px}.lint-results>article>header span{color:var(--muted);font:8px var(--mono)}.lint-results article>button{width:100%;min-width:0;display:grid;grid-template-columns:auto auto minmax(0,1fr);align-items:start;gap:8px;padding:8px 10px;border:0;border-bottom:1px solid color-mix(in srgb,var(--border) 55%,transparent);color:var(--text);background:transparent;text-align:left}.lint-results article>button:hover{background:color-mix(in srgb,var(--accent) 9%,transparent)}.lint-results article>button code{max-width:180px;overflow:hidden;color:var(--accent-2);font:8px var(--mono);text-overflow:ellipsis;white-space:nowrap}.lint-results article>button span{min-width:0;overflow-wrap:anywhere;font-size:9px;line-height:1.45}.lint-results article>pre{max-width:100%;max-height:150px;overflow:auto;margin:0;padding:10px;color:var(--muted);font:8px/1.55 var(--mono);white-space:pre-wrap;overflow-wrap:anywhere} .lint-severity{padding:2px 5px;border-radius:4px;color:var(--yellow);background:color-mix(in srgb,var(--yellow) 10%,transparent);font:7px var(--mono)}.lint-severity--error{color:var(--red);background:color-mix(in srgb,var(--red) 10%,transparent)} -@media(max-width:900px){.lint-panel__body{height:min(420px,55vh)}.lint-results article>button{grid-template-columns:auto minmax(0,1fr)}.lint-results article>button span{grid-column:1/-1}} +@media(max-width:900px){.lint-panel__body{height:min(420px,calc(55 * var(--vh)))}.lint-results article>button{grid-template-columns:auto minmax(0,1fr)}.lint-results article>button span{grid-column:1/-1}} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 811acb0..8ded96c 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -16,7 +16,7 @@ html, body, #root { margin:0; min-width:100%; min-height:100%; overflow:hidden; body { color:var(--text); background:radial-gradient(900px 620px at 76% -14%,color-mix(in srgb,var(--accent) 29%,transparent),transparent 62%),radial-gradient(760px 520px at -8% 108%,color-mix(in srgb,var(--accent-2) 23%,transparent),transparent 64%),linear-gradient(155deg,var(--page),color-mix(in srgb,var(--surface) 72%,var(--page))); } button,input,select { font:inherit; } button,select { cursor:pointer; } button:focus-visible,input:focus-visible,select:focus-visible { outline:0; border-color:var(--accent-2)!important; box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 20%,transparent),0 0 calc(20px * var(--glow-size)) color-mix(in srgb,var(--accent) 28%,transparent)!important; } -.shell { height:100vh; display:grid; grid-template:42px 1fr / 68px 292px 1fr; } +.shell { height:calc(100 * var(--vh)); display:grid; grid-template:42px 1fr / 68px 292px 1fr; } .titlebar { grid-column:1/-1; display:grid; grid-template-columns:1fr auto 1fr; align-items:center; padding:0 20px; border-bottom:1px solid var(--border); background:color-mix(in srgb,var(--page) 80%,transparent); backdrop-filter:blur(22px) saturate(150%); box-shadow:0 8px 36px rgba(0,0,0,.22); --wails-draggable:drag; user-select:none; z-index:10; } .titlebar span { font-weight:750; letter-spacing:.04em; background:linear-gradient(90deg,var(--text),var(--accent),var(--accent-2)); background-clip:text; color:transparent; }.titlebar small{justify-self:end;color:var(--muted);font:11px var(--mono)} .rail { grid-row:2; display:flex; flex-direction:column; align-items:center; gap:10px; padding:15px 10px; border-right:1px solid var(--border); background:linear-gradient(180deg,color-mix(in srgb,var(--surface) 88%,transparent),color-mix(in srgb,var(--page) 90%,transparent)); box-shadow:5px 0 calc(30px * var(--glow-size)) color-mix(in srgb,var(--accent) 9%,transparent); } @@ -29,14 +29,14 @@ button:focus-visible,input:focus-visible,select:focus-visible { outline:0; borde .workspace { grid-row:2;min-width:0;overflow:auto;padding:0 24px 38px }.workspace__header{position:sticky;top:0;z-index:5;display:flex;align-items:center;justify-content:space-between;gap:20px;padding:18px 0 14px;background:linear-gradient(var(--page) 72%,transparent);backdrop-filter:blur(10px)}.workspace__header h1{margin:0;font-size:24px;letter-spacing:-.025em}.header-actions{display:flex;align-items:center;gap:8px}.header-actions select{width:auto;padding:8px 30px 8px 10px}.pill,.chip{white-space:nowrap;padding:6px 10px;border:1px solid var(--border);border-radius:99px;color:var(--muted);font:10px var(--mono);background:color-mix(in srgb,var(--surface-2) 70%,transparent)} .ghost,.primary,.crumb { border-radius:9px;padding:8px 12px;color:var(--text);border:1px solid var(--border);background:transparent;font-size:12px}.ghost:hover{background:color-mix(in srgb,var(--accent) 12%,transparent);box-shadow:0 0 calc(17px * var(--glow-size)) color-mix(in srgb,var(--accent) 18%,transparent)}.primary{border-color:color-mix(in srgb,var(--accent-2) 55%,transparent);background:linear-gradient(135deg,var(--accent),var(--accent-2));box-shadow:var(--edge),0 8px calc(22px * var(--glow-size)) color-mix(in srgb,var(--accent) 30%,transparent)} .panel { min-width:0;border:1px solid var(--border);border-radius:17px;background:radial-gradient(circle at 8% 0,color-mix(in srgb,var(--accent) 8%,transparent),transparent 34%),linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 94%,transparent),color-mix(in srgb,var(--surface) 88%,transparent));box-shadow:var(--edge),var(--elevation),var(--halo);backdrop-filter:blur(16px) saturate(140%) } -.code-layout{height:calc(100vh - 126px);min-height:500px;display:grid;grid-template-columns:clamp(260px,30vw,380px) minmax(0,1fr);gap:14px}.tree,.reader{min-width:0;height:100%;overflow:auto}.tree{padding:12px}.tree__head{display:flex;gap:5px;align-items:center;min-width:0;padding:0 2px 10px;color:var(--muted);font:10px var(--mono);overflow:hidden}.tree__head>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crumb{padding:5px 7px;font:10px var(--mono)}.tree__list{display:grid}.tree__entry{display:grid;grid-template-columns:20px minmax(0,1fr) auto;align-items:center;gap:6px;width:100%;padding:7px 6px;border:0;border-radius:8px;color:var(--muted);background:transparent;text-align:left;font-size:12px}.tree__entry:hover{color:var(--text);background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 15%,transparent),color-mix(in srgb,var(--accent-2) 7%,transparent))}.tree__entry small{font:9px var(--mono);opacity:.7}.tree__entry b{color:var(--accent-2)}.entry-icon{color:var(--muted)}.entry-icon--folder{color:var(--accent)}.tree__up{color:var(--accent-2);margin-bottom:3px} +.code-layout{height:calc(calc(100 * var(--vh)) - 126px);min-height:500px;display:grid;grid-template-columns:clamp(260px,calc(30 * var(--vw)),380px) minmax(0,1fr);gap:14px}.tree,.reader{min-width:0;height:100%;overflow:auto}.tree{padding:12px}.tree__head{display:flex;gap:5px;align-items:center;min-width:0;padding:0 2px 10px;color:var(--muted);font:10px var(--mono);overflow:hidden}.tree__head>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.crumb{padding:5px 7px;font:10px var(--mono)}.tree__list{display:grid}.tree__entry{display:grid;grid-template-columns:20px minmax(0,1fr) auto;align-items:center;gap:6px;width:100%;padding:7px 6px;border:0;border-radius:8px;color:var(--muted);background:transparent;text-align:left;font-size:12px}.tree__entry:hover{color:var(--text);background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 15%,transparent),color-mix(in srgb,var(--accent-2) 7%,transparent))}.tree__entry small{font:9px var(--mono);opacity:.7}.tree__entry b{color:var(--accent-2)}.entry-icon{color:var(--muted)}.entry-icon--folder{color:var(--accent)}.tree__up{color:var(--accent-2);margin-bottom:3px} .reader{background:color-mix(in srgb,var(--surface) 92%,transparent)}.reader__head{position:sticky;top:0;z-index:2;display:flex;align-items:center;justify-content:space-between;gap:20px;padding:16px 20px;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--surface) 88%,transparent);backdrop-filter:blur(18px)}.reader__meta{display:flex;align-items:center;gap:10px;color:var(--muted);font:10px var(--mono)}.reader__loading{display:grid;place-items:center;height:70%;color:var(--muted)}.document{min-height:calc(100% - 70px)}.document.code{overflow:auto;padding:12px 0;background:#11111b}.document.code pre{margin:0!important;padding:0 18px!important;font:12px/1.65 var(--mono)!important}.document.code td:first-child{user-select:none;opacity:.45}.document.markdown{max-width:920px;margin:0 auto;padding:34px 44px 70px;line-height:1.72}.markdown h1,.markdown h2,.markdown h3{line-height:1.25;margin:1.6em 0 .6em}.markdown h1{font-size:30px}.markdown h2{font-size:22px;border-bottom:1px solid var(--border);padding-bottom:9px}.markdown p,.markdown li{color:color-mix(in srgb,var(--text) 90%,var(--muted))}.markdown a{color:var(--cyan)}.markdown code{font-family:var(--mono);font-size:.88em;background:color-mix(in srgb,var(--surface-3) 65%,transparent);border:1px solid var(--border);border-radius:5px;padding:2px 5px}.markdown pre{overflow:auto;padding:16px;border:1px solid var(--border);border-radius:12px;background:var(--page)}.markdown pre code{border:0;background:transparent;padding:0}.markdown blockquote{margin-left:0;padding-left:16px;border-left:3px solid var(--accent);color:var(--muted)} .markdown-code-frame{position:relative;margin:1em 0}.markdown-code-frame pre{margin:0;padding:42px 18px 18px}.markdown-copy{position:absolute;z-index:4;top:8px;right:8px;padding:6px 10px;border:1px solid color-mix(in srgb,var(--border) 82%,var(--accent));border-radius:7px;color:var(--muted);background:color-mix(in srgb,var(--surface-2) 98%,var(--page));box-shadow:var(--edge),0 5px 14px rgba(0,0,0,.32);font:9px var(--mono);line-height:1;cursor:pointer;transition:120ms ease}.markdown-copy:hover,.markdown-copy:focus-visible{color:var(--text);border-color:color-mix(in srgb,var(--cyan) 58%,var(--border));background:var(--surface-3);box-shadow:0 0 13px color-mix(in srgb,var(--cyan) 22%,transparent)}.markdown-copy--done{color:var(--green);border-color:color-mix(in srgb,var(--green) 55%,var(--border))} .history{padding:20px;max-width:1100px}.timeline{position:relative;display:grid;padding-left:10px}.timeline::before{content:"";position:absolute;left:18px;top:12px;bottom:12px;width:1px;background:linear-gradient(var(--accent),color-mix(in srgb,var(--accent-2) 50%,transparent));box-shadow:0 0 8px color-mix(in srgb,var(--accent) 55%,transparent)}.commit{position:relative;display:grid;grid-template-columns:18px 64px minmax(0,1fr);gap:12px;padding:10px 0;align-items:start}.commit__node{position:relative;z-index:1;width:9px;height:9px;margin-top:4px;border:2px solid var(--accent);border-radius:50%;background:var(--surface);box-shadow:0 0 9px color-mix(in srgb,var(--accent) 65%,transparent)}.commit code{color:var(--accent-2);font:11px var(--mono)}.commit strong,.commit small{display:block}.commit strong{font-size:13px}.commit small{margin-top:5px;color:var(--muted);font-size:10px}.tools{max-width:1100px}.tool-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}.tool{display:grid;grid-template-columns:12px 1fr auto;align-items:center;gap:12px;padding:17px}.tool h3{margin:0 0 4px;font:13px var(--mono)}.tool p{margin:0;color:var(--muted);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tool__light{width:8px;height:8px;border-radius:50%;background:var(--muted)}.tool__light--ready{background:var(--green);box-shadow:0 0 9px var(--green)}.chip--ready{color:var(--green);border-color:color-mix(in srgb,var(--green) 42%,transparent);background:color-mix(in srgb,var(--green) 9%,transparent)} -.empty{max-width:620px;margin:10vh auto;padding:44px;text-align:center}.empty .reaper-mark{margin:0 auto 20px}.empty p{color:var(--muted)}.empty code{font-family:var(--mono);color:var(--accent-2)}.loading{height:100vh;display:grid;place-content:center;justify-items:center;gap:8px;text-align:center}.loading .reaper-mark{width:68px;height:68px;border-radius:20px;font-size:24px;animation:pulse 2s ease-in-out infinite}.loading h1{margin:10px 0 0}.loading p{margin:0;color:var(--muted)}.notice{margin-bottom:12px;padding:10px 12px;border:1px solid color-mix(in srgb,var(--red) 45%,transparent);border-radius:10px;color:var(--red);background:color-mix(in srgb,var(--red) 9%,transparent);font-size:12px}@keyframes pulse{50%{transform:scale(1.06);filter:brightness(1.18)}} +.empty{max-width:620px;margin:calc(10 * var(--vh)) auto;padding:44px;text-align:center}.empty .reaper-mark{margin:0 auto 20px}.empty p{color:var(--muted)}.empty code{font-family:var(--mono);color:var(--accent-2)}.loading{height:calc(100 * var(--vh));display:grid;place-content:center;justify-items:center;gap:8px;text-align:center}.loading .reaper-mark{width:68px;height:68px;border-radius:20px;font-size:24px;animation:pulse 2s ease-in-out infinite}.loading h1{margin:10px 0 0}.loading p{margin:0;color:var(--muted)}.notice{margin-bottom:12px;padding:10px 12px;border:1px solid color-mix(in srgb,var(--red) 45%,transparent);border-radius:10px;color:var(--red);background:color-mix(in srgb,var(--red) 9%,transparent);font-size:12px}@keyframes pulse{50%{transform:scale(1.06);filter:brightness(1.18)}} @media(max-width:1150px){.shell{grid-template-columns:62px 250px 1fr}.header-actions .pill{display:none}.code-layout{grid-template-columns:220px minmax(0,1fr)}} @media(prefers-reduced-motion:reduce){*{animation-duration:.001ms!important;transition-duration:.001ms!important}} -.splash{position:fixed;inset:0;display:grid;place-items:center;overflow:hidden;background:radial-gradient(750px 420px at 50% 48%,rgba(92,67,255,.17),transparent 66%),#02030b;color:#f7f7ff}.splash__aura{position:absolute;width:560px;height:360px;border-radius:50%;background:radial-gradient(circle,rgba(91,91,255,.23),rgba(56,221,255,.08) 44%,transparent 72%);filter:blur(28px);animation:splash-aura 2.2s ease both}.splash__binary{position:absolute;inset:0;display:grid;align-content:center;gap:20px;transform:rotate(-8deg) scale(1.22);color:rgba(148,163,255,.22);font:20px/1 var(--mono);letter-spacing:.4em;white-space:nowrap;animation:binary-arrive 1.45s cubic-bezier(.2,.8,.2,1) both}.splash__binary>div:nth-child(odd){transform:translateX(-7%)}.splash__binary>div:nth-child(even){transform:translateX(8%)}.splash__scythe{position:absolute;width:min(620px,72vw);overflow:visible;filter:drop-shadow(0 0 8px rgba(56,221,255,.8)) drop-shadow(0 0 26px rgba(102,90,255,.65));transform:translate(48%,-34%) rotate(-13deg);animation:scythe-swing 1.05s .35s cubic-bezier(.16,.76,.28,1) both}.splash__handle{fill:none;stroke:rgba(205,214,244,.52);stroke-width:9;stroke-linecap:round}.splash__blade{fill:none;stroke:url(#scythe-edge);stroke-width:13;stroke-linecap:round;stroke-linejoin:round}.splash__cut{position:absolute;width:130vw;height:3px;background:linear-gradient(90deg,transparent,var(--cyan) 38%,var(--accent-2) 55%,transparent);box-shadow:0 0 9px var(--cyan),0 0 34px var(--accent);transform:rotate(-19deg) scaleX(0);animation:cut-flash .72s .95s ease-out both}.splash__identity{position:relative;display:grid;justify-items:center;opacity:0;clip-path:inset(50% 0 50%);animation:identity-reveal .8s 1.18s cubic-bezier(.2,.8,.2,1) forwards}.splash__mark{display:grid;place-items:center;width:76px;height:76px;border-radius:22px;color:white;font-size:27px;font-weight:900;background:linear-gradient(145deg,#557dff,#9b4dff);border:1px solid rgba(196,181,253,.62);box-shadow:inset 0 1px rgba(255,255,255,.22),0 0 26px rgba(91,91,255,.72),0 0 70px rgba(56,145,255,.28)}.splash__identity h1{margin:18px 0 2px;font-size:34px;letter-spacing:.06em;background:linear-gradient(90deg,#fff,#b7c7ff 52%,#c5a4ff);background-clip:text;color:transparent}.splash__identity p{margin:0;color:#9ba2c8;font:10px var(--mono);letter-spacing:.18em;text-transform:uppercase}@keyframes binary-arrive{0%{opacity:0;transform:rotate(-8deg) scale(1.36)}55%{opacity:1}100%{opacity:.78;transform:rotate(-8deg) scale(1.22)}}@keyframes scythe-swing{0%{opacity:0;transform:translate(80%,-65%) rotate(-48deg)}18%{opacity:1}78%{opacity:1}100%{opacity:0;transform:translate(-60%,48%) rotate(22deg)}}@keyframes cut-flash{0%{opacity:0;transform:rotate(-19deg) scaleX(0)}34%{opacity:1;transform:rotate(-19deg) scaleX(1)}100%{opacity:0;transform:rotate(-19deg) scaleX(1)}}@keyframes identity-reveal{to{opacity:1;clip-path:inset(0 0 0)}}@keyframes splash-aura{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1)}100%{opacity:.72;transform:scale(1.12)}} +.splash{position:fixed;inset:0;display:grid;place-items:center;overflow:hidden;background:radial-gradient(750px 420px at 50% 48%,rgba(92,67,255,.17),transparent 66%),#02030b;color:#f7f7ff}.splash__aura{position:absolute;width:560px;height:360px;border-radius:50%;background:radial-gradient(circle,rgba(91,91,255,.23),rgba(56,221,255,.08) 44%,transparent 72%);filter:blur(28px);animation:splash-aura 2.2s ease both}.splash__binary{position:absolute;inset:0;display:grid;align-content:center;gap:20px;transform:rotate(-8deg) scale(1.22);color:rgba(148,163,255,.22);font:20px/1 var(--mono);letter-spacing:.4em;white-space:nowrap;animation:binary-arrive 1.45s cubic-bezier(.2,.8,.2,1) both}.splash__binary>div:nth-child(odd){transform:translateX(-7%)}.splash__binary>div:nth-child(even){transform:translateX(8%)}.splash__scythe{position:absolute;width:min(620px,calc(72 * var(--vw)));overflow:visible;filter:drop-shadow(0 0 8px rgba(56,221,255,.8)) drop-shadow(0 0 26px rgba(102,90,255,.65));transform:translate(48%,-34%) rotate(-13deg);animation:scythe-swing 1.05s .35s cubic-bezier(.16,.76,.28,1) both}.splash__handle{fill:none;stroke:rgba(205,214,244,.52);stroke-width:9;stroke-linecap:round}.splash__blade{fill:none;stroke:url(#scythe-edge);stroke-width:13;stroke-linecap:round;stroke-linejoin:round}.splash__cut{position:absolute;width:calc(130 * var(--vw));height:3px;background:linear-gradient(90deg,transparent,var(--cyan) 38%,var(--accent-2) 55%,transparent);box-shadow:0 0 9px var(--cyan),0 0 34px var(--accent);transform:rotate(-19deg) scaleX(0);animation:cut-flash .72s .95s ease-out both}.splash__identity{position:relative;display:grid;justify-items:center;opacity:0;clip-path:inset(50% 0 50%);animation:identity-reveal .8s 1.18s cubic-bezier(.2,.8,.2,1) forwards}.splash__mark{display:grid;place-items:center;width:76px;height:76px;border-radius:22px;color:white;font-size:27px;font-weight:900;background:linear-gradient(145deg,#557dff,#9b4dff);border:1px solid rgba(196,181,253,.62);box-shadow:inset 0 1px rgba(255,255,255,.22),0 0 26px rgba(91,91,255,.72),0 0 70px rgba(56,145,255,.28)}.splash__identity h1{margin:18px 0 2px;font-size:34px;letter-spacing:.06em;background:linear-gradient(90deg,#fff,#b7c7ff 52%,#c5a4ff);background-clip:text;color:transparent}.splash__identity p{margin:0;color:#9ba2c8;font:10px var(--mono);letter-spacing:.18em;text-transform:uppercase}@keyframes binary-arrive{0%{opacity:0;transform:rotate(-8deg) scale(1.36)}55%{opacity:1}100%{opacity:.78;transform:rotate(-8deg) scale(1.22)}}@keyframes scythe-swing{0%{opacity:0;transform:translate(80%,-65%) rotate(-48deg)}18%{opacity:1}78%{opacity:1}100%{opacity:0;transform:translate(-60%,48%) rotate(22deg)}}@keyframes cut-flash{0%{opacity:0;transform:rotate(-19deg) scaleX(0)}34%{opacity:1;transform:rotate(-19deg) scaleX(1)}100%{opacity:0;transform:rotate(-19deg) scaleX(1)}}@keyframes identity-reveal{to{opacity:1;clip-path:inset(0 0 0)}}@keyframes splash-aura{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1)}100%{opacity:.72;transform:scale(1.12)}} @media(prefers-reduced-motion:reduce){.splash__binary,.splash__scythe,.splash__cut{display:none}.splash__identity{opacity:1;clip-path:none}.splash__aura{opacity:.7}} .splash__binary--upper { clip-path:polygon(0 0,100% 0,100% 38%,0 72%);animation:binary-split-upper 1.85s cubic-bezier(.2,.8,.2,1) both } .splash__binary--lower { clip-path:polygon(0 72%,100% 38%,100% 100%,0 100%);animation:binary-split-lower 1.85s cubic-bezier(.2,.8,.2,1) both } @@ -51,16 +51,16 @@ button:focus-visible,input:focus-visible,select:focus-visible { outline:0; borde .titlebar{grid-template-columns:1fr minmax(300px,520px) 1fr;padding:0 16px;gap:16px} .titlebar__brand{display:flex;align-items:center;gap:9px;justify-self:start}.titlebar__brand strong{font-size:14px;letter-spacing:.035em}.titlebar__mark{display:grid;place-items:center;width:30px;height:30px;border-radius:9px;color:white!important;background:linear-gradient(145deg,var(--accent),var(--accent-2));box-shadow:var(--edge),0 0 calc(18px * var(--glow-size)) color-mix(in srgb,var(--accent) 38%,transparent);background-clip:border-box!important} .top-context{justify-self:center;width:min(660px,100%);display:grid;grid-template-columns:minmax(0,1fr) 150px;gap:7px;--wails-draggable:no-drag}.repo-picker{width:100%;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:10px;padding:7px 8px 7px 12px;color:var(--text);border:1px solid var(--border);border-radius:12px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-3) 65%,transparent),color-mix(in srgb,var(--surface) 88%,transparent));box-shadow:var(--edge),0 0 calc(20px * var(--glow-size)) color-mix(in srgb,var(--accent) 10%,transparent)}.repo-picker>span{color:var(--muted);font-size:9px;text-transform:uppercase;letter-spacing:.12em}.repo-picker>strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;font-size:12px}.branch-picker{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;padding-left:9px;border:1px solid var(--border);border-radius:12px;color:var(--accent-2);background:color-mix(in srgb,var(--surface-2) 80%,transparent)}.branch-picker select{min-width:0;border:0;padding:7px 22px 7px 7px;background:transparent;font:10px var(--mono)}kbd{padding:3px 6px;border:1px solid var(--border);border-radius:5px;color:var(--muted);background:color-mix(in srgb,var(--surface-3) 62%,transparent);font:9px var(--mono)}.titlebar__platform{justify-self:end;color:var(--muted);font:10px var(--mono)} -.picker-backdrop{position:fixed;inset:58px 0 0;z-index:50;display:grid;place-items:start center;padding-top:7vh;background:rgba(2,3,11,.62);backdrop-filter:blur(8px)}.picker{width:min(640px,calc(100vw - 48px));max-height:70vh;display:grid;grid-template-rows:auto auto minmax(0,1fr) auto;overflow:hidden;border:1px solid color-mix(in srgb,var(--accent) 48%,transparent);border-radius:18px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 98%,transparent),color-mix(in srgb,var(--surface) 96%,transparent));box-shadow:var(--edge),0 32px 90px rgba(0,0,0,.62),0 0 calc(50px * var(--glow-size)) color-mix(in srgb,var(--accent) 20%,transparent);animation:picker-in 150ms ease}.picker>header{padding:18px 20px 10px}.picker h2{margin:0;font-size:18px}.picker>input{margin:4px 14px 10px;width:calc(100% - 28px);padding:12px 14px;color:var(--text);border:1px solid var(--border);border-radius:11px;background:var(--page)}.picker__list{overflow:auto;padding:4px 8px 12px}.picker__list>button{width:100%;display:grid;grid-template-columns:32px minmax(0,1fr) auto;align-items:center;gap:10px;padding:10px;border:1px solid transparent;border-radius:11px;color:var(--text);background:transparent;text-align:left}.picker__list>button:hover,.picker__list>button:focus{border-color:color-mix(in srgb,var(--accent) 36%,transparent);background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 18%,transparent),color-mix(in srgb,var(--accent-2) 10%,transparent))}.picker__list strong,.picker__list small{display:block}.picker__list small{margin-top:3px;color:var(--muted);font-size:10px}.picker>footer{display:flex;gap:16px;padding:10px 15px;border-top:1px solid var(--border);color:var(--muted);font-size:9px}@keyframes picker-in{from{opacity:0;transform:translateY(-8px) scale(.985)}} +.picker-backdrop{position:fixed;inset:58px 0 0;z-index:50;display:grid;place-items:start center;padding-top:calc(7 * var(--vh));background:rgba(2,3,11,.62);backdrop-filter:blur(8px)}.picker{width:min(640px,calc(calc(100 * var(--vw)) - 48px));max-height:calc(70 * var(--vh));display:grid;grid-template-rows:auto auto minmax(0,1fr) auto;overflow:hidden;border:1px solid color-mix(in srgb,var(--accent) 48%,transparent);border-radius:18px;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-2) 98%,transparent),color-mix(in srgb,var(--surface) 96%,transparent));box-shadow:var(--edge),0 32px 90px rgba(0,0,0,.62),0 0 calc(50px * var(--glow-size)) color-mix(in srgb,var(--accent) 20%,transparent);animation:picker-in 150ms ease}.picker>header{padding:18px 20px 10px}.picker h2{margin:0;font-size:18px}.picker>input{margin:4px 14px 10px;width:calc(100% - 28px);padding:12px 14px;color:var(--text);border:1px solid var(--border);border-radius:11px;background:var(--page)}.picker__list{overflow:auto;padding:4px 8px 12px}.picker__list>button{width:100%;display:grid;grid-template-columns:32px minmax(0,1fr) auto;align-items:center;gap:10px;padding:10px;border:1px solid transparent;border-radius:11px;color:var(--text);background:transparent;text-align:left}.picker__list>button:hover,.picker__list>button:focus{border-color:color-mix(in srgb,var(--accent) 36%,transparent);background:linear-gradient(90deg,color-mix(in srgb,var(--accent) 18%,transparent),color-mix(in srgb,var(--accent-2) 10%,transparent))}.picker__list strong,.picker__list small{display:block}.picker__list small{margin-top:3px;color:var(--muted);font-size:10px}.picker>footer{display:flex;gap:16px;padding:10px 15px;border-top:1px solid var(--border);color:var(--muted);font-size:9px}@keyframes picker-in{from{opacity:0;transform:translateY(-8px) scale(.985)}} .rail{grid-row:2;grid-column:1;padding:12px 7px}.rail__brand{display:none}.rail__item{width:42px;height:42px} .workspace{grid-row:2;grid-column:2;padding:0;overflow:hidden;display:grid;grid-template-rows:58px minmax(0,1fr)} .workspace__header{position:relative;min-height:58px;padding:8px 18px;border-bottom:1px solid var(--border);background:color-mix(in srgb,var(--surface) 58%,transparent)}.workspace__header h1{font-size:17px}.workspace__header .eyebrow{font-size:8px;margin-bottom:2px}.header-actions select{min-width:105px} -.code-layout{height:auto;min-height:0;display:grid;grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), 42vw)) minmax(0,1fr);gap:0} +.code-layout{height:auto;min-height:0;display:grid;grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), calc(42 * var(--vw)))) minmax(0,1fr);gap:0} .tree{height:100%;min-width:0;overflow:auto;padding:0 10px 16px;border-right:1px solid var(--border);border-radius:0;background:linear-gradient(180deg,color-mix(in srgb,var(--surface-2) 74%,transparent),color-mix(in srgb,var(--surface) 70%,transparent));box-shadow:5px 0 calc(26px * var(--glow-size)) color-mix(in srgb,var(--accent) 6%,transparent)} .tree__title{position:sticky;top:0;z-index:2;display:flex;align-items:center;justify-content:space-between;margin:0 -10px 8px;padding:12px 14px 10px;border-bottom:1px solid var(--border);color:var(--muted);background:color-mix(in srgb,var(--surface) 90%,transparent);backdrop-filter:blur(15px);font-size:10px;text-transform:uppercase;letter-spacing:.12em}.tree__title small{font:9px var(--mono)} .reader{height:100%;overflow:auto;border:0;border-radius:0;background:color-mix(in srgb,var(--page) 76%,var(--surface));box-shadow:none}.reader__head{padding:13px 22px}.document.markdown{max-width:1040px;padding:40px 54px 90px}.document.code{min-height:100%} -.history,.tools{height:calc(100vh - 116px);max-width:none;margin:0;border:0;border-radius:0;overflow:auto;box-shadow:none;background:transparent}.history{padding:24px 34px}.tools{padding:24px 30px}.empty{margin:auto;align-self:center} -@media(max-width:900px){.titlebar{grid-template-columns:auto 1fr}.titlebar__platform{display:none}.repo-picker{justify-self:stretch}.code-layout{grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), 32vw)) minmax(0,1fr)}} +.history,.tools{height:calc(calc(100 * var(--vh)) - 116px);max-width:none;margin:0;border:0;border-radius:0;overflow:auto;box-shadow:none;background:transparent}.history{padding:24px 34px}.tools{padding:24px 30px}.empty{margin:auto;align-self:center} +@media(max-width:900px){.titlebar{grid-template-columns:auto 1fr}.titlebar__platform{display:none}.repo-picker{justify-self:stretch}.code-layout{grid-template-columns:minmax(220px,min(var(--tree-pane-width, 300px), calc(32 * var(--vw)))) minmax(0,1fr)}} .code-layout--chat{grid-template-columns:270px minmax(360px,1fr) minmax(300px,380px)}.chat-button{color:var(--accent-2);border-color:color-mix(in srgb,var(--accent-2) 38%,transparent)}.chat-drawer{height:100%;min-width:0;display:grid;grid-template-rows:auto auto minmax(0,1fr) auto;border-left:1px solid var(--border);background:linear-gradient(160deg,color-mix(in srgb,var(--surface-2) 94%,transparent),color-mix(in srgb,var(--surface) 96%,transparent));box-shadow:-8px 0 calc(30px * var(--glow-size)) rgba(0,0,0,.24),-3px 0 calc(24px * var(--glow-size)) color-mix(in srgb,var(--accent-2) 8%,transparent)}.chat-drawer>header{display:flex;align-items:center;justify-content:space-between;padding:15px 16px;border-bottom:1px solid var(--border)}.chat-drawer h2{margin:0;font-size:15px}.chat-drawer>header button{width:28px;height:28px;border:1px solid var(--border);border-radius:8px;color:var(--muted);background:transparent}.chat-context{display:flex;gap:6px;padding:9px 12px;border-bottom:1px solid var(--border);overflow:hidden}.chat-context span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:4px 7px;border-radius:6px;color:var(--muted);background:color-mix(in srgb,var(--accent) 8%,transparent);font:9px var(--mono)}.chat-messages{overflow:auto;padding:14px;display:grid;align-content:start;gap:12px}.chat-message{padding:11px 12px;border:1px solid var(--border);border-radius:12px;background:color-mix(in srgb,var(--surface-3) 36%,transparent)}.chat-message--user{margin-left:28px;border-color:color-mix(in srgb,var(--accent) 35%,transparent);background:color-mix(in srgb,var(--accent) 10%,transparent)}.chat-message small{color:var(--accent-2);font-size:9px;text-transform:uppercase;letter-spacing:.1em}.chat-message p{margin:6px 0 0;white-space:pre-wrap;overflow-wrap:anywhere;color:color-mix(in srgb,var(--text) 91%,var(--muted));font-size:11px;line-height:1.6}.chat-empty{align-self:center;padding:25px;text-align:center;color:var(--muted);font-size:11px;line-height:1.55}.chat-empty span{color:var(--accent-2);font-size:28px;filter:drop-shadow(0 0 10px var(--accent))}.chat-drawer>footer{display:grid;gap:8px;padding:11px;border-top:1px solid var(--border);background:color-mix(in srgb,var(--page) 50%,transparent)}.chat-drawer>footer>div{display:flex;gap:6px}.chat-drawer select{width:auto;padding:6px 24px 6px 8px;font-size:10px}.chat-drawer textarea{resize:none;width:100%;padding:10px;color:var(--text);border:1px solid var(--border);border-radius:10px;background:var(--page);font:11px/1.5 var(--mono)} /* Abduction identity and animated encounter system. */ @@ -71,17 +71,17 @@ button:focus-visible,input:focus-visible,select:focus-visible { outline:0; borde .splash-craft{position:absolute;z-index:4;left:50%;top:16%;width:230px;height:80px;transform:translateX(-50%);animation:craft-arrive 1s cubic-bezier(.18,.8,.2,1) both}.splash-craft>span{position:absolute;left:65px;top:5px;width:100px;height:48px;border:2px solid #77e9ff;border-radius:70px 70px 18px 18px;background:radial-gradient(circle at 50% 85%,rgba(94,236,255,.5),rgba(89,77,191,.35) 50%,#101738);box-shadow:inset 0 0 18px rgba(79,222,255,.35)}.splash-craft>i{position:absolute;left:12px;top:39px;width:206px;height:29px;border-radius:50%;background:linear-gradient(#8499c4,#182343 43%,#080d22 70%);border:2px solid #63dffc;box-shadow:0 4px 20px rgba(50,214,255,.65)}.splash-craft>b{position:absolute;left:47px;top:56px;width:136px;height:17px;border-radius:0 0 70% 70%;background:#090f2b}.splash-craft>em{position:absolute;left:52px;top:53px;width:9px;height:9px;border-radius:50%;background:#b4ff5e;box-shadow:0 0 12px #75ff6e}.splash-craft>em:last-child{left:169px} .tractor-beam{position:absolute;z-index:2;left:50%;top:23%;width:290px;height:61%;transform:translateX(-50%) scaleY(0);transform-origin:top;clip-path:polygon(40% 0,60% 0,100% 100%,0 100%);background:linear-gradient(90deg,transparent,rgba(109,246,255,.12) 22%,rgba(174,255,154,.35) 50%,rgba(109,246,255,.12) 78%,transparent);filter:drop-shadow(0 0 18px rgba(104,241,255,.4));animation:beam-on .5s .75s ease-out forwards} .abductee{position:absolute;z-index:3;left:50%;bottom:17%;transform:translateX(-50%);animation:abduct 1.5s 1.1s cubic-bezier(.5,0,.65,1) forwards}.abductee--code{display:flex;gap:14px;color:#baff8e;font:700 18px var(--mono);text-shadow:0 0 9px #48ffb5}.abductee--code code:nth-child(2){transform:translateY(8px)}.abductee--cow{width:94px;height:56px}.cow__body{position:absolute;left:6px;top:10px;width:61px;height:29px;border-radius:45% 45% 35% 30%;background:#d8d8da;box-shadow:inset 15px 3px #283044}.cow__head{position:absolute;right:5px;top:16px;width:27px;height:23px;border-radius:42%;background:#d8d8da}.abductee--cow i{position:absolute;left:18px;top:35px;width:5px;height:22px;background:#c7cad1}.abductee--cow i:nth-of-type(2){left:53px}.abductee--cow b{position:absolute;right:3px;top:13px;width:12px;height:3px;background:#c7cad1;transform:rotate(25deg)}.abductee--cow b:last-child{top:33px}.abductee--person{width:54px;height:86px}.person__head{position:absolute;left:18px;width:19px;height:19px;border-radius:50%;background:#10172a}.person__body{position:absolute;left:15px;top:17px;width:25px;height:42px;border-radius:12px 12px 5px 5px;background:#111a31}.abductee--person i,.abductee--person b{position:absolute;top:24px;width:6px;height:38px;border-radius:6px;background:#111a31;transform-origin:top}.abductee--person i{left:11px;transform:rotate(24deg)}.abductee--person i:nth-of-type(2){right:10px;transform:rotate(-24deg)}.abductee--person b{top:54px;left:17px;transform:rotate(9deg)}.abductee--person b:last-child{left:31px;transform:rotate(-9deg)} -.splash--abduction .splash__identity{z-index:6;align-self:end;margin-bottom:5vh;animation:identity-reveal .8s 2.05s cubic-bezier(.2,.8,.2,1) forwards}.splash--abduction .splash__identity>.alien-glyph{width:58px;height:58px}.splash--abduction .splash__identity h1{margin:8px 0 4px;font-size:38px;letter-spacing:.16em;text-transform:uppercase}.splash--abduction .splash__identity span{margin-top:7px;color:#657397;font:8px var(--mono);letter-spacing:.14em;text-transform:uppercase} +.splash--abduction .splash__identity{z-index:6;align-self:end;margin-bottom:calc(5 * var(--vh));animation:identity-reveal .8s 2.05s cubic-bezier(.2,.8,.2,1) forwards}.splash--abduction .splash__identity>.alien-glyph{width:58px;height:58px}.splash--abduction .splash__identity h1{margin:8px 0 4px;font-size:38px;letter-spacing:.16em;text-transform:uppercase}.splash--abduction .splash__identity span{margin-top:7px;color:#657397;font:8px var(--mono);letter-spacing:.14em;text-transform:uppercase} .ufo-loader{display:grid;place-items:center;gap:10px;color:var(--muted);font:10px var(--mono);letter-spacing:.08em}.ufo-loader__craft{position:relative;display:block;width:52px;height:34px;animation:ufo-spin 1.15s linear infinite;filter:drop-shadow(0 0 8px var(--cyan))}.ufo-loader__craft:before{content:"";position:absolute;left:15px;top:1px;width:22px;height:16px;border:1px solid var(--cyan);border-radius:20px 20px 4px 4px;background:color-mix(in srgb,var(--accent) 28%,var(--surface))}.ufo-loader__craft:after{content:"";position:absolute;left:3px;top:14px;width:46px;height:13px;border-radius:50%;background:linear-gradient(var(--cyan),var(--accent));box-shadow:0 7px 12px color-mix(in srgb,var(--cyan) 36%,transparent)}.ufo-loader__craft i,.ufo-loader__craft b{position:absolute;z-index:2;top:18px;width:4px;height:4px;border-radius:50%;background:#c5ff80}.ufo-loader__craft i{left:13px}.ufo-loader__craft b{right:13px}.reader__loading{gap:13px;text-transform:lowercase}.reader__loading:before{content:"";width:52px;height:34px;background:linear-gradient(transparent 0 38%,var(--cyan) 40% 55%,var(--accent) 57% 76%,transparent 78%);clip-path:polygon(38% 0,62% 0,72% 38%,94% 55%,78% 78%,58% 82%,68% 100%,32% 100%,42% 82%,22% 78%,6% 55%,28% 38%);filter:drop-shadow(0 0 7px var(--cyan));animation:ufo-spin 1.15s linear infinite} @keyframes craft-arrive{from{opacity:0;transform:translate(-140%,-80%) rotate(-9deg)}to{opacity:1;transform:translateX(-50%)}}@keyframes beam-on{to{transform:translateX(-50%) scaleY(1)}}@keyframes abduct{0%{transform:translateX(-50%) translateY(0) rotate(0)}65%{opacity:1}100%{opacity:0;transform:translateX(-50%) translateY(-310px) rotate(12deg) scale(.55)}}@keyframes star-pulse{to{opacity:.25}}@keyframes ufo-spin{0%{transform:perspective(90px) rotateY(0) rotate(-4deg)}50%{transform:perspective(90px) rotateY(180deg) rotate(4deg)}100%{transform:perspective(90px) rotateY(360deg) rotate(-4deg)}} @media(prefers-reduced-motion:reduce){.abductee{opacity:0}.tractor-beam{transform:translateX(-50%) scaleY(1)}.splash-craft{transform:translateX(-50%)}.ufo-loader__craft,.reader__loading:before{animation:none}} /* ASCII encounter: crisp terminal art with restrained pixel stepping. */ -.splash--ascii{display:block;background:#02050d;color:#9ef8ff;font-family:var(--mono);image-rendering:pixelated;text-shadow:0 0 7px rgba(70,232,255,.55);isolation:isolate}.splash--ascii:before{content:"";position:absolute;inset:0;z-index:8;pointer-events:none;background:repeating-linear-gradient(0deg,rgba(255,255,255,.022) 0,rgba(255,255,255,.022) 1px,transparent 1px,transparent 4px);mix-blend-mode:screen}.splash--ascii:after{content:"";position:absolute;inset:0;box-shadow:inset 0 0 120px #000;pointer-events:none;z-index:7}.ascii-stars{position:absolute;inset:7% 6% auto;white-space:pre;font:clamp(12px,1.4vw,19px)/4 var(--mono);letter-spacing:clamp(8px,1.5vw,22px);color:#6fc7d3;opacity:.72;animation:ascii-flicker 1.2s steps(2,end) infinite}.ascii-moon{position:absolute;right:10%;top:10%;margin:0;color:#c7edee;font:clamp(13px,1.7vw,24px)/.8 var(--mono);letter-spacing:-.12em;filter:drop-shadow(0 0 13px rgba(169,238,255,.45))}.ascii-craft{position:absolute;z-index:4;left:50%;top:11%;margin:0;transform:translateX(-50%);color:#b8fbff;font:700 clamp(10px,1.35vw,18px)/1.05 var(--mono);letter-spacing:0;white-space:pre;text-align:center;filter:drop-shadow(0 0 8px #2ad9ff);animation:ascii-craft-in .8s steps(8,end) both}.ascii-beam{position:absolute;z-index:2;left:50%;top:29%;width:min(32vw,330px);height:51%;display:grid;grid-template-columns:repeat(4,1fr);justify-items:center;overflow:hidden;transform:translateX(-50%);clip-path:polygon(34% 0,66% 0,100% 100%,0 100%);color:rgba(137,255,209,.24);background:repeating-linear-gradient(90deg,transparent 0 12px,rgba(69,236,221,.025) 12px 15px);font:clamp(8px,1vw,13px)/1 var(--mono);animation:ascii-beam-in .45s .65s steps(5,end) both}.ascii-beam span{writing-mode:vertical-rl;letter-spacing:12px;animation:ascii-stream .65s steps(4,end) infinite}.ascii-beam span:nth-child(even){animation-delay:-.3s;color:rgba(102,222,255,.3)}.ascii-target{position:absolute;z-index:3;left:50%;bottom:19%;margin:0;transform:translateX(-50%);white-space:pre;text-align:center;color:#ceff8d;font:700 clamp(12px,1.5vw,20px)/1.05 var(--mono);filter:drop-shadow(0 0 5px #7aff96);animation:ascii-abduct 1.45s 1.05s steps(15,end) forwards}.ascii-target--cow{color:#e8f2df}.ascii-target--person{color:#a8e9ff}.ascii-woods{position:absolute;z-index:1;left:50%;bottom:0;width:110%;margin:0;transform:translateX(-50%) scaleX(1.25);overflow:hidden;white-space:pre;text-align:center;color:#183e43;font:700 clamp(13px,2vw,27px)/.88 var(--mono);letter-spacing:.08em;text-shadow:0 -4px 12px rgba(44,135,127,.28)}.splash--ascii .splash__identity{position:absolute;z-index:6;left:50%;bottom:4.5%;transform:translateX(-50%);width:100%;animation:ascii-title-in .55s 2.08s steps(7,end) forwards}.splash--ascii .splash__identity h1{margin:0 0 7px;color:#d9ffff;background:none;-webkit-text-fill-color:initial;font:800 clamp(23px,3vw,42px)/1 var(--mono);letter-spacing:.14em;text-shadow:3px 0 #5c46aa,-3px 0 #1bcad3,0 0 17px rgba(80,237,255,.58)}.splash--ascii .splash__identity p{color:#8cc9c6;font:10px var(--mono);letter-spacing:.22em}.splash--ascii .splash__identity span{margin-top:8px;color:#607d88;font:9px var(--mono);letter-spacing:.08em;text-transform:none;animation:cursor-blink .65s steps(1,end) infinite} +.splash--ascii{display:block;background:#02050d;color:#9ef8ff;font-family:var(--mono);image-rendering:pixelated;text-shadow:0 0 7px rgba(70,232,255,.55);isolation:isolate}.splash--ascii:before{content:"";position:absolute;inset:0;z-index:8;pointer-events:none;background:repeating-linear-gradient(0deg,rgba(255,255,255,.022) 0,rgba(255,255,255,.022) 1px,transparent 1px,transparent 4px);mix-blend-mode:screen}.splash--ascii:after{content:"";position:absolute;inset:0;box-shadow:inset 0 0 120px #000;pointer-events:none;z-index:7}.ascii-stars{position:absolute;inset:7% 6% auto;white-space:pre;font:clamp(12px,calc(1.4 * var(--vw)),19px)/4 var(--mono);letter-spacing:clamp(8px,calc(1.5 * var(--vw)),22px);color:#6fc7d3;opacity:.72;animation:ascii-flicker 1.2s steps(2,end) infinite}.ascii-moon{position:absolute;right:10%;top:10%;margin:0;color:#c7edee;font:clamp(13px,calc(1.7 * var(--vw)),24px)/.8 var(--mono);letter-spacing:-.12em;filter:drop-shadow(0 0 13px rgba(169,238,255,.45))}.ascii-craft{position:absolute;z-index:4;left:50%;top:11%;margin:0;transform:translateX(-50%);color:#b8fbff;font:700 clamp(10px,calc(1.35 * var(--vw)),18px)/1.05 var(--mono);letter-spacing:0;white-space:pre;text-align:center;filter:drop-shadow(0 0 8px #2ad9ff);animation:ascii-craft-in .8s steps(8,end) both}.ascii-beam{position:absolute;z-index:2;left:50%;top:29%;width:min(calc(32 * var(--vw)),330px);height:51%;display:grid;grid-template-columns:repeat(4,1fr);justify-items:center;overflow:hidden;transform:translateX(-50%);clip-path:polygon(34% 0,66% 0,100% 100%,0 100%);color:rgba(137,255,209,.24);background:repeating-linear-gradient(90deg,transparent 0 12px,rgba(69,236,221,.025) 12px 15px);font:clamp(8px,calc(1 * var(--vw)),13px)/1 var(--mono);animation:ascii-beam-in .45s .65s steps(5,end) both}.ascii-beam span{writing-mode:vertical-rl;letter-spacing:12px;animation:ascii-stream .65s steps(4,end) infinite}.ascii-beam span:nth-child(even){animation-delay:-.3s;color:rgba(102,222,255,.3)}.ascii-target{position:absolute;z-index:3;left:50%;bottom:19%;margin:0;transform:translateX(-50%);white-space:pre;text-align:center;color:#ceff8d;font:700 clamp(12px,calc(1.5 * var(--vw)),20px)/1.05 var(--mono);filter:drop-shadow(0 0 5px #7aff96);animation:ascii-abduct 1.45s 1.05s steps(15,end) forwards}.ascii-target--cow{color:#e8f2df}.ascii-target--person{color:#a8e9ff}.ascii-woods{position:absolute;z-index:1;left:50%;bottom:0;width:110%;margin:0;transform:translateX(-50%) scaleX(1.25);overflow:hidden;white-space:pre;text-align:center;color:#183e43;font:700 clamp(13px,calc(2 * var(--vw)),27px)/.88 var(--mono);letter-spacing:.08em;text-shadow:0 -4px 12px rgba(44,135,127,.28)}.splash--ascii .splash__identity{position:absolute;z-index:6;left:50%;bottom:4.5%;transform:translateX(-50%);width:100%;animation:ascii-title-in .55s 2.08s steps(7,end) forwards}.splash--ascii .splash__identity h1{margin:0 0 7px;color:#d9ffff;background:none;-webkit-text-fill-color:initial;font:800 clamp(23px,calc(3 * var(--vw)),42px)/1 var(--mono);letter-spacing:.14em;text-shadow:3px 0 #5c46aa,-3px 0 #1bcad3,0 0 17px rgba(80,237,255,.58)}.splash--ascii .splash__identity p{color:#8cc9c6;font:10px var(--mono);letter-spacing:.22em}.splash--ascii .splash__identity span{margin-top:8px;color:#607d88;font:9px var(--mono);letter-spacing:.08em;text-transform:none;animation:cursor-blink .65s steps(1,end) infinite} @keyframes ascii-craft-in{from{opacity:0;transform:translate(-80%,-80px)}to{opacity:1;transform:translateX(-50%)}}@keyframes ascii-beam-in{from{opacity:0;height:0}to{opacity:1;height:51%}}@keyframes ascii-stream{to{transform:translateY(24px)}}@keyframes ascii-abduct{0%{transform:translateX(-50%)}70%{opacity:1}100%{opacity:0;transform:translate(-50%,-285px) scale(.62)}}@keyframes ascii-title-in{from{opacity:0;clip-path:inset(0 50%)}to{opacity:1;clip-path:inset(0)}}@keyframes ascii-flicker{50%{opacity:.42}}@keyframes cursor-blink{50%{opacity:.45}} @media(prefers-reduced-motion:reduce){.ascii-craft{animation:none}.ascii-target{opacity:0}.ascii-beam{height:51%;animation:none}.ascii-stars,.ascii-beam span,.splash--ascii .splash__identity span{animation:none}.splash--ascii .splash__identity{opacity:1;clip-path:none}} /* Richer classic-saucer pass: soft atmosphere around deliberately simple ASCII. */ -.splash--ascii{background:radial-gradient(ellipse at 50% 35%,#101b38 0,#050a19 45%,#010309 82%);text-shadow:0 0 7px rgba(70,232,255,.48)}.ascii-aurora{position:absolute;inset:-18% -10% 35%;opacity:.28;background:radial-gradient(ellipse at 34% 40%,rgba(64,255,177,.24),transparent 38%),radial-gradient(ellipse at 68% 22%,rgba(91,89,255,.3),transparent 42%);filter:blur(42px);transform:skewY(-5deg);animation:aurora-drift 5s ease-in-out infinite alternate}.ascii-stars{inset:4% 4% auto;font-size:clamp(11px,1.25vw,17px);line-height:3.35;letter-spacing:clamp(7px,1.25vw,18px);color:#8ddbe1;opacity:.8}.ascii-moon{right:8%;top:8%;color:#d4ecdf;font-size:clamp(10px,1.25vw,18px);line-height:.92;letter-spacing:0;text-shadow:0 0 6px #a9d9d3,0 0 28px rgba(181,227,218,.48)}.ascii-craft{top:9%;width:max-content;max-width:90vw;color:#d8feff;font-size:clamp(8px,1.18vw,16px);line-height:1.03;text-shadow:0 0 4px #83ecff,0 0 15px rgba(65,205,255,.6);filter:none;animation:classic-saucer-in .9s steps(10,end) both,classic-saucer-hover 3.2s .9s ease-in-out infinite}.ascii-craft:after{content:"";position:absolute;left:12%;right:12%;bottom:-10px;height:8px;border-radius:50%;background:rgba(117,242,255,.42);filter:blur(7px);box-shadow:0 0 25px rgba(133,255,192,.55)}.ascii-beam{top:28%;width:min(38vw,390px);height:56%;grid-template-columns:repeat(5,1fr);color:rgba(164,255,196,.2);background:repeating-linear-gradient(90deg,transparent 0 15px,rgba(94,251,213,.035) 15px 18px);filter:drop-shadow(0 0 16px rgba(102,255,213,.18))}.ascii-beam:after{content:"";position:absolute;inset:auto 9% 0;height:10px;border:1px dashed rgba(138,255,203,.32);border-radius:50%;box-shadow:0 0 22px rgba(107,255,194,.3);animation:landing-ring 1.1s steps(4,end) infinite}.ascii-target{bottom:17%;text-shadow:0 0 5px currentColor,0 0 14px rgba(130,255,175,.5)}.ascii-hills{position:absolute;z-index:0;left:50%;bottom:14%;width:120%;margin:0;transform:translateX(-50%) scaleX(1.15);overflow:hidden;color:#183549;font:clamp(9px,1.25vw,17px)/1 var(--mono);text-align:center;white-space:pre;text-shadow:0 -3px 12px rgba(42,107,153,.25)}.ascii-woods{z-index:1;width:115%;color:#204b42;font-size:clamp(10px,1.45vw,20px);line-height:.9;letter-spacing:.04em;text-shadow:0 -3px 9px rgba(67,158,113,.25)}.splash--ascii .splash__identity{bottom:3%;padding-top:8px;background:linear-gradient(transparent,rgba(1,3,9,.72) 30%)} +.splash--ascii{background:radial-gradient(ellipse at 50% 35%,#101b38 0,#050a19 45%,#010309 82%);text-shadow:0 0 7px rgba(70,232,255,.48)}.ascii-aurora{position:absolute;inset:-18% -10% 35%;opacity:.28;background:radial-gradient(ellipse at 34% 40%,rgba(64,255,177,.24),transparent 38%),radial-gradient(ellipse at 68% 22%,rgba(91,89,255,.3),transparent 42%);filter:blur(42px);transform:skewY(-5deg);animation:aurora-drift 5s ease-in-out infinite alternate}.ascii-stars{inset:4% 4% auto;font-size:clamp(11px,calc(1.25 * var(--vw)),17px);line-height:3.35;letter-spacing:clamp(7px,calc(1.25 * var(--vw)),18px);color:#8ddbe1;opacity:.8}.ascii-moon{right:8%;top:8%;color:#d4ecdf;font-size:clamp(10px,calc(1.25 * var(--vw)),18px);line-height:.92;letter-spacing:0;text-shadow:0 0 6px #a9d9d3,0 0 28px rgba(181,227,218,.48)}.ascii-craft{top:9%;width:max-content;max-width:calc(90 * var(--vw));color:#d8feff;font-size:clamp(8px,calc(1.18 * var(--vw)),16px);line-height:1.03;text-shadow:0 0 4px #83ecff,0 0 15px rgba(65,205,255,.6);filter:none;animation:classic-saucer-in .9s steps(10,end) both,classic-saucer-hover 3.2s .9s ease-in-out infinite}.ascii-craft:after{content:"";position:absolute;left:12%;right:12%;bottom:-10px;height:8px;border-radius:50%;background:rgba(117,242,255,.42);filter:blur(7px);box-shadow:0 0 25px rgba(133,255,192,.55)}.ascii-beam{top:28%;width:min(calc(38 * var(--vw)),390px);height:56%;grid-template-columns:repeat(5,1fr);color:rgba(164,255,196,.2);background:repeating-linear-gradient(90deg,transparent 0 15px,rgba(94,251,213,.035) 15px 18px);filter:drop-shadow(0 0 16px rgba(102,255,213,.18))}.ascii-beam:after{content:"";position:absolute;inset:auto 9% 0;height:10px;border:1px dashed rgba(138,255,203,.32);border-radius:50%;box-shadow:0 0 22px rgba(107,255,194,.3);animation:landing-ring 1.1s steps(4,end) infinite}.ascii-target{bottom:17%;text-shadow:0 0 5px currentColor,0 0 14px rgba(130,255,175,.5)}.ascii-hills{position:absolute;z-index:0;left:50%;bottom:14%;width:120%;margin:0;transform:translateX(-50%) scaleX(1.15);overflow:hidden;color:#183549;font:clamp(9px,calc(1.25 * var(--vw)),17px)/1 var(--mono);text-align:center;white-space:pre;text-shadow:0 -3px 12px rgba(42,107,153,.25)}.ascii-woods{z-index:1;width:115%;color:#204b42;font-size:clamp(10px,calc(1.45 * var(--vw)),20px);line-height:.9;letter-spacing:.04em;text-shadow:0 -3px 9px rgba(67,158,113,.25)}.splash--ascii .splash__identity{bottom:3%;padding-top:8px;background:linear-gradient(transparent,rgba(1,3,9,.72) 30%)} @keyframes classic-saucer-in{from{opacity:0;transform:translate(-85%,-90px) scale(.78)}to{opacity:1;transform:translateX(-50%) scale(1)}}@keyframes classic-saucer-hover{0%,100%{transform:translate(-50%,0)}50%{transform:translate(-50%,5px)}}@keyframes aurora-drift{to{opacity:.42;transform:translateX(4%) skewY(-2deg)}}@keyframes landing-ring{50%{opacity:.45;transform:scaleX(.88)}} @media(prefers-reduced-motion:reduce){.ascii-craft,.ascii-aurora,.ascii-beam:after{animation:none}.ascii-craft{transform:translateX(-50%)}} diff --git a/frontend/src/viewport.ts b/frontend/src/viewport.ts new file mode 100644 index 0000000..905f5c4 --- /dev/null +++ b/frontend/src/viewport.ts @@ -0,0 +1,10 @@ +// updateViewportUnits recomputes --vh/--vw as 1% of the true viewport divided +// by the active --scale, so viewport-unit CSS keeps its real-world proportions +// under the whole-app scale transform on .shell instead of measuring against +// the unscaled window. +export function updateViewportUnits() { + const root = document.documentElement; + const scale = Number(getComputedStyle(root).getPropertyValue("--scale")) || 1; + root.style.setProperty("--vh", `${window.innerHeight / 100 / scale}px`); + root.style.setProperty("--vw", `${window.innerWidth / 100 / scale}px`); +} From 06c8fd4bdb416b15517d9f683b5d6d5a8580dd9e Mon Sep 17 00:00:00 2001 From: billy slade Date: Thu, 3 Sep 2026 14:43:29 +0100 Subject: [PATCH 2/2] fix: restore and extend the Open editor GUI-launch fix PR #14 merged an outdated commit of its own branch, so the ExecutablePath-based fix for Open editor never actually reached main even though it shipped in v0.1.15's changelog and its own PR. Restores it, and adds a macOS fallback: when the configured editor's CLI binary can't be found anywhere (for example "code" with the VS Code shell command never installed), launch the application directly with `open -a`, forwarding any extra configured flags via --args. --- CHANGELOG.md | 5 ++++ backend/repository_git.go | 42 +++++++++++++++++++++++++-- backend/repository_test.go | 59 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9283be..365df20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to Abduction are documented here. This project follows ## [Unreleased] +### Fixed + +- Made the Text & UI scale control resize viewport-relative layout (modals, panes, splash) consistently with everything else, instead of leaving it measured against the real, unscaled window. +- Restored the Open editor executable-path fix that a prior merge silently dropped, and added a macOS fallback that launches the editor's application directly (via `open -a`) when its CLI shim was never added to PATH. + ## [0.1.16] - 2026-09-03 ### Added diff --git a/backend/repository_git.go b/backend/repository_git.go index 59f8bb2..b2ff3a9 100644 --- a/backend/repository_git.go +++ b/backend/repository_git.go @@ -328,6 +328,21 @@ func (service *RepositoryService) Fingerprint(repositoryPath string) (string, er return fmt.Sprintf("%x", fingerprint.Sum(nil)), nil } +// macEditorApplications maps common editor CLI commands to the macOS +// application `open -a` can launch when the CLI shim was never installed +// into PATH (for example, VS Code's "Shell Command: Install 'code' command" +// was never run). +var macEditorApplications = map[string]string{ + "code": "Visual Studio Code", + "code-insiders": "Visual Studio Code - Insiders", + "cursor": "Cursor", + "subl": "Sublime Text", + "zed": "Zed", + "webstorm": "WebStorm", + "idea": "IntelliJ IDEA", + "atom": "Atom", +} + // OpenInEditor starts the configured editor without blocking Abduction. func (service *RepositoryService) OpenInEditor(repositoryPath string, relativePath string) error { targetPath, pathError := SafeRepositoryPath(repositoryPath, relativePath) @@ -338,8 +353,31 @@ func (service *RepositoryService) OpenInEditor(repositoryPath string, relativePa if len(editorParts) == 0 { return errors.New("no editor configured") } - commandArguments := append(editorParts[1:], targetPath) - return exec.Command(editorParts[0], commandArguments...).Start() + if editorBinary, lookupError := ExecutablePath(editorParts[0]); lookupError == nil { + commandArguments := append(editorParts[1:], targetPath) + return exec.Command(editorBinary, commandArguments...).Start() + } + if runtime.GOOS == "darwin" { + if arguments, known := macEditorLaunchArguments(editorParts, targetPath); known { + return exec.Command("open", arguments...).Start() + } + } + return fmt.Errorf("editor %q not found", editorParts[0]) +} + +// macEditorLaunchArguments builds the `open` argument vector that launches a +// known editor application directly when its CLI shim is not on PATH. +func macEditorLaunchArguments(editorParts []string, targetPath string) ([]string, bool) { + applicationName, known := macEditorApplications[editorParts[0]] + if !known { + return nil, false + } + arguments := []string{"-a", applicationName, targetPath} + if len(editorParts) > 1 { + arguments = append(arguments, "--args") + arguments = append(arguments, editorParts[1:]...) + } + return arguments, true } // SafeRepositoryPath resolves a path and proves that it remains inside its repository. diff --git a/backend/repository_test.go b/backend/repository_test.go index 3ef0eaf..ddfa052 100644 --- a/backend/repository_test.go +++ b/backend/repository_test.go @@ -7,6 +7,7 @@ import ( "reflect" "strings" "testing" + "time" ) // TestSafeRepositoryPathRejectsTraversal protects the desktop filesystem boundary. @@ -93,6 +94,64 @@ func TestRunGitSurvivesAnEmptyPATH(testingContext *testing.T) { } } +// TestOpenInEditorUsesExecutablePathFallbacks protects macOS GUI launches from +// silently failing to open an editor installed outside the minimal launch PATH. +func TestOpenInEditorUsesExecutablePathFallbacks(testingContext *testing.T) { + home := testingContext.TempDir() + localBin := filepath.Join(home, ".local", "bin") + if makeError := os.MkdirAll(localBin, 0o755); makeError != nil { + testingContext.Fatal(makeError) + } + repositoryPath := testingContext.TempDir() + markerPath := filepath.Join(repositoryPath, "editor-opened") + editorStub := filepath.Join(localBin, "stub-editor") + script := "#!/bin/sh\necho \"$@\" > " + markerPath + "\n" + if writeError := os.WriteFile(editorStub, []byte(script), 0o755); writeError != nil { + testingContext.Fatal(writeError) + } + testingContext.Setenv("HOME", home) + testingContext.Setenv("PATH", "") + service := NewRepositoryService(Config{Editor: "stub-editor"}) + if openError := service.OpenInEditor(repositoryPath, ""); openError != nil { + testingContext.Fatalf("expected the editor to resolve via ~/.local/bin despite an empty PATH, received: %v", openError) + } + deadline := time.Now().Add(2 * time.Second) + for time.Now().Before(deadline) { + if _, statError := os.Stat(markerPath); statError == nil { + return + } + time.Sleep(20 * time.Millisecond) + } + testingContext.Fatal("expected the stub editor to run and record its arguments") +} + +// TestMacEditorLaunchArgumentsResolvesKnownApplications protects editors that +// were installed without their optional CLI shim on PATH. +func TestMacEditorLaunchArgumentsResolvesKnownApplications(testingContext *testing.T) { + arguments, known := macEditorLaunchArguments([]string{"code"}, "/tmp/example") + if !known { + testingContext.Fatal("expected \"code\" to resolve to a known macOS application") + } + if !reflect.DeepEqual(arguments, []string{"-a", "Visual Studio Code", "/tmp/example"}) { + testingContext.Fatalf("unexpected open arguments: %#v", arguments) + } + if _, known := macEditorLaunchArguments([]string{"some-unknown-editor"}, "/tmp/example"); known { + testingContext.Fatal("expected an unrecognised editor command to report unknown") + } +} + +// TestMacEditorLaunchArgumentsForwardsExtraFlags keeps configured editor +// flags working when Abduction has to fall back to launching the application. +func TestMacEditorLaunchArgumentsForwardsExtraFlags(testingContext *testing.T) { + arguments, known := macEditorLaunchArguments([]string{"code", "--new-window"}, "/tmp/example") + if !known { + testingContext.Fatal("expected \"code\" to resolve to a known macOS application") + } + if !reflect.DeepEqual(arguments, []string{"-a", "Visual Studio Code", "/tmp/example", "--args", "--new-window"}) { + testingContext.Fatalf("unexpected open arguments: %#v", arguments) + } +} + // TestRepositoryFingerprintChangesWithWorkingTree protects live UI refreshes. func TestRepositoryFingerprintChangesWithWorkingTree(testingContext *testing.T) { repositoryPath := testingContext.TempDir()