Compare commits

...
3 Commits
Author SHA1 Message Date
Christoph 95c72340fe feat(ui): add consistent page-header layout and styles
publish / Build and publish Ubuntu AppImage (release) Successful in 9m27s
publish / Build and publish Windows installer (release) Successful in 10m56s
publish / Build and publish AUR packages (release) Successful in 19m46s
Introduce a shared page-header/page-heading pattern and CSS to
standardize headers across top-level sections. Components were
updated to adopt the new classes and slightly smaller icon sizing
for a more compact, consistent header appearance. This improves
visual consistency and makes future header adjustments simpler.

- Add reusable page-header styles for spacing, borders, and bg
- Standardize icon sizing and heading layout across screens
2026-09-09 09:24:18 +02:00
Christoph abbd737a8d feat(ui): refine integration board view and compact assignees
Refactor the integration board UI to improve board discovery, loading,
and the card detail experience. Introduce a compact assignee mode and
apply it in list views to save horizontal space, and make several
accessibility and labeling improvements for board links and authors.

- Add a compact prop for assignee rendering and use it across lists.
- Improve board URL handling and add Azure DevOps board label parsing.
- Replace the old inspector with a focused detail drawer and sidebar.
2026-09-09 08:45:55 +02:00
Christoph bb53de3b83 Update version to 2026.9.4 2026-09-08 22:12:16 +02:00
10 changed files with 137 additions and 79 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "gitty",
"version": "2026.9.3",
"version": "2026.9.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gitty",
"version": "2026.9.3",
"version": "2026.9.4",
"dependencies": {
"@lucide/svelte": "^1.21.0",
"@tailwindcss/vite": "^4.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gitty",
"version": "2026.9.3",
"version": "2026.9.4",
"private": true,
"type": "module",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Gitty",
"version": "2026.9.3",
"version": "2026.9.4",
"identifier": "com.gitty",
"build": {
"beforeDevCommand": "npm run prepare:lfs && npm run dev",
+33
View File
@@ -9069,3 +9069,36 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
--color-sync-ahead: #9a5200;
--color-sync-behind: #0755c8;
}
/* Consistent page headers for repositories, pull requests, and issues. */
section > header.page-header.page-header {
box-sizing: border-box;
display: flex;
flex-shrink: 0;
min-height: 54px;
height: auto;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 8px 24px;
border-bottom: 1px solid var(--color-border-subtle);
background: color-mix(in srgb, var(--app-bg) 94%, var(--color-surface));
}
.page-header .page-heading {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
}
.page-header .page-heading > svg {
flex: 0 0 auto;
color: var(--color-accent);
}
.page-header.page-header .page-heading h1 {
margin: 0;
color: var(--color-ink);
font-size: 14px;
font-weight: 700;
line-height: 20px;
letter-spacing: normal;
}
+53 -30
View File
@@ -4,7 +4,7 @@
<script lang="ts">
import { onMount, onDestroy } from "svelte";
import { Columns3, ExternalLink, Link2, RefreshCw, Search, X } from "@lucide/svelte";
import { Columns3, ExternalLink, RefreshCw, Search, X } from "@lucide/svelte";
import SelectMenu from "./SelectMenu.svelte";
import IssueLabels from "./IssueLabels.svelte";
import IssueAssignees from "./IssueAssignees.svelte";
@@ -22,8 +22,6 @@
let discovering = false;
let discoveryWarnings: string[] = [];
let destroyed = false;
let connectOpen = true;
let boardUrl = "";
let activeUrl = "";
let board: IntegrationBoard | null = null;
let loading = false;
@@ -43,12 +41,8 @@
$: repositoryOptions = [{ value: "", label: de ? "Alle Repositories" : "All repositories" }, ...[...new Set(board?.columns.flatMap(column => column.cards.map(card => card.repository)).filter(Boolean) ?? [])].sort().map(value => ({ value, label: value }))];
$: columns = board?.columns.map(column => ({ ...column, cards: column.cards.filter(card => (!repositoryFilter || card.repository === repositoryFilter) &&
`${card.title} ${card.number} ${card.repository} ${card.labels.join(" ")} ${card.assignees.join(" ")} ${card.lane}`.toLocaleLowerCase().includes(normalizedQuery)) })) ?? [];
$: placeholder = source.provider === "github" ? "https://github.com/orgs/team/projects/1/views/1"
: source.provider.startsWith("gitlab") ? `${source.baseUrl}/group/project/-/boards/1`
: source.provider === "gitea" ? `${source.baseUrl}/owner/repo/projects/1`
: `${source.baseUrl}/Project/_boards/board/t/Team/Stories`;
onMount(() => {
let boardUrl = "";
try { boardUrl = localStorage.getItem(preferenceKey) ?? ""; } catch { /* Optional preference. */ }
try {
const saved: unknown = JSON.parse(localStorage.getItem(directoryKey) ?? "[]");
@@ -56,7 +50,7 @@
} catch { /* Invalid optional preference. */ }
if (boardUrl && validBoardUrl(boardUrl)) rememberBoard({ title: boardUrl, webUrl: boardUrl, scope: "" });
void discoverBoards();
if (boardUrl) { connectOpen = false; void loadBoard(boardUrl); }
if (boardUrl && validBoardUrl(boardUrl)) void loadBoard(boardUrl);
const timer = window.setInterval(() => { if (activeUrl && !loading && !moving) void loadBoard(activeUrl); }, 180_000);
return () => window.clearInterval(timer);
});
@@ -72,6 +66,26 @@
try { localStorage.setItem(directoryKey, JSON.stringify(savedBoards)); } catch { /* Optional preference. */ }
}
function boardLabel(item: IntegrationBoardReference): string {
if (source.provider === "azure-devops") {
try {
const path = new URL(item.webUrl).pathname.split("/").filter(Boolean).map(decodeURIComponent);
const index = path.indexOf("_boards");
if (index > 0 && path[index + 1] === "board" && path[index + 2] === "t") {
const project = path[index - 1];
const team = path[index + 3];
const name = path[index + 4];
if (team && name) {
// Use the stable URL names: loaded titles also contain project and team.
const defaultTeam = team === project || team === `${project} Team`;
return `${project}${defaultTeam ? "" : ` / ${team}`} · ${name}`;
}
}
} catch { /* Keep the original label for nonstandard board links. */ }
}
return `${item.scope ? `${item.scope} · ` : ""}${item.title}`;
}
function boardError(message: string) {
if (de && message.includes("publishes no Projects/Columns API")) return "Dieser Gitea-Server bietet keine Projects-/Columns-API an. Boards sind im Browser verfügbar, können aber mit dem API-Token weder automatisch gefunden noch importiert werden. Bitte das Original-Board öffnen.";
if (de && message.includes("Gitea returned 404")) return "Gitea meldet 404. Bitte Board-Link und Token-Zugriff prüfen. Möglicherweise unterstützt der Server die Projects-/Columns-API nicht.";
@@ -94,7 +108,7 @@
} finally { if (!destroyed) discovering = false; }
}
async function loadBoard(url: string, collapseEditor = false) {
async function loadBoard(url: string) {
if (moving) return;
const requestedUrl = url.trim();
if (!requestedUrl) return;
@@ -119,7 +133,6 @@
if (requestGeneration !== generation) return;
board = result;
rememberBoard({ title: result.title, webUrl: requestedUrl, scope: savedBoards.find(item => item.webUrl === requestedUrl)?.scope ?? "" });
if (collapseEditor && boardUrl.trim() === requestedUrl) connectOpen = false;
boardCache.set(`${preferenceKey}:${requestedUrl}`, result);
selected = selected ? result.columns.flatMap(column => column.cards).find(card => card.id === selected!.id) ?? null : null;
try { localStorage.setItem(preferenceKey, requestedUrl); } catch { /* Keep the board in memory. */ }
@@ -203,30 +216,23 @@
<section class="board-view" aria-label={de ? "Kanban-Board" : "Kanban board"}>
<div class="board-directory">
<SelectMenu class="board-select" value={activeUrl} options={[{ value: "", label: de ? "Board auswählen" : "Select board" }, ...savedBoards.map(item => ({ value: item.webUrl, label: `${item.scope ? `${item.scope} · ` : ""}${item.title}` }))]} ariaLabel={de ? "Board auswählen" : "Select board"} onChange={value => { if (value && !moving) { boardUrl = value; void loadBoard(value, true); } }} />
<SelectMenu class="board-select" value={activeUrl} options={[{ value: "", label: de ? "Board auswählen" : "Select board" }, ...savedBoards.map(item => ({ value: item.webUrl, label: boardLabel(item) }))]} ariaLabel={de ? "Board auswählen" : "Select board"} onChange={value => { if (value && !moving) { void loadBoard(value); } }} />
<button class="workspace-button" disabled={discovering} onclick={discoverBoards}><RefreshCw size={14} />{de ? "Boards suchen" : "Find boards"}</button>
<small aria-live="polite">{discovering ? (de ? "Boards werden im Hintergrund gesucht …" : "Finding boards in background …") : `${savedBoards.length} Boards`}</small>
{#if !board && boardUrl && validBoardUrl(boardUrl)}<button class="workspace-button" onclick={() => openOriginal(boardUrl)}><ExternalLink size={14} />{de ? "Original öffnen" : "Open original"}</button>{/if}
{#if !board && activeUrl && validBoardUrl(activeUrl)}<button class="workspace-button" onclick={() => openOriginal(activeUrl)}><ExternalLink size={14} />{de ? "Original öffnen" : "Open original"}</button>{/if}
</div>
{#if discoveryWarnings.length}<details class="board-discovery-notice" open={!savedBoards.length}><summary>{de ? "Hinweise zur Board-Suche" : "Board discovery notices"} ({discoveryWarnings.length})</summary>{#each discoveryWarnings as warning}<p>{warning}</p>{/each}</details>{/if}
{#if board}
<div class="board-header">
<div class="board-title"><h2>{board.title}</h2><small>{source.label} <span>·</span> {canMove ? (de ? "Karten zwischen Spalten verschieben" : "Move cards between columns") : (de ? "Lesende Ansicht" : "Read-only view")}{#if loading} <span>·</span> {de ? "Aktualisierung läuft …" : "Updating …"}{/if}</small></div>
<div class="board-title"><h2>{boardLabel({ title: board.title, webUrl: board.webUrl, scope: "" })}</h2><small>{source.label} <span>·</span> {canMove ? (de ? "Karten zwischen Spalten verschieben" : "Move cards between columns") : (de ? "Lesende Ansicht" : "Read-only view")}{#if loading} <span>·</span> {de ? "Aktualisierung läuft …" : "Updating …"}{/if}</small></div>
<div class="board-tools">
<SelectMenu class="repository-select" value={repositoryFilter} options={repositoryOptions} ariaLabel={de ? "Repository filtern" : "Filter repository"} onChange={value => { repositoryFilter = value; selected = null; }} />
<label class="workspace-search"><Search size={15} /><input bind:value={query} aria-label={de ? "Board durchsuchen" : "Search board"} placeholder={de ? "Karten suchen …" : "Search cards …"} /></label>
<button class="workspace-button" class:active={connectOpen} aria-expanded={connectOpen} onclick={() => { connectOpen = !connectOpen; }}><Link2 size={14} />{de ? "Board wechseln" : "Change board"}</button>
<button class="workspace-button icon-button" disabled={loading || moving} onclick={() => loadBoard(activeUrl)} aria-label={de ? "Board aktualisieren" : "Refresh board"}><RefreshCw size={15} /></button>
<button class="workspace-button" onclick={() => openOriginal(board!.webUrl)}><ExternalLink size={14} />{de ? "Original öffnen" : "Open original"}</button>
</div>
</div>
{/if}
{#if connectOpen || !board}
<form class="board-connect" onsubmit={event => { event.preventDefault(); void loadBoard(boardUrl, true); }}>
<label for="native-board-url">{de ? "Original-Board" : "Original board"}</label>
<div class="board-connect-fields"><input id="native-board-url" type="url" bind:value={boardUrl} {placeholder} required aria-label={de ? "Board-Link" : "Board URL"} /><button class="workspace-button" type="submit" disabled={moving || !boardUrl.trim()}>{de ? "Board übernehmen" : "Load board"}</button></div>
</form>
{/if}
{#if moveMessage}<p class="board-notice" role="status">{moveMessage}</p>{/if}
{#if error}<div class="workspace-notice error" role="alert">{error}{#if board}<p>{de ? "Der zuletzt geladene Stand bleibt sichtbar." : "The last loaded board remains visible."}</p>{/if}</div>{/if}
{#if board}
@@ -248,7 +254,7 @@
<strong>{card.title}</strong>
{#if card.lane}<span class="lane">{card.lane}</span>{/if}
<IssueLabels labels={card.labels} />
{#if card.assignees.length}<IssueAssignees names={card.assignees} />{/if}
{#if card.assignees.length}<IssueAssignees names={card.assignees} compact />{/if}
</button>
{:else}<p class="column-empty">{de ? "Keine Karten" : "No cards"}</p>{/each}
</div>
@@ -256,24 +262,41 @@
{:else}<p class="column-empty">{de ? "Dieses Board hat keine Spalten." : "This board has no columns."}</p>{/each}
</div>
{#if selected}
<aside class="issue-inspector board-inspector" aria-label={de ? "Kartendetails" : "Card details"}>
<div class="inspector-top"><span>{selected.repository} <span class="issue-number">{selected.number ? `#${selected.number}` : ""}</span></span><button class="workspace-button close-button" onclick={() => { selected = null; }} aria-label={de ? "Kartendetails schließen" : "Close card details"}><X size={16} /></button></div>
<h2>{selected.title}</h2>
{@const selectedColumn = board.columns.find(column => column.id === selectedColumnId)}
<aside class="issue-detail-drawer" aria-label={de ? "Kartendetails" : "Card details"}>
<header class="issue-detail-header">
<div><Columns3 size={17} /><strong>{source.label} · {de ? "Karte" : "Card"}</strong></div>
<div class="issue-detail-header-actions">
{#if selected.webUrl}<button class="workspace-button close-button" onclick={() => openOriginal(selected!.webUrl)} aria-label={de ? "Im Anbieter öffnen" : "Open in provider"}><ExternalLink size={16} /></button>{/if}
<button class="workspace-button close-button" onclick={() => { selected = null; }} aria-label={de ? "Kartendetails schließen" : "Close card details"}><X size={17} /></button>
</div>
</header>
<div class="issue-detail-body">
<div class="issue-detail-main">
<div class="issue-detail-title"><div>{#if selected.number}<span>#{selected.number}</span>{/if}<h2>{selected.title}</h2></div>
{#if selectedColumn}<div class="issue-detail-summary"><span class="issue-status" data-tone={issueTone(selectedColumn.title)}><span class="status-dot"></span>{selectedColumn.title}</span></div>{/if}
</div>
<section class="issue-detail-description"><h3>{de ? "Beschreibung" : "Description"}</h3><div class="description">{selected.description || (de ? "Weitere Details im Original-Board." : "More details in the original board.")}</div></section>
</div>
<div class="issue-detail-sidebar">
{#if selected.webUrl}<button class="workspace-button inspector-open" onclick={() => openOriginal(selected!.webUrl)}><ExternalLink size={14} />{de ? "Im Browser öffnen" : "Open in browser"}</button>{/if}
{#if canMove}
{@const currentColumn = board.columns.find(column => column.id === selectedColumnId && column.cards.some(card => card.id === selected?.id))}
{#if currentColumn?.moveTarget}
<div class="card-move-control"><small>{de ? "In Spalte verschieben" : "Move to column"}</small><SelectMenu value={currentColumn.id} options={board.columns.filter(column => column.moveTarget).map(column => ({ value: column.id, label: column.title }))} ariaLabel={de ? "Karte verschieben" : "Move card"} onChange={value => { if (selected && currentColumn) void moveCard(selected.id, currentColumn.id, value); }} /></div>
{/if}
{/if}
<div class="inspector-properties"><IssueAssignees names={selected.assignees} />{#if selected.lane}<span class="lane">{selected.lane}</span>{/if}</div>
{#if selected.labels.length}<div class="inspector-labels"><small>Labels</small><IssueLabels labels={selected.labels} /></div>{/if}
<div class="inspector-description"><h3>{de ? "Beschreibung" : "Description"}</h3><div class="description">{selected.description || (de ? "Weitere Details im Original-Board." : "More details in the original board.")}</div></div>
{#if selected.webUrl}<button class="workspace-button inspector-open" onclick={() => openOriginal(selected!.webUrl)}><ExternalLink size={14} />{de ? "Karte öffnen" : "Open card"}</button>{/if}
<section><h3>{de ? "Zugewiesen" : "Assignees"}</h3><IssueAssignees names={selected.assignees} /></section>
<section><h3>Labels</h3>{#if selected.labels.length}<IssueLabels labels={selected.labels} />{:else}<small>{de ? "Keine Labels" : "No labels"}</small>{/if}</section>
{#if selected.repository}<section><h3>Repository</h3><strong class="issue-detail-repo">{selected.repository}</strong></section>{/if}
{#if selected.lane}<section><h3>Swimlane</h3><span class="lane">{selected.lane}</span></section>{/if}
</div>
</div>
</aside>
{/if}
</div>
{:else}
<div class="workspace-empty"><span class="empty-symbol"><Columns3 size={26} /></span><h2>{loading ? (de ? "Board wird im Hintergrund geladen" : "Loading board in background") : (de ? "Dein vorhandenes Board übernehmen" : "Load your existing board")}</h2><p>{de ? "Wähle oben ein gefundenes Board aus oder füge einen Board-Link ein. Spalten und Karten werden aus der Integration gelesen; der Link wird für diese Integration gespeichert." : "Select a discovered board above or paste a board link. Columns and cards come from the integration; the link is saved for this integration."}</p>
<div class="workspace-empty"><span class="empty-symbol"><Columns3 size={26} /></span><h2>{loading ? (de ? "Board wird im Hintergrund geladen" : "Loading board in background") : (de ? "Dein vorhandenes Board übernehmen" : "Load your existing board")}</h2><p>{de ? "Boards werden automatisch aus der Integration gesucht. Wähle oben ein Board aus, um seine Spalten und Karten zu laden." : "Boards are discovered automatically from the integration. Select a board above to load its columns and cards."}</p>
{#if source.provider === "gitea"}<p>{de ? "Gitea benötigt eine Serverversion mit Projects-/Columns-API." : "Gitea requires a server version with the Projects/Columns API."}</p>{/if}
</div>
{/if}
+4 -2
View File
@@ -1,8 +1,10 @@
<script lang="ts">
export let names: string[] = [];
export let emptyLabel = "—";
export let compact = false;
$: initials = names[0]?.trim().split(/[\s._-]+/).filter(Boolean).slice(0, 2).map(part => part[0]).join("").toLocaleUpperCase() ?? "";
$: avatarText = compact && initials.length === 1 ? names[0]?.trim().slice(0, 2).toLocaleUpperCase() : initials;
</script>
<span class="issue-person" title={names.join(", ")}>
{#if names.length}<span class="issue-avatar" aria-hidden="true">{initials}</span><span class="person-name">{names[0]}{names.length > 1 ? ` +${names.length - 1}` : ""}</span>{:else}<span class="unassigned">{emptyLabel}</span>{/if}
<span class="issue-person" title={names.join(", ")} aria-label={names.length ? names.join(", ") : undefined}>
{#if names.length}<span class="issue-avatar" aria-hidden="true">{avatarText}</span>{#if !compact}<span class="person-name">{names[0]}{names.length > 1 ? ` +${names.length - 1}` : ""}</span>{/if}{:else}<span class="unassigned">{emptyLabel}</span>{/if}
</span>
+3 -3
View File
@@ -172,8 +172,8 @@
<svelte:window onkeydown={event => { if (event.key === "Escape" && selectedId) void closeDetails(); }} />
<section class="issue-center" aria-label="Issues">
<header class="workspace-heading">
<div class="workspace-title"><span class="workspace-symbol"><CircleDot size={21} strokeWidth={1.7} /></span><div><h1>Issues</h1><p>{de ? "Arbeit im Blick. Über alle Integrationen." : "Work in focus. Across your integrations."}</p></div></div>
<header class="workspace-heading page-header">
<div class="page-heading"><CircleDot size={17} /><h1>Issues</h1></div>
<button class="workspace-button" onclick={onOpenSettings} title={de ? "Integrationen konfigurieren" : "Configure integrations"}><Settings2 size={14} />{de ? "Integrationen" : "Integrations"}</button>
</header>
{#if !sources.length}
@@ -211,7 +211,7 @@
<button class="issue-row" class:selected={selectedId === issue.id} aria-pressed={selectedId === issue.id} onclick={event => { detailTrigger = event.currentTarget; selectedId = issue.id; actionError = ""; }}>
<span class="issue-identity"><span class="issue-number">#{issue.number}</span><span class="issue-text"><strong>{issue.title}</strong><small>{issue.repositoryName}</small><IssueLabels labels={issue.labels} /></span></span>
<span class="issue-status" data-tone={issueTone(issue.state)}><span class="status-dot"></span>{issueStateLabel(issue.state, de)}</span>
<IssueAssignees names={issue.assignees} />
<IssueAssignees names={issue.assignees} compact />
</button>
{/each}
{/if}
@@ -164,8 +164,8 @@
</script>
<section class="repo-dashboard" aria-label={de ? "Repository-Verwaltung" : "Repository management"}>
<header class="dashboard-header">
<h1>Repository Management</h1>
<header class="dashboard-header page-header">
<div class="page-heading"><FolderGit2 size={17} /><h1>Dashboard</h1></div>
<div class="header-actions">
<button type="button" onclick={onClone} disabled={isBusy}><Download size={14} />{de ? "Klonen" : "Clone"}</button>
<button type="button" onclick={onInit} disabled={isBusy}><FolderGit2 size={14} />{de ? "Initialisieren" : "Initialize"}</button>
+4 -4
View File
@@ -402,8 +402,8 @@
{/if}
<section class:has-inspector={detailOpen && !!selected} class="review-center" aria-label="Review Center">
<header class="review-header">
<div class="review-heading"><GitPullRequest size={17} /><h1>Review Center</h1></div>
<header class="review-header page-header">
<div class="review-heading page-heading"><GitPullRequest size={17} /><h1>Review Center</h1></div>
{#if activeSource}<button class="create-review" type="button" disabled={loading} onclick={() => { detailOpen = false; createOpen = true; }}><GitPullRequest size={14}/>{activeSource.provider.startsWith("gitlab") ? (de ? "MR erstellen" : "Create MR") : (de ? "PR erstellen" : "Create PR")}</button>{/if}
</header>
@@ -459,7 +459,7 @@
<span>{stateLabel(request.state)}<small title={formatDate(request.updatedAt || request.createdAt)}>{formatRelativeDate(request.updatedAt || request.createdAt)}</small></span>
</span>
<span class="request-title"><span><code>#{request.number}</code><strong title={request.title}>{request.title}</strong></span><small class="change-stats"><b>+{request.additions ?? ""}</b><i>/</i><em>{request.deletions ?? ""}</em>{#if request.changedFiles !== null}<span title={de ? "Geänderte Dateien" : "Changed files"}>{request.changedFiles} {request.changedFiles === 1 ? (de ? "Datei geändert" : "file changed") : (de ? "Dateien geändert" : "files changed")}</span>{:else if detailLoadingId === request.id}<span>{de ? "Lädt …" : "Loading …"}</span>{/if}</small></span>
<span class="request-author"><i>{initials(request.author)}</i><span>{request.author || (de ? "Unbekannt" : "Unknown")}</span></span>
<span class="request-author" title={request.author || (de ? "Unbekannt" : "Unknown")} aria-label={request.author || (de ? "Unbekannt" : "Unknown")}><i aria-hidden="true">{initials(request.author)}</i></span>
<span class="collaborators">{#if request.collaborators.length}{#each request.collaborators.slice(0, 3) as collaborator}<i title={collaborator}>{initials(collaborator)}</i>{/each}{:else}<span></span>{/if}</span>
<span class="repo-branch"><strong>{request.repositoryName}</strong>{#if request.sourceBranch && request.targetBranch}<span class="branch-route"><GitBranch size={11} /><code title={request.sourceBranch}>{request.sourceBranch}</code><b></b><code title={request.targetBranch}>{request.targetBranch}</code></span>{:else}<span class="branch-loading"><LoaderCircle class="spin" size={11} />{de ? "Branches werden geladen …" : "Loading branches …"}</span>{/if}</span>
<span class="row-actions">
@@ -537,7 +537,7 @@
.state-tabs{display:flex;min-height:42px;align-items:stretch;gap:18px;padding:0 18px;border-bottom:1px solid var(--color-border-subtle);background:var(--color-surface)}.state-tabs button{position:relative;display:flex;align-items:center;gap:7px;padding:0 5px;border:0;color:var(--color-ink-muted);background:transparent;font-size:11px}.state-tabs button:hover{color:var(--color-ink)}.state-tabs button.active{color:var(--color-accent)}.state-tabs button.active:after{position:absolute;right:0;bottom:0;left:0;height:2px;background:var(--color-accent);content:""}.state-tabs span,.group-header>span{display:grid;min-width:18px;height:18px;place-items:center;padding:0 5px;border-radius:9px;color:var(--color-ink-muted);background:var(--color-surface-raised);font-size:9.5px}
.review-toolbar{display:flex;min-height:48px;align-items:center;gap:10px;padding:7px 18px;border-bottom:1px solid var(--color-border-subtle)}.group-actions{display:flex;align-items:center;gap:2px}.group-actions button,.icon-button{display:inline-flex;height:30px;align-items:center;gap:5px;padding:0 7px;border:1px solid transparent;color:var(--color-ink-muted);background:transparent}.group-actions button:hover,.icon-button:hover{border-color:var(--color-border);color:var(--color-ink);background:var(--color-surface-hover)}.group-actions .icon-button{width:30px;justify-content:center;padding:0;border-color:var(--color-border-subtle);margin-left:3px}.review-search{display:flex;min-width:180px;height:30px;align-items:center;gap:7px;flex:1;padding:0 9px;border:1px solid var(--color-border-input);color:var(--color-ink-faint);background:var(--app-input-bg)}.review-search:focus-within{border-color:var(--color-accent)}.review-search input{width:100%;min-width:0;height:100%;padding:0;border:0;outline:0;color:var(--color-ink);background:transparent}
.source-warning{padding:7px 18px;border-bottom:1px solid color-mix(in srgb,#d3a64d 28%,var(--color-border));color:#d3a64d;background:color-mix(in srgb,#d3a64d 6%,var(--app-bg))}.source-warning summary{display:flex;align-items:center;gap:7px;cursor:pointer}.source-warning ul{display:grid;gap:4px;margin:7px 0 2px;padding-left:22px;color:var(--color-ink-muted);font-size:10.5px}.source-warning li strong{color:var(--color-ink)}.action-notice{display:flex;min-height:30px;align-items:center;gap:7px;padding:0 18px;border-bottom:1px solid color-mix(in srgb,#63c783 28%,var(--color-border));color:#63c783;background:color-mix(in srgb,#63c783 6%,var(--app-bg));font-size:10.5px}
.review-layout{display:grid;grid-template-columns:minmax(0,1fr);flex:1;min-height:0}.review-layout.inspector-open{grid-template-columns:minmax(560px,1fr) minmax(360px,38%)}.table-pane{min-width:0;min-height:0;overflow:auto}.table-head,.request-row{display:grid;grid-template-columns:95px minmax(280px,1.5fr) 135px 145px minmax(210px,1fr) 190px;align-items:center}.table-head{position:sticky;z-index:2;top:0;min-height:30px;padding:0 12px;border-bottom:1px solid var(--color-border);color:var(--color-ink-faint);background:var(--color-surface-raised);font-size:9px;font-weight:700;letter-spacing:.035em;text-transform:uppercase}.request-groups{min-width:1075px}.request-group{border-bottom:1px solid var(--color-border-subtle)}.group-header{display:flex;width:100%;height:34px;align-items:center;justify-content:flex-start;gap:7px;padding:0 12px;border:0;border-bottom:1px solid var(--color-border-subtle);color:var(--color-ink);background:var(--color-surface);text-align:left}.group-header:hover{background:var(--color-surface-hover)}.group-header>:global(svg){color:var(--color-ink-faint)}.group-header strong{font-size:11px}.group-header>span{margin-left:2px}.request-row{position:relative;min-height:52px;padding:0 12px;border-bottom:1px solid var(--color-border-subtle);outline:1px solid transparent;outline-offset:-1px;color:var(--color-ink-muted);background:transparent;cursor:default}.request-row:hover{background:var(--color-surface-hover)}.request-row.selected{z-index:1;outline-color:var(--color-accent);background:var(--color-surface-raised)}.request-status{display:flex;align-items:center;gap:6px;font-size:10px}.request-status>span{display:grid;gap:2px}.request-status small{color:var(--color-ink-faint);font-size:9px}.request-title{display:grid;min-width:0;gap:5px;padding-right:14px}.request-title>span{display:flex;min-width:0;gap:8px}.request-title code{color:var(--color-accent);font-size:10px}.request-title strong{overflow:hidden;color:var(--color-ink);font-size:11px;font-weight:560;text-overflow:ellipsis;white-space:nowrap}.change-stats{display:flex;align-items:center;gap:6px;font-size:9.5px}.change-stats b{color:#63c783}.change-stats em{color:#e0737b;font-style:normal}.change-stats i{color:var(--color-ink-faint);font-style:normal}.change-stats span{color:var(--color-ink-faint)}.request-author{display:flex;min-width:0;align-items:center;gap:7px;padding-right:10px}.request-author i,.avatar,.collaborators i{display:grid;width:23px;height:23px;flex:0 0 auto;place-items:center;border:1px solid color-mix(in srgb,var(--color-accent) 35%,var(--color-border));border-radius:50%;color:#fff;background:color-mix(in srgb,var(--color-accent) 45%,var(--color-surface-raised));font-size:9px;font-style:normal;font-weight:750}.request-author>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.collaborators{display:flex;padding-left:3px}.collaborators i+ i{margin-left:-5px}.repo-branch{display:grid;min-width:0;gap:4px}.repo-branch>strong{overflow:hidden;color:var(--color-ink-muted);font-size:10px;text-overflow:ellipsis;white-space:nowrap}.branch-route{display:flex;min-width:0;align-items:center;gap:5px;padding-right:12px}.branch-route code{max-width:42%;overflow:hidden;color:var(--color-ink-faint);font-size:9px;text-overflow:ellipsis;white-space:nowrap}.branch-route b{color:var(--color-ink-faint);font-weight:400}.row-actions{display:flex;align-items:center;justify-content:flex-end;gap:5px}.provider-action{position:relative;display:flex}.provider-button,.action-toggle,.detail-action{display:inline-flex;height:28px;align-items:center;justify-content:center;gap:6px;border:1px solid var(--color-accent);color:var(--color-accent);background:color-mix(in srgb,var(--color-accent) 5%,transparent)}.provider-button{min-width:120px;padding:0 8px;border-right:0}.provider-button.merge-primary{color:#63c783;border-color:#4fa565;background:color-mix(in srgb,#4fa565 15%,var(--color-surface))}.provider-button.conflict{color:#e0737b;border-color:#a74b55}.action-toggle{width:27px;padding:0}.provider-button:hover,.action-toggle:hover,.action-toggle.active,.detail-action:hover{color:#fff;background:color-mix(in srgb,var(--color-accent) 24%,var(--color-surface))}.action-menu{position:absolute;z-index:8;top:31px;right:0;display:grid;width:178px;padding:4px;border:1px solid var(--color-border);box-shadow:0 8px 22px #0008;background:var(--color-surface-raised)}.action-menu button{display:flex;height:29px;align-items:center;gap:8px;padding:0 8px;border:0;color:var(--color-ink-muted);background:transparent;text-align:left}.action-menu button:hover{color:var(--color-ink);background:var(--color-surface-hover)}.action-menu button.danger{color:#e0737b}.panel-button{display:grid;width:28px;height:28px;place-items:center;border:1px solid var(--color-border);color:var(--color-ink-muted);background:var(--app-button-bg)}.panel-button:hover,.panel-button.active{border-color:var(--color-accent);color:var(--color-accent)}
.review-layout{display:grid;grid-template-columns:minmax(0,1fr);flex:1;min-height:0}.review-layout.inspector-open{grid-template-columns:minmax(560px,1fr) minmax(360px,38%)}.table-pane{min-width:0;min-height:0;overflow:auto}.table-head,.request-row{display:grid;grid-template-columns:95px minmax(280px,1.5fr) 135px 145px minmax(210px,1fr) 190px;align-items:center}.table-head{position:sticky;z-index:2;top:0;min-height:30px;padding:0 12px;border-bottom:1px solid var(--color-border);color:var(--color-ink-faint);background:var(--color-surface-raised);font-size:9px;font-weight:700;letter-spacing:.035em;text-transform:uppercase}.request-groups{min-width:1075px}.request-group{border-bottom:1px solid var(--color-border-subtle)}.group-header{display:flex;width:100%;height:34px;align-items:center;justify-content:flex-start;gap:7px;padding:0 12px;border:0;border-bottom:1px solid var(--color-border-subtle);color:var(--color-ink);background:var(--color-surface);text-align:left}.group-header:hover{background:var(--color-surface-hover)}.group-header>:global(svg){color:var(--color-ink-faint)}.group-header strong{font-size:11px}.group-header>span{margin-left:2px}.request-row{position:relative;min-height:52px;padding:0 12px;border-bottom:1px solid var(--color-border-subtle);outline:1px solid transparent;outline-offset:-1px;color:var(--color-ink-muted);background:transparent;cursor:default}.request-row:hover{background:var(--color-surface-hover)}.request-row.selected{z-index:1;outline-color:var(--color-accent);background:var(--color-surface-raised)}.request-status{display:flex;align-items:center;gap:6px;font-size:10px}.request-status>span{display:grid;gap:2px}.request-status small{color:var(--color-ink-faint);font-size:9px}.request-title{display:grid;min-width:0;gap:5px;padding-right:14px}.request-title>span{display:flex;min-width:0;gap:8px}.request-title code{color:var(--color-accent);font-size:10px}.request-title strong{overflow:hidden;color:var(--color-ink);font-size:11px;font-weight:560;text-overflow:ellipsis;white-space:nowrap}.change-stats{display:flex;align-items:center;gap:6px;font-size:9.5px}.change-stats b{color:#63c783}.change-stats em{color:#e0737b;font-style:normal}.change-stats i{color:var(--color-ink-faint);font-style:normal}.change-stats span{color:var(--color-ink-faint)}.request-author{display:flex;min-width:0;align-items:center;gap:7px;padding-right:10px}.request-author i,.avatar,.collaborators i{display:grid;width:23px;height:23px;flex:0 0 auto;place-items:center;border:1px solid color-mix(in srgb,var(--color-accent) 35%,var(--color-border));border-radius:50%;color:#fff;background:color-mix(in srgb,var(--color-accent) 45%,var(--color-surface-raised));font-size:9px;font-style:normal;font-weight:750}.collaborators{display:flex;padding-left:3px}.collaborators i+ i{margin-left:-5px}.repo-branch{display:grid;min-width:0;gap:4px}.repo-branch>strong{overflow:hidden;color:var(--color-ink-muted);font-size:10px;text-overflow:ellipsis;white-space:nowrap}.branch-route{display:flex;min-width:0;align-items:center;gap:5px;padding-right:12px}.branch-route code{max-width:42%;overflow:hidden;color:var(--color-ink-faint);font-size:9px;text-overflow:ellipsis;white-space:nowrap}.branch-route b{color:var(--color-ink-faint);font-weight:400}.row-actions{display:flex;align-items:center;justify-content:flex-end;gap:5px}.provider-action{position:relative;display:flex}.provider-button,.action-toggle,.detail-action{display:inline-flex;height:28px;align-items:center;justify-content:center;gap:6px;border:1px solid var(--color-accent);color:var(--color-accent);background:color-mix(in srgb,var(--color-accent) 5%,transparent)}.provider-button{min-width:120px;padding:0 8px;border-right:0}.provider-button.merge-primary{color:#63c783;border-color:#4fa565;background:color-mix(in srgb,#4fa565 15%,var(--color-surface))}.provider-button.conflict{color:#e0737b;border-color:#a74b55}.action-toggle{width:27px;padding:0}.provider-button:hover,.action-toggle:hover,.action-toggle.active,.detail-action:hover{color:#fff;background:color-mix(in srgb,var(--color-accent) 24%,var(--color-surface))}.action-menu{position:absolute;z-index:8;top:31px;right:0;display:grid;width:178px;padding:4px;border:1px solid var(--color-border);box-shadow:0 8px 22px #0008;background:var(--color-surface-raised)}.action-menu button{display:flex;height:29px;align-items:center;gap:8px;padding:0 8px;border:0;color:var(--color-ink-muted);background:transparent;text-align:left}.action-menu button:hover{color:var(--color-ink);background:var(--color-surface-hover)}.action-menu button.danger{color:#e0737b}.panel-button{display:grid;width:28px;height:28px;place-items:center;border:1px solid var(--color-border);color:var(--color-ink-muted);background:var(--app-button-bg)}.panel-button:hover,.panel-button.active{border-color:var(--color-accent);color:var(--color-accent)}
.detail-panel{min-width:0;min-height:0;overflow:auto;border-left:1px solid var(--color-border);background:var(--color-surface)}.detail-header{display:flex;min-height:78px;align-items:flex-start;justify-content:space-between;gap:14px;padding:15px 16px;border-bottom:1px solid var(--color-border)}.detail-header>div{min-width:0}.detail-content{display:grid;gap:0;padding:0 16px}.detail-summary{display:flex;min-height:48px;align-items:center;gap:8px;border-bottom:1px solid var(--color-border-subtle)}.state-badge{padding:3px 7px;border:1px solid currentColor;font-size:9px;font-weight:700}.detail-summary .avatar{margin-left:4px}.detail-summary strong{font-size:11px}.description{padding:15px 0;border-bottom:1px solid var(--color-border-subtle)}.description h3{margin:0 0 9px;font-size:11px}.description p{margin:0;white-space:pre-wrap;color:var(--color-ink-muted);font-size:11px;line-height:1.55}.description p.muted{color:var(--color-ink-faint)}.detail-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px;margin-top:16px}.detail-action{width:100%;height:32px;padding:0 8px}.detail-action.primary-action{color:#63c783;border-color:#63c783}.detail-action.danger-action{color:#e0737b;border-color:color-mix(in srgb,#e0737b 75%,var(--color-border))}.open{color:#63c783}.draft{color:var(--color-ink-muted)}.merged{color:#b785e8}.closed{color:#e0737b}
.loading-state,.list-empty,.empty-state{display:flex;min-height:180px;align-items:center;justify-content:center;gap:8px;color:var(--color-ink-muted)}.list-empty,.empty-state{flex-direction:column}.list-empty strong{color:var(--color-ink);font-size:12px}.list-empty span{font-size:10px}.empty-state{flex:1;text-align:center}.empty-state h2{margin:4px 0 0;font-size:14px}.empty-state p{max-width:430px;margin:0 0 8px;line-height:1.5}.empty-icon{display:grid;width:42px;height:42px;place-items:center;border:1px solid var(--color-border);color:var(--color-accent);background:var(--color-surface)}.primary{display:inline-flex;min-height:30px;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--color-primary);color:#fff;background:var(--color-primary)}
@media(max-width:1100px){.review-layout.inspector-open{grid-template-columns:minmax(500px,1fr) 360px}.table-head,.request-row{grid-template-columns:78px minmax(230px,1.5fr) minmax(180px,1fr) 90px 170px}.table-head>span:nth-child(3),.request-author{display:none}.request-groups{min-width:760px}}
+34 -34
View File
@@ -21,8 +21,8 @@
.issue-center .workspace-heading {display:flex;align-items:center;justify-content:space-between;gap:20px;padding:14px 24px 8px;flex-shrink:0}
.issue-center .workspace-title {display:flex;align-items:center;gap:13px;min-width:0}
.issue-center .workspace-title p {color:var(--issue-muted);font-size:12px;margin-top:4px}
.issue-center .workspace-symbol {display:grid;place-items:center;flex-shrink:0;width:34px;height:34px;color:var(--color-accent);border:1px solid color-mix(in srgb,var(--color-accent) 55%,transparent);border-radius:6px;background:color-mix(in srgb,var(--color-accent) 5%,transparent)}
.issue-center .workspace-button {display:inline-flex;align-items:center;justify-content:center;gap:7px;min-height:32px;padding:6px 10px;white-space:nowrap;border:1px solid var(--color-border);border-radius:4px;background:transparent;color:var(--color-ink-muted);box-shadow:none}
.issue-center .workspace-symbol {display:grid;place-items:center;flex-shrink:0;width:34px;height:34px;color:var(--color-accent);border:1px solid color-mix(in srgb,var(--color-accent) 55%,transparent);border-radius:0;background:color-mix(in srgb,var(--color-accent) 5%,transparent)}
.issue-center .workspace-button {display:inline-flex;align-items:center;justify-content:center;gap:7px;min-height:32px;padding:6px 10px;white-space:nowrap;border:1px solid var(--color-border);border-radius:0;background:transparent;color:var(--color-ink-muted);box-shadow:none}
.issue-center .workspace-button:hover:not(:disabled) {background:var(--color-surface-hover);border-color:var(--color-border-input);color:var(--color-ink)}
.issue-center .workspace-button.active {color:var(--color-accent)}
.issue-center .workspace-button svg {flex-shrink:0}
@@ -34,13 +34,13 @@
.issue-center .view-toggle button.active:after {position:absolute;content:"";bottom:-1px;left:0;right:0;height:2px;background:var(--color-accent)}
.issue-center .view-toggle button:hover {color:var(--color-ink)}
.issue-center .source-select {width:190px;flex:0 1 190px}
.issue-center .source-select button,.issue-center .state-select button {border-radius:4px;font-size:12px;font-weight:400;min-height:32px;background:transparent}
.issue-center .workspace-search {display:flex;align-items:center;gap:9px;min-width:0;height:34px;padding:0 10px;border:1px solid var(--color-border);border-radius:4px;color:var(--issue-muted);background:color-mix(in srgb,var(--color-surface) 35%,transparent)}
.issue-center .source-select button,.issue-center .state-select button,.issue-center .board-select button,.issue-center .repository-select button {border-radius:0;font-size:12px;font-weight:400;min-height:32px;background:transparent}
.issue-center .workspace-search {display:flex;align-items:center;gap:9px;min-width:0;height:34px;padding:0 10px;border:1px solid var(--color-border);border-radius:0;color:var(--issue-muted);background:color-mix(in srgb,var(--color-surface) 35%,transparent)}
.issue-center .workspace-search:focus-within {border-color:var(--color-accent)}
.issue-center .workspace-search svg {flex-shrink:0}
.issue-center .workspace-search input {min-width:0;width:100%;height:100%;border:0;border-radius:0;outline:0;background:transparent;color:var(--color-ink);padding:0}
.issue-center input::placeholder {color:var(--issue-muted);opacity:1}
.issue-center .workspace-notice {margin:0 24px 12px;padding:10px 12px;border:1px solid var(--issue-line);border-radius:4px;color:var(--color-ink-muted);font-size:12px;overflow-wrap:anywhere}
.issue-center .workspace-notice {margin:0 24px 12px;padding:10px 12px;border:1px solid var(--issue-line);border-radius:0;color:var(--color-ink-muted);font-size:12px;overflow-wrap:anywhere}
.issue-center .workspace-notice.error {border-color:color-mix(in srgb,#d6a555 45%,transparent);background:color-mix(in srgb,#d6a555 4%,transparent)}
.issue-center .workspace-notice p {margin-top:4px;color:var(--issue-muted)}
.issue-center .issue-content {display:flex;flex:1;min-height:0;min-width:0;position:relative;overflow:hidden}
@@ -50,7 +50,7 @@
.issue-center .state-select {flex:0 0 150px;width:150px}
.issue-center .issue-list {flex:0 1 auto;min-height:0;overflow:auto;padding:0 24px}
.issue-center .issue-table-heading,.issue-center .issue-row {display:grid;grid-template-columns:minmax(0,1fr) 145px 130px;gap:18px;align-items:center;text-align:left}
.issue-center .issue-table-heading {min-height:32px;padding:0 14px 0 16px;color:var(--issue-muted);font-size:10px;font-weight:500;text-transform:uppercase;letter-spacing:.65px;background:color-mix(in srgb,var(--color-surface) 35%,transparent);border-radius:4px 4px 0 0;border-bottom:1px solid var(--issue-line);position:sticky;top:0;z-index:1}
.issue-center .issue-table-heading {min-height:32px;padding:0 14px 0 16px;color:var(--issue-muted);font-size:10px;font-weight:500;text-transform:uppercase;letter-spacing:.65px;background:color-mix(in srgb,var(--color-surface) 35%,transparent);border-radius:0;border-bottom:1px solid var(--issue-line);position:sticky;top:0;z-index:1}
.issue-center .issue-row {position:relative;width:100%;min-height:56px;padding:8px 14px 8px 16px;border:0;border-bottom:1px solid var(--issue-line);border-radius:0;color:var(--color-ink);background:transparent;box-shadow:none}
.issue-center .issue-row:hover {background:color-mix(in srgb,var(--color-surface-hover) 55%,transparent)}
.issue-center .issue-row.selected {background:color-mix(in srgb,var(--color-accent) 9%,transparent);box-shadow:inset 2px 0 var(--color-accent)}
@@ -73,7 +73,7 @@
.issue-center .person-name {min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.issue-center .unassigned {color:var(--color-ink-faint)}
.issue-center .issue-labels {display:flex;flex-wrap:wrap;gap:4px;min-width:0}
.issue-center .issue-label {padding:2px 6px;border-radius:4px;font-size:10px;line-height:1.5;letter-spacing:.1px;color:var(--color-ink-muted);background:var(--color-surface-dim);overflow-wrap:anywhere;font-weight:400}
.issue-center .issue-label {padding:2px 6px;border-radius:0;font-size:10px;line-height:1.5;letter-spacing:.1px;color:var(--color-ink-muted);background:var(--color-surface-dim);overflow-wrap:anywhere;font-weight:400}
.issue-center .issue-label[data-tone="red"] {background:#9e3d43;color:#fff0f1}
.issue-center .issue-label[data-tone="blue"] {background:#3e5699;color:#eef2ff}
:root[data-theme="light"] .issue-center .issue-label[data-tone="red"] {color:#972e3c;background:#fbe5e8}
@@ -94,36 +94,31 @@
.issue-center .workspace-empty {display:flex;flex:1;flex-direction:column;align-items:center;justify-content:center;gap:12px;text-align:center;padding:56px 24px;color:var(--issue-muted);min-height:250px}
.issue-center .workspace-empty p {font-size:12px;max-width:440px;line-height:1.7}
.issue-center .workspace-empty h2 {color:var(--color-ink);font-size:16px}
.issue-center .empty-symbol {display:grid;place-items:center;width:52px;height:52px;margin-bottom:6px;border:1px solid var(--issue-line);border-radius:12px;color:var(--issue-muted)}
.issue-center .empty-symbol {display:grid;place-items:center;width:52px;height:52px;margin-bottom:6px;border:1px solid var(--issue-line);border-radius:0;color:var(--issue-muted)}
.issue-center .board-view {display:flex;flex:1;flex-direction:column;min-height:0;min-width:0;overflow:hidden}
.issue-center .board-header {display:flex;align-items:center;justify-content:space-between;gap:20px;padding:18px 24px 14px;flex-shrink:0}
.issue-center .board-header {display:flex;align-items:center;justify-content:space-between;gap:20px;padding:12px 24px 10px;flex-shrink:0}
.issue-center .board-title {min-width:0}
.issue-center .board-title h2 {font-size:16px;line-height:1.4;font-weight:600;letter-spacing:.05px}
.issue-center .board-title h2 {font-size:16px;line-height:1.4;font-weight:600;letter-spacing:-.25px}
.issue-center .board-title small {display:block;margin-top:4px}
.issue-center .board-title small>span {padding:0 5px}
.issue-center .board-tools {display:flex;align-items:center;gap:9px;flex-shrink:0}
.issue-center .board-tools .workspace-search {width:240px}
.issue-center .board-connect {padding:18px 24px;flex-shrink:0;border-bottom:1px solid var(--issue-line)}
.issue-center .board-connect label {display:block;font-size:11px;color:var(--issue-muted);margin-bottom:7px}
.issue-center .board-connect-fields {display:flex;gap:10px}
.issue-center .board-connect input {flex:1;min-width:100px;min-height:34px;padding:6px 10px;border:1px solid var(--color-border);border-radius:4px;background:transparent;color:var(--color-ink)}
.issue-center .board-tools {display:flex;align-items:center;gap:10px;flex-shrink:0}
.issue-center .board-tools .workspace-search {width:360px;max-width:100%}
.issue-center .board-notice {font-size:11px;line-height:1.6;padding:0 24px 12px;color:var(--issue-muted);flex-shrink:0}
.issue-center .board-body {position:relative;display:flex;flex:1;min-height:0;overflow:hidden}
.issue-center .board-columns {display:flex;flex:1;min-width:0;gap:14px;padding:0 24px 20px;overflow:auto;align-items:stretch}
.issue-center .board-column {display:flex;flex:1 0 278px;max-width:400px;min-width:0;flex-direction:column;border:0;border-radius:6px;background:color-mix(in srgb,var(--color-surface) 60%,var(--issue-canvas));overflow:hidden}
.issue-center .board-column>header {display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 12px 12px;flex-shrink:0}
.issue-center .board-column {display:flex;flex:1 0 278px;max-width:400px;min-width:0;flex-direction:column;border:1px solid var(--issue-line);border-radius:0;background:transparent;overflow:hidden}
.issue-center .board-column>header {display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:34px;padding:8px 14px;flex-shrink:0;border-bottom:1px solid var(--issue-line);background:color-mix(in srgb,var(--color-surface) 35%,transparent)}
.issue-center .board-column h3 {display:flex;align-items:center;gap:9px;min-width:0;font-size:12px;font-weight:600;overflow-wrap:anywhere}
.issue-center .column-dot {width:10px;height:10px;flex:0 0 10px;border-radius:50%;background:var(--status-color)}
.issue-center .column-dot {width:13px;height:13px;flex:0 0 13px;border:2px solid var(--status-color);border-radius:50%;background:transparent}
.issue-center .column-count {color:var(--issue-muted);font-size:11px;white-space:nowrap}
.issue-center .wip-limit {font-size:10px}
.issue-center .column-cards {padding:0 10px 10px;min-height:0;overflow:auto;flex:1}
.issue-center .board-card {display:flex;flex-direction:column;align-items:flex-start;gap:7px;width:100%;text-align:left;padding:12px;margin-bottom:9px;border:1px solid var(--color-border);border-radius:6px;box-shadow:0 2px 3px #0000000a;background:var(--issue-canvas);color:var(--color-ink);overflow-wrap:anywhere}
.issue-center .board-card:hover {border-color:var(--color-border-input);background:color-mix(in srgb,var(--color-surface) 55%,var(--issue-canvas))}
.issue-center .board-card.chosen {border-color:color-mix(in srgb,var(--color-accent) 65%,var(--color-border));background:color-mix(in srgb,var(--color-accent) 5%,var(--issue-canvas))}
.issue-center .board-card strong {font-size:13px;line-height:1.5;font-weight:550}
.issue-center .column-cards {padding:0;min-height:0;overflow:auto;flex:1}
.issue-center .board-card {display:flex;flex-direction:column;align-items:flex-start;gap:7px;width:100%;text-align:left;padding:12px 14px;margin:0;border:0;border-bottom:1px solid var(--issue-line);border-radius:0;box-shadow:none;background:transparent;color:var(--color-ink);overflow-wrap:anywhere}
.issue-center .board-card:hover {background:color-mix(in srgb,var(--color-surface-hover) 55%,transparent)}
.issue-center .board-card.chosen {background:color-mix(in srgb,var(--color-accent) 9%,transparent);box-shadow:inset 2px 0 var(--color-accent)}
.issue-center .board-card strong {font-size:13px;line-height:1.45;font-weight:550}
.issue-center .card-reference {display:flex;align-items:center;flex-wrap:wrap;gap:8px;font-size:11px;line-height:1.4}
.issue-center .board-card .issue-person {margin-top:3px;font-size:11px}
.issue-center .board-card .issue-avatar {width:19px;height:19px;flex-basis:19px;font-size:9px}
.issue-center .lane {font-size:10px;line-height:1.5;color:var(--color-accent);font-weight:400}
.issue-center .column-empty {padding:28px 12px;text-align:center;color:var(--color-ink-faint);font-size:11px}
@media(min-width:1250px) {
@@ -151,7 +146,7 @@
.issue-center .issue-footer {padding:12px 16px;font-size:10px}
.issue-center .issue-inspector {position:absolute;inset:0;width:100%;max-width:none;z-index:3;border:0;flex-basis:auto;background:var(--issue-canvas);padding:20px}
.issue-center .with-details .issue-main {visibility:hidden}
.issue-center .board-header,.issue-center .board-connect {padding:16px}
.issue-center .board-header {padding:16px}
.issue-center .board-tools {flex-wrap:wrap;gap:8px}
.issue-center .board-tools .workspace-search {flex:1 1 100%;height:34px}
.issue-center .board-columns {padding:0 16px 16px;gap:12px}
@@ -171,19 +166,19 @@
.issue-center .issue-status {font-size:11px;gap:6px}
.issue-center .issue-toolbar .workspace-search {flex-basis:100%}
.issue-center .board-tools>.workspace-button {font-size:11px;padding:6px 8px}
.issue-center .board-connect-fields {flex-wrap:wrap}
.issue-center .board-connect input {flex-basis:100%}
}
@media(prefers-reduced-motion:reduce) {.issue-center button {transition:none}}
/* This workspace opts into its compact rounded controls. The app-wide square
reset uses !important, so the same priority is needed for these local shapes. */
.issue-center :is(.issue-avatar,.status-dot,.column-dot) {border-radius:50% !important}
.issue-center :is(.workspace-button,.workspace-search,.issue-label,.source-select button,.state-select button,.board-connect input) {border-radius:4px !important}
.issue-center :is(.workspace-symbol,.board-column,.board-card) {border-radius:6px !important}
.issue-center .empty-symbol {border-radius:12px !important}
.issue-center :is(.workspace-button,.workspace-search,.issue-label,.source-select button,.state-select button) {border-radius:0}
.issue-center .workspace-symbol {border-radius:0}
.issue-center .board-column {border-radius:0}
.issue-center .board-card {border-radius:0}
.issue-center .empty-symbol {border-radius:0}
.issue-center .repository-select {width:190px;flex:0 1 190px;min-width:130px}
.issue-center .repository-select button {font-size:12px;min-height:32px;border-radius:4px !important}
.issue-center .repository-select button {font-size:12px;min-height:32px;border-radius:0}
/* Both tabs, including their shared navigation and dropdowns, use square corners. */
.issue-center :not(.status-dot):not(.column-dot) {border-radius:0 !important}
.issue-center .repository-group-heading {display:flex;align-items:center;gap:9px;padding:14px 16px 9px;color:var(--color-ink-muted);border-bottom:1px solid var(--issue-line)}
.issue-center .repository-group-heading strong {overflow-wrap:anywhere}
.issue-center .repository-group-heading>span {margin-left:auto;color:var(--issue-muted);font-size:11px}
@@ -251,3 +246,8 @@
.issue-center .comment-error {color:#e0737b;font-size:11px;overflow-wrap:anywhere}
.issue-center .issue-close-action {width:100%;min-height:39px;margin-bottom:10px;color:#e0737b;border-color:#a74b55;font-size:11px}
@media(max-width:800px) {
.issue-center .board-directory {padding:14px 16px 10px;gap:8px}
.issue-center .board-discovery-notice {padding:8px 16px}
}