@anthusai/papyrus 5.43.0-next.4 → 5.43.0-next.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/amplify/data/resource.js +6 -0
- package/amplify/data/resource.ts +7 -0
- package/amplify/data/schema.js +6 -0
- package/amplify/data/schema.ts +7 -0
- package/amplify/functions/category-action/handler.ts +16 -8
- package/amplify/functions/content-actions/handler.py +8 -0
- package/amplify/functions/content-actions/requirements.txt +2 -0
- package/amplify/functions/content-actions/resource.js +1 -1
- package/amplify/functions/content-actions/resource.ts +1 -1
- package/amplify/functions/model-attachment-upload/handler.ts +1 -0
- package/amplify/functions/monitoring-view/schema.js +16 -0
- package/amplify/functions/monitoring-view/schema.ts +16 -0
- package/amplify/functions/procedure-action/handler.ts +2 -10
- package/amplify/functions/proposal-actions/proposals.py +20 -3
- package/amplify/plugins/reader-steering/function/handler.py +1 -3
- package/amplify/plugins/reader-steering/function/moderation.py +19 -0
- package/app/api/newsroom/source-frameable/route.ts +12 -0
- package/app/api/newsroom/source-icon/route.ts +20 -0
- package/app/newsroom/[section]/[...selection]/page.tsx +2 -0
- package/app/newsroom/[section]/page.tsx +1 -0
- package/bin/papyrus-app.mjs +12 -1
- package/bin/papyrus-infra.mjs +21 -1
- package/components/auto-accepted-badge.tsx +21 -0
- package/components/conversation-context.tsx +52 -0
- package/components/conversation-provider.tsx +20 -0
- package/components/conversation-thread.tsx +174 -0
- package/components/decision-control.tsx +306 -0
- package/components/dev-sandbox-editor-sign-in.tsx +2 -2
- package/components/markdown-context.tsx +412 -0
- package/components/monitoring-overview-view.tsx +143 -21
- package/components/monitoring-panel.tsx +64 -4
- package/components/needs-me-bodies.tsx +302 -0
- package/components/needs-me-detail.tsx +24 -0
- package/components/needs-me-feed.tsx +594 -0
- package/components/needs-me-reference-detail.tsx +79 -0
- package/components/needs-me-shared.tsx +48 -0
- package/components/news-desk-client-provider.tsx +24 -3
- package/components/news-desk-page.tsx +2 -1
- package/components/news-desk-taxonomy-client.ts +253 -31
- package/components/newsroom-access-gate.tsx +13 -20
- package/components/newsroom-board-skeleton.tsx +20 -0
- package/components/newsroom-board-view.tsx +2 -6
- package/components/newsroom-client-shell.tsx +2 -1
- package/components/newsroom-ops-overview.tsx +88 -73
- package/components/newsroom-ops-shell.tsx +8 -28
- package/components/newsroom-organizer.css +127 -3
- package/components/newsroom-references-view.tsx +334 -158
- package/components/notification-cards.tsx +370 -0
- package/components/notification-center.tsx +376 -213
- package/components/papyrus-console-shell.tsx +2 -1
- package/components/proposals-panel.tsx +21 -24
- package/components/proposals-view.tsx +4 -2
- package/components/reader-auth-control.tsx +3 -1
- package/components/reference-capture-client.ts +138 -0
- package/components/reference-capture-panel.tsx +268 -0
- package/components/reference-conversation.tsx +43 -0
- package/components/reference-feed.tsx +514 -0
- package/components/reference-review-card.tsx +62 -197
- package/components/reference-source-preview.tsx +27 -5
- package/components/reference-stories.tsx +34 -0
- package/components/references-page-loading.tsx +61 -0
- package/components/references-prefetch.ts +52 -0
- package/components/story-reporting-trail-client.ts +45 -8
- package/components/story-reporting-trail.tsx +24 -13
- package/components/topic-steering-workspace.tsx +50 -439
- package/components/ui/auto-grow-textarea.tsx +18 -0
- package/components/use-conversation.ts +84 -0
- package/components/use-media-query.ts +16 -0
- package/components/use-reference-preview-attachments.ts +101 -0
- package/components/use-reference-ratings.ts +189 -0
- package/infra/amplify-app-shell.js +18 -2
- package/infra/amplify-app-shell.ts +18 -2
- package/infra/chat-stack.js +222 -0
- package/infra/chat-stack.ts +250 -0
- package/infra/chat.test.js +142 -0
- package/infra/chat.test.ts +151 -0
- package/infra/index.js +1 -0
- package/infra/site-config.js +58 -1
- package/infra/site-config.ts +78 -1
- package/lib/category-repository.ts +6 -1
- package/lib/content-actions-client.ts +20 -0
- package/lib/conversation.ts +154 -0
- package/lib/local-preview-feed-fixture.ts +63 -0
- package/lib/local-preview-seed.ts +24 -2
- package/lib/local-preview-synthetic-rejects.ts +41 -0
- package/lib/monitoring-client.ts +29 -2
- package/lib/monitoring-overview.ts +52 -1
- package/lib/monitoring-paging.ts +58 -0
- package/lib/needs-me-items.ts +289 -0
- package/lib/needs-me-ranking.ts +315 -0
- package/lib/newsroom-all-pages.ts +21 -0
- package/lib/newsroom-chat-identity.ts +2 -1
- package/lib/newsroom-index-filters.ts +18 -0
- package/lib/newsroom-nav.ts +1 -1
- package/lib/newsroom-organizer-nav.ts +2 -1
- package/lib/newsroom-references.ts +25 -1
- package/lib/notification-feed.ts +212 -0
- package/lib/proposals-client.ts +29 -0
- package/lib/reader-subject.ts +3 -2
- package/lib/reference-capture.ts +294 -0
- package/lib/reference-feed-cache.ts +170 -0
- package/lib/reference-feed-ranking.ts +236 -0
- package/lib/reference-policy.ts +90 -0
- package/lib/reference-preview.ts +112 -0
- package/lib/relevance-decisions.ts +6 -2
- package/lib/review-client.ts +71 -5
- package/lib/review-drafts.ts +277 -0
- package/lib/review-fixture.ts +56 -2
- package/lib/review-requests.ts +89 -24
- package/lib/site-brand.ts +2 -0
- package/lib/source-frameable.ts +77 -0
- package/lib/source-icon.ts +104 -0
- package/lib/staff-groups.ts +23 -0
- package/lib/staging-gate.ts +2 -2
- package/lib/story-reporting-trail.ts +33 -2
- package/package.json +45 -2
- package/routes.manifest.json +23 -1
- package/components/newsroom-overview-skeleton.tsx +0 -25
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FEED_SURFACE_PROPS } from "./reference-feed";
|
|
2
|
+
|
|
3
|
+
/** The board's loading state: three columns of pulsing cards in the feed's flat tones and rounded rectangles, with no outlines. */
|
|
4
|
+
export function NewsroomBoardSkeleton() {
|
|
5
|
+
return (
|
|
6
|
+
<div aria-busy="true" aria-label="Loading board records" className="grid w-full grid-cols-1 gap-3 sm:grid-cols-3" data-board-skeleton role="status" {...FEED_SURFACE_PROPS}>
|
|
7
|
+
{Array.from({ length: 3 }, (_, column) => (
|
|
8
|
+
<div className="min-h-64 space-y-3 rounded-[20px] bg-[var(--feed-footer)] p-4" key={column}>
|
|
9
|
+
<div className="h-4 w-1/2 animate-pulse rounded-full bg-[var(--feed-control)]" />
|
|
10
|
+
{Array.from({ length: 2 }, (_, row) => (
|
|
11
|
+
<div className="h-24 rounded-2xl bg-[var(--feed-card)] p-3" key={row}>
|
|
12
|
+
<div className="h-4 w-3/4 animate-pulse rounded-full bg-[var(--feed-control)]" />
|
|
13
|
+
<div className="mt-3 h-3 w-1/2 animate-pulse rounded-full bg-[var(--feed-control)]" />
|
|
14
|
+
</div>
|
|
15
|
+
))}
|
|
16
|
+
</div>
|
|
17
|
+
))}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -31,6 +31,7 @@ import type { ContentItemVersionRecord } from "../lib/content-item-lifecycle";
|
|
|
31
31
|
import { useOptionalNewsDeskClient } from "./news-desk-client-provider";
|
|
32
32
|
import { NewsDeskAccessGate } from "./newsroom-access-gate";
|
|
33
33
|
import { isLocalPreviewEnabled } from "../lib/local-preview";
|
|
34
|
+
import { NewsroomBoardSkeleton } from "./newsroom-board-skeleton";
|
|
34
35
|
import { NewsroomArticleEditor } from "./newsroom-article-editor";
|
|
35
36
|
import { NewsroomAssignmentDetail } from "./newsroom-assignment-detail";
|
|
36
37
|
import { NewsroomOpsShell, NewsroomOpsStatusBanner } from "./newsroom-ops-shell";
|
|
@@ -174,12 +175,7 @@ export function NewsroomBoardView({ subject, deskId }: { subject: NewsroomBoardS
|
|
|
174
175
|
{error && <NewsroomOpsStatusBanner tone="error">{error}</NewsroomOpsStatusBanner>}
|
|
175
176
|
{subject === "desk" && <IssueTypeFilter config={config} value={typeFilter} onChange={setTypeFilter} name="Record type" className="organizer-board-type-filter" />}
|
|
176
177
|
<div className="organizer-board-body" data-detail-open={Boolean(issue)} ref={boardBodyRef} onScrollCapture={handleBoardScroll}>
|
|
177
|
-
{loading && !issues.length ? <
|
|
178
|
-
{Array.from({ length: 3 }, (_, column) => <div className="min-h-64 space-y-3 rounded-xl border bg-card p-4" key={column}>
|
|
179
|
-
<div className="h-4 w-1/2 rounded bg-muted" />
|
|
180
|
-
{Array.from({ length: 2 }, (_, row) => <div className="h-24 rounded-lg border bg-background p-3" key={row}><div className="h-4 w-3/4 rounded bg-muted" /><div className="mt-3 h-3 w-1/2 rounded bg-muted" /></div>)}
|
|
181
|
-
</div>)}
|
|
182
|
-
</div> : <IssueCollection issues={issues} config={config} query={{ type: subject === "desk" ? issueTypeFromFilter(typeFilter) : boardType }} view={view}
|
|
178
|
+
{loading && !issues.length ? <NewsroomBoardSkeleton /> : <IssueCollection issues={issues} config={config} query={{ type: subject === "desk" ? issueTypeFromFilter(typeFilter) : boardType }} view={view}
|
|
183
179
|
motion={lowMotion ? STATIC_MOTION : undefined}
|
|
184
180
|
collapsedColumns={columnState.collapsedColumns} onToggleCollapse={columnState.toggleColumn} initialScroll="start"
|
|
185
181
|
selectedIssueId={selected} detailOpen={Boolean(issue)} onSelectIssue={item => setSelected(item.id)} ariaLabel={pageTitle}
|
|
@@ -2,13 +2,14 @@ import { NewsDeskClientProvider } from "./news-desk-client-provider";
|
|
|
2
2
|
import { createDemoCategorySteeringDashboard } from "../lib/category-repository";
|
|
3
3
|
import { resolveDevSandboxEditorAuth } from "../lib/dev-sandbox-editor-auth";
|
|
4
4
|
import { isLocalPreviewEnabled } from "../lib/local-preview";
|
|
5
|
+
import { withReferenceFeedFixture } from "../lib/local-preview-feed-fixture";
|
|
5
6
|
import { getBrandNewsroomSectionsConfigPath, resolveActiveSiteBrand } from "../lib/site-brand-tenant";
|
|
6
7
|
|
|
7
8
|
export function NewsroomClientShell({ children }: Readonly<{ children: React.ReactNode }>) {
|
|
8
9
|
const devSandboxEditorAuth = resolveDevSandboxEditorAuth();
|
|
9
10
|
const activeBrand = resolveActiveSiteBrand();
|
|
10
11
|
const localPreviewDashboard = isLocalPreviewEnabled()
|
|
11
|
-
? createDemoCategorySteeringDashboard(activeBrand.id, getBrandNewsroomSectionsConfigPath(activeBrand))
|
|
12
|
+
? withReferenceFeedFixture(createDemoCategorySteeringDashboard(activeBrand.id, getBrandNewsroomSectionsConfigPath(activeBrand)))
|
|
12
13
|
: null;
|
|
13
14
|
|
|
14
15
|
return (
|
|
@@ -2,18 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import Link from "next/link";
|
|
4
4
|
import { usePathname } from "next/navigation";
|
|
5
|
-
import { useMemo } from "react";
|
|
6
|
-
import { Badge } from "./ui/badge";
|
|
5
|
+
import { useCallback, useMemo } from "react";
|
|
7
6
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";
|
|
8
|
-
import type { AssignmentRecord, NewsroomSectionRecord, ReferenceRecord } from "../lib/category-repository";
|
|
7
|
+
import type { AssignmentRecord, NewsroomSectionRecord, ReferenceAttachmentRecord, ReferenceRecord } from "../lib/category-repository";
|
|
9
8
|
import { getNewsroomNavHref } from "../lib/newsroom-nav";
|
|
10
|
-
import {
|
|
11
|
-
filterReferencesByStatus,
|
|
12
|
-
formatReferenceListDate,
|
|
13
|
-
referenceDisplayTitle,
|
|
14
|
-
referenceLineageId,
|
|
15
|
-
selectCanonicalReferenceRecords,
|
|
16
|
-
} from "../lib/newsroom-references";
|
|
9
|
+
import { referenceLineageId, selectCanonicalReferenceRecords, type ReferenceCurationAction } from "../lib/newsroom-references";
|
|
17
10
|
import {
|
|
18
11
|
buildNewsroomSectionHref,
|
|
19
12
|
displayNewsroomSectionShortTitle,
|
|
@@ -21,9 +14,15 @@ import {
|
|
|
21
14
|
newsroomDeskKind,
|
|
22
15
|
sortNewsroomSections,
|
|
23
16
|
} from "../lib/newsroom-sections";
|
|
24
|
-
import {
|
|
17
|
+
import { cn } from "../lib/utils";
|
|
18
|
+
import { FEED_SURFACE_PROPS } from "./reference-feed";
|
|
25
19
|
import type { RelevanceDecisionView } from "../lib/relevance-decisions";
|
|
20
|
+
import type { ReferenceRejectionReasonCode } from "../lib/reference-policy";
|
|
21
|
+
import { referencePreviewsByLineage, type ReferencePreview } from "../lib/reference-preview";
|
|
22
|
+
import type { NotificationFixture } from "./notification-center";
|
|
26
23
|
import { NotificationCenter } from "./notification-center";
|
|
24
|
+
import type { CorrectCaptureAction } from "./reference-capture-client";
|
|
25
|
+
import type { ReviewChoice } from "./reference-review-card";
|
|
27
26
|
|
|
28
27
|
type NewsroomOpsOverviewProps = {
|
|
29
28
|
assignments: AssignmentRecord[];
|
|
@@ -33,26 +32,57 @@ type NewsroomOpsOverviewProps = {
|
|
|
33
32
|
humanCuratedReferenceLineageIds?: ReadonlySet<string>;
|
|
34
33
|
newsroomSections: NewsroomSectionRecord[];
|
|
35
34
|
references: ReferenceRecord[];
|
|
35
|
+
referenceAttachments?: ReferenceAttachmentRecord[];
|
|
36
|
+
/** True until the References have been read; a saved copy of the last view fills the page meanwhile. */
|
|
37
|
+
loading?: boolean;
|
|
38
|
+
savedCopy?: { references: ReferenceRecord[]; previews: Array<[string, ReferencePreview]>; decisions: Array<[string, RelevanceDecisionView]> } | null;
|
|
39
|
+
predictionState?: "loading" | "ready" | "error";
|
|
40
|
+
/** Words for why a rating cannot be saved right now, or null. */
|
|
41
|
+
disabledReason?: string | null;
|
|
42
|
+
onReview?: (reference: ReferenceRecord, action: ReferenceCurationAction, options?: { reasonCode?: ReferenceRejectionReasonCode | null; note?: string; decisionRelationId?: string; shareable?: boolean }) => Promise<void> | void;
|
|
43
|
+
/** Saves a pasted or corrected capture (the `correctReferenceCapture` action). Without it the capture panel has no edit action. */
|
|
44
|
+
onCorrectCapture?: CorrectCaptureAction;
|
|
45
|
+
/** Local real-data preview of the Notification Center (scripts/export-notification-center-fixture.py). */
|
|
46
|
+
notificationFixture?: NotificationFixture | null;
|
|
36
47
|
};
|
|
37
48
|
|
|
38
49
|
const NO_DECISIONS: ReadonlyMap<string, RelevanceDecisionView> = new Map();
|
|
39
|
-
const NO_IDS: ReadonlySet<string> = new Set();
|
|
40
50
|
|
|
41
51
|
export function NewsroomOpsOverview({
|
|
42
52
|
actorLabel = "",
|
|
43
53
|
assignments,
|
|
44
54
|
decisions = NO_DECISIONS,
|
|
45
55
|
demo = false,
|
|
46
|
-
humanCuratedReferenceLineageIds
|
|
56
|
+
humanCuratedReferenceLineageIds,
|
|
57
|
+
disabledReason = null,
|
|
58
|
+
loading = false,
|
|
47
59
|
newsroomSections,
|
|
60
|
+
notificationFixture = null,
|
|
61
|
+
onCorrectCapture,
|
|
62
|
+
onReview,
|
|
63
|
+
predictionState = "ready",
|
|
64
|
+
referenceAttachments = [],
|
|
48
65
|
references,
|
|
66
|
+
savedCopy = null,
|
|
49
67
|
}: NewsroomOpsOverviewProps) {
|
|
50
68
|
const pathname = usePathname();
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
);
|
|
69
|
+
const liveReferences = useMemo(() => selectCanonicalReferenceRecords(references), [references]);
|
|
70
|
+
// Until the live read arrives, a saved copy of the last view fills the page. It is display only.
|
|
71
|
+
const showingSavedCopy = loading && !liveReferences.length && Boolean(savedCopy?.references.length);
|
|
72
|
+
const canonicalReferences = showingSavedCopy ? savedCopy!.references : liveReferences;
|
|
73
|
+
const shownDecisions = useMemo(() => (showingSavedCopy && !decisions.size ? new Map(savedCopy!.decisions) : decisions), [decisions, savedCopy, showingSavedCopy]);
|
|
74
|
+
const previews = useMemo(() => {
|
|
75
|
+
const live = referencePreviewsByLineage(referenceAttachments);
|
|
76
|
+
return showingSavedCopy && !live.size ? new Map(savedCopy!.previews) : live;
|
|
77
|
+
}, [referenceAttachments, savedCopy, showingSavedCopy]);
|
|
78
|
+
const rateReference = useCallback(async (reference: ReferenceRecord, choice: ReviewChoice, reasonCode: ReferenceRejectionReasonCode | null, note?: string) => {
|
|
79
|
+
const decision = shownDecisions.get(referenceLineageId(reference));
|
|
80
|
+
await onReview?.(reference, choice, {
|
|
81
|
+
reasonCode: choice === "reject" ? reasonCode : null,
|
|
82
|
+
...(note ? { note } : {}),
|
|
83
|
+
...(decision ? { decisionRelationId: decision.decisionRelationId, shareable: false } : {}),
|
|
84
|
+
});
|
|
85
|
+
}, [onReview, shownDecisions]);
|
|
56
86
|
const attentionAssignments = useMemo(
|
|
57
87
|
() => assignments
|
|
58
88
|
.filter((assignment) => {
|
|
@@ -68,58 +98,21 @@ export function NewsroomOpsOverview({
|
|
|
68
98
|
);
|
|
69
99
|
const coreDesks = useMemo(() => desks.filter(desk => newsroomDeskKind(desk) === "core"), [desks]);
|
|
70
100
|
const rotatingDesks = useMemo(() => desks.filter(desk => newsroomDeskKind(desk) === "rotating"), [desks]);
|
|
101
|
+
const rateDisabled = disabledReason ?? (showingSavedCopy ? "Confirming your sign-in. You can answer in a moment." : null);
|
|
71
102
|
|
|
72
|
-
|
|
73
|
-
<div
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
>
|
|
78
|
-
<div className="space-y-8" data-newsroom-overview-feeds>
|
|
79
|
-
<div aria-label="Notification Center feed" className="newsroom-overview-feed-frame rounded-xl border bg-card p-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" data-newsroom-overview-notifications role="region" tabIndex={0}>
|
|
80
|
-
<NotificationCenter
|
|
81
|
-
actorLabel={actorLabel}
|
|
82
|
-
decisions={decisions}
|
|
83
|
-
demo={demo}
|
|
84
|
-
humanCuratedReferenceLineageIds={humanCuratedReferenceLineageIds}
|
|
85
|
-
references={canonicalReferences}
|
|
86
|
-
/>
|
|
87
|
-
</div>
|
|
88
|
-
<section aria-label="Needs attention" className="space-y-3">
|
|
89
|
-
<h2 className="text-sm font-medium text-muted-foreground">Needs attention</h2>
|
|
90
|
-
{pendingReferences.length || attentionAssignments.length ? (
|
|
103
|
+
const below = (
|
|
104
|
+
<div className="space-y-12 pt-6" data-newsroom-overview-below {...FEED_SURFACE_PROPS}>
|
|
105
|
+
{attentionAssignments.length ? (
|
|
106
|
+
<section aria-label="Open assignments" className="space-y-3">
|
|
107
|
+
<h2 className="text-sm font-medium text-muted-foreground">Open assignments</h2>
|
|
91
108
|
<div className="space-y-2">
|
|
92
|
-
{pendingReferences.map((reference) => {
|
|
93
|
-
const lineageId = referenceLineageId(reference);
|
|
94
|
-
const href = getNewsroomNavHref(`/newsroom/references/${encodeURIComponent(lineageId)}`, demo);
|
|
95
|
-
const active = pathname === href || pathname.startsWith(`${href}/`);
|
|
96
|
-
return (
|
|
97
|
-
<Link
|
|
98
|
-
aria-current={active ? "true" : undefined}
|
|
99
|
-
className={newsroomInboxRowClassName(active)}
|
|
100
|
-
data-newsroom-inbox-item="reference"
|
|
101
|
-
data-newsroom-list-row
|
|
102
|
-
data-selected={active || undefined}
|
|
103
|
-
data-newsroom-card
|
|
104
|
-
data-newsroom-card-id={lineageId}
|
|
105
|
-
href={href}
|
|
106
|
-
key={lineageId}
|
|
107
|
-
>
|
|
108
|
-
<div className="min-w-0 flex-1">
|
|
109
|
-
<p className="truncate text-sm font-medium text-foreground">{referenceDisplayTitle(reference)}</p>
|
|
110
|
-
<p className="text-xs text-muted-foreground">Review source intake · {formatReferenceListDate(reference)}</p>
|
|
111
|
-
</div>
|
|
112
|
-
<Badge className="mt-0.5 shrink-0" variant="outline">Pending</Badge>
|
|
113
|
-
</Link>
|
|
114
|
-
);
|
|
115
|
-
})}
|
|
116
109
|
{attentionAssignments.map((assignment) => {
|
|
117
110
|
const href = getNewsroomNavHref(`/newsroom/assignments/${encodeURIComponent(assignment.id)}`, demo);
|
|
118
111
|
const active = pathname === href || pathname.startsWith(`${href}/`);
|
|
119
112
|
return (
|
|
120
113
|
<Link
|
|
121
114
|
aria-current={active ? "true" : undefined}
|
|
122
|
-
className={
|
|
115
|
+
className={cn("flex items-start gap-3 rounded-[16px] bg-[var(--feed-card)] p-3 text-foreground outline-none transition-colors hover:bg-[var(--feed-control)] focus-visible:ring-2 focus-visible:ring-ring", active && "bg-[var(--feed-control)]")}
|
|
123
116
|
data-newsroom-inbox-item="assignment"
|
|
124
117
|
data-newsroom-list-row
|
|
125
118
|
data-selected={active || undefined}
|
|
@@ -130,19 +123,13 @@ export function NewsroomOpsOverview({
|
|
|
130
123
|
<p className="truncate text-sm font-medium text-foreground">{assignment.title}</p>
|
|
131
124
|
<p className="text-xs text-muted-foreground">Assignment · {assignment.assignmentTypeKey}</p>
|
|
132
125
|
</div>
|
|
133
|
-
<
|
|
126
|
+
<span className="mt-0.5 shrink-0 rounded-full bg-[var(--feed-control)] px-2 py-0.5 text-xs font-medium">{assignment.status}</span>
|
|
134
127
|
</Link>
|
|
135
128
|
);
|
|
136
129
|
})}
|
|
137
130
|
</div>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
<CardContent className="p-4 text-sm text-muted-foreground">
|
|
141
|
-
No pending references or open assignments. Check those destinations for other work.
|
|
142
|
-
</CardContent>
|
|
143
|
-
</Card>
|
|
144
|
-
)}
|
|
145
|
-
</section>
|
|
131
|
+
</section>
|
|
132
|
+
) : null}
|
|
146
133
|
|
|
147
134
|
{desks.length ? (
|
|
148
135
|
<section aria-label="Sections" className="space-y-3" data-newsroom-ops-desks>
|
|
@@ -156,7 +143,7 @@ export function NewsroomOpsOverview({
|
|
|
156
143
|
href={buildNewsroomSectionHref(section.id, demo)}
|
|
157
144
|
key={section.id}
|
|
158
145
|
>
|
|
159
|
-
<Card className="h-full transition-colors hover:
|
|
146
|
+
<Card className="h-full rounded-[20px] border-0 bg-[var(--feed-card)] shadow-none ring-0 transition-colors hover:bg-[var(--feed-control)]">
|
|
160
147
|
<CardHeader className="p-4">
|
|
161
148
|
<CardTitle className="text-base font-semibold">{section.title}</CardTitle>
|
|
162
149
|
<CardDescription className="uppercase tracking-wide text-[0.65rem]">
|
|
@@ -176,7 +163,7 @@ export function NewsroomOpsOverview({
|
|
|
176
163
|
href={buildNewsroomSectionHref(section.id, demo)}
|
|
177
164
|
key={section.id}
|
|
178
165
|
>
|
|
179
|
-
<Card className="h-full transition-colors hover:
|
|
166
|
+
<Card className="h-full rounded-[20px] border-0 bg-[var(--feed-card)] shadow-none ring-0 transition-colors hover:bg-[var(--feed-control)]">
|
|
180
167
|
<CardHeader className="p-4">
|
|
181
168
|
<CardTitle className="text-base font-semibold">{section.title}</CardTitle>
|
|
182
169
|
<CardDescription className="uppercase tracking-wide text-[0.65rem]">
|
|
@@ -189,6 +176,34 @@ export function NewsroomOpsOverview({
|
|
|
189
176
|
</div> : null}
|
|
190
177
|
</section>
|
|
191
178
|
) : null}
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<div
|
|
184
|
+
className="h-full font-sans"
|
|
185
|
+
data-news-desk-section="overview"
|
|
186
|
+
data-newsroom-ops-home="true"
|
|
187
|
+
>
|
|
188
|
+
<div className="h-full" data-newsroom-overview-feeds>
|
|
189
|
+
<div className="h-full" data-newsroom-overview-notifications>
|
|
190
|
+
<NotificationCenter
|
|
191
|
+
below={below}
|
|
192
|
+
actorLabel={actorLabel}
|
|
193
|
+
decisions={shownDecisions}
|
|
194
|
+
demo={demo}
|
|
195
|
+
fixture={notificationFixture}
|
|
196
|
+
humanCuratedReferenceLineageIds={humanCuratedReferenceLineageIds}
|
|
197
|
+
onCorrectCapture={onCorrectCapture}
|
|
198
|
+
onRateReference={rateReference}
|
|
199
|
+
referenceAttachments={referenceAttachments}
|
|
200
|
+
predictionLoading={predictionState === "loading"}
|
|
201
|
+
previews={previews}
|
|
202
|
+
referenceDisabledReason={rateDisabled}
|
|
203
|
+
references={canonicalReferences}
|
|
204
|
+
referencesLoading={loading && !canonicalReferences.length}
|
|
205
|
+
/>
|
|
206
|
+
</div>
|
|
192
207
|
</div>
|
|
193
208
|
</div>
|
|
194
209
|
);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { SearchIcon } from "lucide-react";
|
|
4
3
|
import { Button } from "./ui/button";
|
|
5
4
|
import { Separator } from "./ui/separator";
|
|
6
5
|
import { cn } from "../lib/utils";
|
|
@@ -143,6 +142,8 @@ export function NewsroomOpsShell({ activeTab, appTitle, backHref = "/", backLabe
|
|
|
143
142
|
media.addEventListener("change", change);
|
|
144
143
|
return () => { document.removeEventListener("focusin", remember); media.removeEventListener("change", change); cancelAnimationFrame(frame); };
|
|
145
144
|
}, []);
|
|
145
|
+
// The mobile top bar prefers the brand's compact mark, then scales the full logo; the serif title is the no-logo fallback.
|
|
146
|
+
const MastheadLogo = SITE_BRAND.components?.NewsroomLogoCompact ?? SITE_BRAND.components?.NewsroomLogo;
|
|
146
147
|
const activePath = browserPathToInternalNewsroomPath(pathname ?? "/newsroom");
|
|
147
148
|
const sidebarToggleLabel = collapsed ? "Expand sidebar" : "Collapse sidebar";
|
|
148
149
|
const sidebarToggle = <button type="button" className="organizer-toggle" title={sidebarToggleLabel}
|
|
@@ -162,10 +163,10 @@ export function NewsroomOpsShell({ activeTab, appTitle, backHref = "/", backLabe
|
|
|
162
163
|
<div className="organizer-workspace">
|
|
163
164
|
<header className="organizer-topbar" data-newsroom-ops-topbar>
|
|
164
165
|
{showNavigation && collapsed && sidebarToggle}
|
|
165
|
-
<Link className="organizer-masthead" href={backHref} title={backLabel}>{appTitle}</Link>
|
|
166
|
+
<Link className="organizer-masthead" href={backHref} title={backLabel}>{MastheadLogo ? <MastheadLogo className="organizer-masthead-logo" /> : appTitle}</Link>
|
|
166
167
|
<h1 data-newsroom-ops-title>{pageTitle}</h1><OrganizerSearch demo={demo} /><div className="organizer-header-actions">{headerActions}</div><Account placement="header" />
|
|
167
168
|
</header>
|
|
168
|
-
<main className="organizer-main">{demo && <p className="organizer-demo-notice">Demo workspace · synthetic examples</p>}{children}</main>
|
|
169
|
+
<main className="organizer-main">{demo && !session?.shell.dashboard?.realDataPreview && <p className="organizer-demo-notice">Demo workspace · synthetic examples</p>}{children}</main>
|
|
169
170
|
</div>
|
|
170
171
|
{showNavigation && <NewsroomMobileNavigation activeTab={activeTab} items={ORGANIZER_PRIMARY_NAV.map(item => ({ ...item, href: getNewsroomNavHref(item.path, demo) }))}
|
|
171
172
|
chat={consoleState?.shouldOfferConsole ? { open: consoleState.open, onOpen: consoleState.openConsole } : undefined}
|
|
@@ -177,27 +178,6 @@ export function NewsroomOpsShell({ activeTab, appTitle, backHref = "/", backLabe
|
|
|
177
178
|
</div>;
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
export function NewsroomOpsSearchButton({
|
|
181
|
-
disabled,
|
|
182
|
-
onPress,
|
|
183
|
-
}: {
|
|
184
|
-
disabled?: boolean;
|
|
185
|
-
onPress?: () => void;
|
|
186
|
-
}) {
|
|
187
|
-
return (
|
|
188
|
-
<Button
|
|
189
|
-
aria-label="Search knowledge base"
|
|
190
|
-
disabled={disabled}
|
|
191
|
-
onClick={onPress}
|
|
192
|
-
size="icon-sm"
|
|
193
|
-
type="button"
|
|
194
|
-
variant="outline"
|
|
195
|
-
>
|
|
196
|
-
<SearchIcon className="size-4" />
|
|
197
|
-
</Button>
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
181
|
export function NewsroomOpsStatusBanner({
|
|
202
182
|
children,
|
|
203
183
|
tone = "info",
|
|
@@ -208,10 +188,10 @@ export function NewsroomOpsStatusBanner({
|
|
|
208
188
|
return (
|
|
209
189
|
<div
|
|
210
190
|
className={cn(
|
|
211
|
-
|
|
212
|
-
tone === "
|
|
213
|
-
tone === "
|
|
214
|
-
tone === "info" && "
|
|
191
|
+
// A success is announced to screen readers and never drawn: it would push the page down. Errors and notes are flat fills, no outlines.
|
|
192
|
+
tone === "ok" ? "sr-only" : "mb-4 rounded-lg px-3 py-2 text-sm",
|
|
193
|
+
tone === "error" && "bg-destructive/10 text-destructive",
|
|
194
|
+
tone === "info" && "bg-muted/60 text-foreground",
|
|
215
195
|
)}
|
|
216
196
|
role="status"
|
|
217
197
|
>
|
|
@@ -16,15 +16,14 @@ body:has(.newsroom-organizer)>[data-staging-banner]{flex-shrink:0}
|
|
|
16
16
|
.organizer-destinations a[aria-current=page]{color:var(--org-ink);box-shadow:inset 3px 0 0 var(--org-accent)}
|
|
17
17
|
.newsroom-organizer :is(a,button):focus-visible,.organizer-menu :is(a,button):focus-visible{outline:2px solid currentColor;outline-offset:-3px}
|
|
18
18
|
.organizer-workspace{display:flex;flex-direction:column;min-height:0;min-width:0;overflow:hidden;padding:0 16px}
|
|
19
|
-
.organizer-topbar{height:48px;min-height:48px;display:flex;align-items:center;gap:16px
|
|
19
|
+
.organizer-topbar{height:48px;min-height:48px;display:flex;align-items:center;gap:16px}
|
|
20
20
|
.organizer-masthead{font:900 28px var(--font-wordmark),Georgia,serif;white-space:nowrap;max-width:30vw;overflow:hidden;text-overflow:ellipsis}
|
|
21
|
+
.organizer-masthead-logo{display:block;height:24px;width:auto;max-width:36vw;overflow:visible}
|
|
21
22
|
.organizer-topbar h1{font:400 12px var(--kb-theme-ui-font);flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}
|
|
22
23
|
.organizer-toggle{display:flex;align-items:center;justify-content:center;width:36px;min-height:36px;padding:0;border:1px solid var(--org-line);flex-shrink:0}
|
|
23
24
|
.organizer-sidebar-head{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.organizer-sidebar-head .organizer-brand{flex:1;min-width:0}
|
|
24
25
|
.organizer-header-actions{display:flex;align-items:center;gap:8px;min-width:0;max-width:45%;overflow-x:auto}
|
|
25
26
|
.organizer-main{min-width:0;min-height:0;overflow:auto;overscroll-behavior:contain;flex:1;padding:16px 0}
|
|
26
|
-
.newsroom-overview-feed-frame{height:auto}
|
|
27
|
-
@media(min-width:640px){.newsroom-overview-feed-frame{height:38rem;overflow-y:auto}}
|
|
28
27
|
.organizer-main>[data-category-steering]{min-height:0}.organizer-demo-notice{font-size:11px;color:var(--org-muted);margin-bottom:12px}
|
|
29
28
|
.organizer-account{display:flex;align-items:center;gap:10px;min-height:44px;flex-shrink:0;border:1px solid var(--org-line);padding:8px;text-align:left;border-radius:3px}
|
|
30
29
|
.organizer-account span{min-width:0}.organizer-account strong{display:block;font:600 11px var(--kb-theme-ui-font);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.organizer-account small{display:block;font-size:9px;color:var(--org-muted);margin-top:2px}
|
|
@@ -35,6 +34,17 @@ body:has(.newsroom-organizer)>[data-staging-banner]{flex-shrink:0}
|
|
|
35
34
|
.organizer-bottom-nav{display:none}
|
|
36
35
|
.organizer-bottom-nav button{appearance:none;border:0;background:transparent;color:inherit}
|
|
37
36
|
.organizer-main:has(.organizer-native-board){display:flex;overflow:hidden}
|
|
37
|
+
@media (min-width:768px){
|
|
38
|
+
.organizer-main:has(>[data-category-steering]>[data-news-desk-section=references]){display:flex;flex-direction:column;overflow:hidden;padding-bottom:0}
|
|
39
|
+
.organizer-main>[data-category-steering]:has(>[data-news-desk-section=references]){display:flex;flex-direction:column;flex:1;min-height:0}
|
|
40
|
+
.organizer-main:has(>[data-category-steering]>[data-newsroom-ops-home]){display:flex;flex-direction:column;overflow:hidden;padding-bottom:0}
|
|
41
|
+
.organizer-main>[data-category-steering]:has(>[data-newsroom-ops-home]){display:flex;flex-direction:column;flex:1;min-height:0}
|
|
42
|
+
[data-newsroom-ops-home]{display:flex;flex-direction:column;flex:1;min-height:0;overflow-y:auto}
|
|
43
|
+
[data-newsroom-ops-home]>[data-newsroom-overview-feeds]{display:contents}
|
|
44
|
+
[data-newsroom-overview-notifications]{display:flex;flex-direction:column;flex:0 0 100%;min-height:0}
|
|
45
|
+
[data-newsroom-overview-notifications]>[data-notification-center]{flex:1;min-height:0}
|
|
46
|
+
[data-newsroom-overview-feeds]>:not([data-newsroom-overview-notifications]){flex:none}
|
|
47
|
+
}
|
|
38
48
|
.organizer-native-board{display:flex;flex-direction:column;flex:1;min-height:0;min-width:0;gap:8px}
|
|
39
49
|
.organizer-board-view-toggle{display:flex;gap:4px;flex-shrink:0}
|
|
40
50
|
.organizer-header-button{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:4px 12px;border:1px solid var(--org-line);font:inherit;color:inherit;background:transparent;text-decoration:none;white-space:nowrap;cursor:pointer}
|
|
@@ -184,6 +194,17 @@ body:has(.newsroom-organizer)>[data-staging-banner]{flex-shrink:0}
|
|
|
184
194
|
.story-trail-row{display:flex;flex-wrap:wrap;gap:8px;align-items:baseline}
|
|
185
195
|
.story-trail-meta,.story-trail-empty{font-size:12px;color:var(--org-muted);margin:0}
|
|
186
196
|
.story-trail-chip{font-size:11px;border:1px solid var(--org-ink);padding:0 6px;text-transform:uppercase;letter-spacing:.04em}
|
|
197
|
+
.story-trail-reference{display:grid;grid-template-columns:minmax(0,96px) minmax(0,1fr);gap:12px;align-items:start;background:color-mix(in srgb,var(--org-ink) 6%,transparent);border-radius:10px;padding:12px}
|
|
198
|
+
.story-trail-reference:not(:has(.story-trail-reference-image)){grid-template-columns:minmax(0,1fr)}
|
|
199
|
+
.story-trail-reference-image{width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:8px;background:color-mix(in srgb,var(--org-ink) 10%,transparent)}
|
|
200
|
+
.story-trail-reference-text{display:grid;gap:4px;min-width:0}
|
|
201
|
+
.story-trail-reference-links{display:flex;flex-wrap:wrap;gap:4px 16px;font-size:13px}
|
|
202
|
+
.story-trail-reference-links a,.reference-stories a{display:inline-flex;align-items:center;gap:4px}
|
|
203
|
+
.story-trail-role{display:inline-flex;align-items:center;gap:4px;font-size:11px;text-transform:uppercase;letter-spacing:.04em;background:color-mix(in srgb,var(--org-ink) 12%,transparent);border-radius:999px;padding:1px 8px}
|
|
204
|
+
.reference-stories{display:grid;gap:8px}
|
|
205
|
+
.reference-stories h3{margin:0;font-size:14px;font-weight:500}
|
|
206
|
+
.reference-stories ul{list-style:none;margin:0;padding:0;display:grid;gap:8px}
|
|
207
|
+
.reference-stories li{display:flex;flex-wrap:wrap;gap:4px 12px;align-items:center;background:color-mix(in srgb,var(--org-ink) 6%,transparent);border-radius:10px;padding:10px 12px}
|
|
187
208
|
.story-trail-message pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:6px 0 0;font-size:12px;max-height:320px;overflow:auto}
|
|
188
209
|
.story-trail-message summary{cursor:pointer;font-size:13px}
|
|
189
210
|
@container (min-width:900px){.story-trail{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:32px;align-items:start}}
|
|
@@ -347,3 +368,106 @@ body:has(.newsroom-organizer)>[data-staging-banner]{flex-shrink:0}
|
|
|
347
368
|
.news-desk-columns--administration .news-desk-newsletter__text{margin:0;padding:12px;max-height:280px;overflow:auto;border:1px solid var(--org-line);font:400 12px/1.5 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere}
|
|
348
369
|
.news-desk-columns--administration .news-desk-newsletter__filters{display:flex;flex-wrap:wrap;gap:12px 24px}
|
|
349
370
|
.news-desk-columns--administration .news-desk-newsletter__filters .news-desk-doctrine-card__field{min-width:180px}
|
|
371
|
+
|
|
372
|
+
/* The References feed is rounded and borderless (Ryan's design rule): flat tones and rounded rectangles instead of lines and boxes.
|
|
373
|
+
The newsroom chrome squares every "rounded" class above; inside a [data-feed-surface] the rounded classes mean what they say.
|
|
374
|
+
The repeated attribute raises specificity over the squaring rules without !important escalation. */
|
|
375
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface] [class*="rounded-full"],
|
|
376
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface][class*="rounded-full"] { border-radius: var(--feed-radius-pill) !important; }
|
|
377
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface] [class*="rounded-[20px]"],
|
|
378
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface][class*="rounded-[20px]"] { border-radius: var(--feed-radius-lg) !important; }
|
|
379
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface] [class*="rounded-2xl"],
|
|
380
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface][class*="rounded-2xl"] { border-radius: var(--feed-radius-md) !important; }
|
|
381
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface] [class*="rounded-[16px]"],
|
|
382
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface][class*="rounded-[16px]"] { border-radius: var(--feed-radius-md) !important; }
|
|
383
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface] [class*="rounded-3xl"],
|
|
384
|
+
.newsroom-organizer[data-kanbus-theme] [data-feed-surface][data-feed-surface][data-feed-surface][class*="rounded-3xl"] { border-radius: var(--feed-radius-xl) !important; }
|
|
385
|
+
|
|
386
|
+
/* The mobile sheet is portaled outside .newsroom-organizer; it carries the theme attributes itself, so the same radii apply inside it. */
|
|
387
|
+
[data-kanbus-theme][data-feed-surface] [class*="rounded-full"] { border-radius: var(--feed-radius-pill) !important; }
|
|
388
|
+
[data-kanbus-theme][data-feed-surface] [class*="rounded-[20px]"] { border-radius: var(--feed-radius-lg) !important; }
|
|
389
|
+
[data-kanbus-theme][data-feed-surface] [class*="rounded-2xl"], [data-kanbus-theme][data-feed-surface] [class*="rounded-[16px]"] { border-radius: var(--feed-radius-md) !important; }
|
|
390
|
+
[data-kanbus-theme][data-feed-surface] [class*="rounded-3xl"] { border-radius: var(--feed-radius-xl) !important; }
|
|
391
|
+
|
|
392
|
+
/* Feed tones. Light: cards a touch lighter than the page, footers between, controls a touch darker. Dark: each step lifts toward the ink.
|
|
393
|
+
Also set on the portaled mobile sheet, which carries the theme attributes itself. */
|
|
394
|
+
[data-kanbus-theme] [data-feed-surface], [data-kanbus-theme][data-feed-surface] {
|
|
395
|
+
--feed-card: color-mix(in oklab, var(--kb-theme-paper) 35%, white);
|
|
396
|
+
--feed-footer: color-mix(in oklab, var(--kb-theme-paper) 70%, white);
|
|
397
|
+
--feed-control: color-mix(in oklab, var(--kb-theme-paper) 90%, var(--kb-theme-ink));
|
|
398
|
+
/* Corner radii of the whole feed layer, in one place (Ryan, 2026-10-27: half of the first design). lg: cards and the detail pane;
|
|
399
|
+
md: rating cells, buttons, textareas; xl: sheets; pill: chips, filters and toggles (a rounded rectangle, not a capsule). */
|
|
400
|
+
--feed-radius-xl: 12px;
|
|
401
|
+
--feed-radius-lg: 10px;
|
|
402
|
+
--feed-radius-md: 8px;
|
|
403
|
+
--feed-radius-pill: 8px;
|
|
404
|
+
/* Verdict tones for the rating grid. Hue is never the only signal: the cell also carries a CircleCheck or
|
|
405
|
+
CircleX and the word Match or Miss. Named here, in the feed layer, because the component must not hold
|
|
406
|
+
literal palette values and because Tailwind's dark: variant (.dark *) never fires in this app. */
|
|
407
|
+
--feed-verdict-match-tint: #05966933;
|
|
408
|
+
--feed-verdict-match-ink: #064e3b;
|
|
409
|
+
--feed-verdict-match-fill: #059669;
|
|
410
|
+
--feed-verdict-miss-tint: #dc262633;
|
|
411
|
+
--feed-verdict-miss-ink: #7f1d1d;
|
|
412
|
+
--feed-verdict-miss-fill: #dc2626;
|
|
413
|
+
/* The quiet step for an unpredicted cell and a switched-off button. */
|
|
414
|
+
--feed-quiet: 0.6;
|
|
415
|
+
}
|
|
416
|
+
[data-kanbus-theme][data-color-mode="dark"] [data-feed-surface], [data-kanbus-theme][data-color-mode="dark"][data-feed-surface] {
|
|
417
|
+
--feed-card: color-mix(in oklab, var(--kb-theme-paper) 94%, var(--kb-theme-ink));
|
|
418
|
+
--feed-footer: color-mix(in oklab, var(--kb-theme-paper) 90%, var(--kb-theme-ink));
|
|
419
|
+
--feed-control: color-mix(in oklab, var(--kb-theme-paper) 80%, var(--kb-theme-ink));
|
|
420
|
+
/* Dark verdicts lift toward the tint rather than down into it, so the ink reads on a dark card. */
|
|
421
|
+
--feed-verdict-match-tint: #34d39933;
|
|
422
|
+
--feed-verdict-match-ink: #d1fae5;
|
|
423
|
+
--feed-verdict-match-fill: #34d399;
|
|
424
|
+
--feed-verdict-miss-tint: #f8717133;
|
|
425
|
+
--feed-verdict-miss-ink: #fee2e2;
|
|
426
|
+
--feed-verdict-miss-fill: #f87171;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* Borderless detail pane, Add panel and mobile sheet ([data-feed-flat]): no border, rule or box anywhere inside. Regions are told apart
|
|
430
|
+
by tone (card, footer, control) and shapes are rounded rectangles. The repeated attribute outranks the newsroom chrome's own rules. */
|
|
431
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat],
|
|
432
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] * { border-width: 0 !important; }
|
|
433
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] *:not(:focus-visible) { box-shadow: none; }
|
|
434
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] :is([data-slot=separator], hr) { display: none !important; }
|
|
435
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] :is(button, [role=button], [data-slot=badge]):not([aria-pressed=true]):not([data-slot=sheet-close]):not([class*="hover:bg-muted"]) {
|
|
436
|
+
background: var(--feed-control) !important; border-radius: var(--feed-radius-pill) !important; color: var(--foreground, inherit);
|
|
437
|
+
}
|
|
438
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] :is(button, [role=button])[aria-pressed=true]:not([class*="destructive"]) {
|
|
439
|
+
background: var(--primary) !important; color: var(--primary-foreground) !important; border-radius: var(--feed-radius-pill) !important;
|
|
440
|
+
}
|
|
441
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] :is(button, [role=button])[aria-pressed=true][class*="destructive"] { border-radius: var(--feed-radius-pill) !important; }
|
|
442
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] :is(textarea, input:not([type=radio]):not([type=checkbox]), select, details, [data-cyclotron-choice]:not([data-predicted])) {
|
|
443
|
+
background: var(--feed-control) !important; border-radius: 16px !important;
|
|
444
|
+
}
|
|
445
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] [data-cyclotron-choice] { border-radius: var(--feed-radius-pill) !important; }
|
|
446
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] [data-review-queue-bar] { background: var(--feed-footer) !important; }
|
|
447
|
+
/* The decision control keeps one corner across its segments and its reason field, and its predicted segment
|
|
448
|
+
keeps its tones apart: the flat rules above give every unpressed button the same control fill, which would
|
|
449
|
+
leave the predicted side and an untouched side looking identical. */
|
|
450
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] [data-decision-control] :is(button, textarea) { border-radius: var(--feed-radius-md) !important; }
|
|
451
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] [data-decision-control] [data-review-choice][data-state="idle"] { background: color-mix(in oklab, var(--feed-control) 45%, transparent) !important; }
|
|
452
|
+
|
|
453
|
+
/* The rating grid keeps its own rounded rectangles in the borderless panes (not the pill shape the flat rules give other buttons). */
|
|
454
|
+
[data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat][data-feed-flat] [data-rating-grid] :is(button, [data-cyclotron-choice]) { border-radius: var(--feed-radius-md) !important; }
|
|
455
|
+
|
|
456
|
+
/* Flat chrome (Ryan, 2026-10-28): the shell has no outlines or rules either. Controls are tone fills in rounded rectangles; on a phone the
|
|
457
|
+
page's own heading names the page, so the bar keeps one search field and the account button, nothing cut off. */
|
|
458
|
+
.newsroom-organizer,.organizer-menu,.organizer-account-popup{--org-control:color-mix(in oklab,var(--org-paper) 90%,var(--org-ink))}
|
|
459
|
+
.organizer-sidebar{border-right:0}
|
|
460
|
+
.organizer-search{border-bottom:0;background:var(--org-control);border-radius:8px;padding:6px 10px}
|
|
461
|
+
.newsroom-organizer button.organizer-toggle,.newsroom-organizer button.organizer-account{border:0;background:var(--org-control);border-radius:8px !important}
|
|
462
|
+
.organizer-account-popup{border:0}
|
|
463
|
+
.organizer-menu .organizer-destinations a{border:0;background:var(--org-control);border-radius:8px !important}
|
|
464
|
+
@media(max-width:900px){
|
|
465
|
+
.organizer-topbar h1{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
466
|
+
.organizer-search{flex:1;max-width:none}
|
|
467
|
+
.organizer-header-settings{display:none}
|
|
468
|
+
.organizer-bottom-nav{border-top:0;background:color-mix(in oklab,var(--org-paper) 95%,var(--org-ink))}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/* Captured text in the reference detail reads in the feed's own type, not the analysis view's serif and small caps. */
|
|
472
|
+
[data-capture-text] .reference-capture-markdown,[data-capture-text] .reference-capture-markdown :is(h1,h2,h3,h4,h5,h6,p,li,th,td){font-family:inherit;letter-spacing:normal;text-transform:none}
|
|
473
|
+
[data-capture-text] .reference-capture-markdown :is(h3,h4,h5){font-size:1em;font-weight:600;margin:1em 0 .25em}
|