pierre-review 0.1.32 → 0.1.34
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/dist/api/routes/me.js +2 -1
- package/dist/api/routes/prs.js +66 -0
- package/dist/db/queries.js +88 -5
- package/dist/db/schema.pg.js +1 -1
- package/dist/db/schema.sqlite.js +1 -1
- package/dist/db/triage.js +37 -15
- package/dist/github/client.js +17 -0
- package/dist/sync/upsert.js +22 -5
- package/package.json +1 -1
- package/public/assets/index-3IRHhCY3.css +10 -0
- package/public/assets/{index-Jpff0GIg.js → index-V649ti9W.js} +93 -93
- package/public/assets/perfProbe-Da13EhTE.js +1 -0
- package/public/index.html +2 -2
- package/public/assets/index-Df7dQP0l.css +0 -10
package/dist/api/routes/me.js
CHANGED
|
@@ -10,7 +10,7 @@ const dismissSchema = {
|
|
|
10
10
|
properties: {
|
|
11
11
|
kind: {
|
|
12
12
|
type: 'string',
|
|
13
|
-
enum: ['review_request', 'thread', 'watched_repo_pr', 'claude_review'],
|
|
13
|
+
enum: ['review_request', 'thread', 'watched_repo_pr', 'pr_approved', 'claude_review'],
|
|
14
14
|
},
|
|
15
15
|
refId: { type: 'integer' },
|
|
16
16
|
},
|
|
@@ -25,6 +25,7 @@ export async function meRoutes(app) {
|
|
|
25
25
|
counts: {
|
|
26
26
|
awaitingReview: myTurn.awaitingReview.length,
|
|
27
27
|
yourPrsActivity: myTurn.yourPrs.length,
|
|
28
|
+
approvedPrs: myTurn.approvedPrs.length,
|
|
28
29
|
threadsAwaiting: myTurn.threadsAwaiting.length,
|
|
29
30
|
watchedRepoPrs: myTurn.watchedRepoPrs.length,
|
|
30
31
|
claudeReviewsToAction: myTurn.claudeReviewsToAction.length,
|
package/dist/api/routes/prs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { getAccessToken, getAccountUserId } from '../../auth/account.js';
|
|
3
|
+
import { ghRestGetText } from '../../github/client.js';
|
|
3
4
|
import { getPrDetail, getPrFilesContext, getPrWriteContext, markAllViewed, markPrViewed, upsertLocalPrComment, upsertLocalReview, } from '../../db/queries.js';
|
|
4
5
|
import { buildFileAnchors, fallbackAnchor, isFindingAnchored, } from '../../github/diff-anchor.js';
|
|
5
6
|
import { addIssueComment, fetchHeadShaFor, fetchPrFilesWithPatch, postInlineComment, submitPrReview, } from '../../github/mutations.js';
|
|
@@ -33,6 +34,20 @@ const idParamSchema = {
|
|
|
33
34
|
properties: { id: { type: 'integer' } },
|
|
34
35
|
},
|
|
35
36
|
};
|
|
37
|
+
const checkLogsSchema = {
|
|
38
|
+
params: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
required: ['id', 'jobId'],
|
|
41
|
+
properties: {
|
|
42
|
+
id: { type: 'integer' },
|
|
43
|
+
jobId: { type: 'integer', minimum: 1 },
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
querystring: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: { tail: { type: 'integer', minimum: 1, maximum: 1000 } },
|
|
49
|
+
},
|
|
50
|
+
};
|
|
36
51
|
const markViewedSchema = {
|
|
37
52
|
...idParamSchema,
|
|
38
53
|
body: {
|
|
@@ -312,5 +327,56 @@ export async function prRoutes(app) {
|
|
|
312
327
|
return result;
|
|
313
328
|
}
|
|
314
329
|
});
|
|
330
|
+
// Failed-check logs: the tail of a GitHub Actions job's log, fetched live (never
|
|
331
|
+
// stored). The jobId comes from CheckRun.jobId (parsed from the Actions detailsUrl);
|
|
332
|
+
// only Actions checks have one, so the frontend offers this on failed Actions rows.
|
|
333
|
+
// Degrades to {available:false, reason} on any GitHub error (expired logs, no
|
|
334
|
+
// actions:read, network) instead of 500ing.
|
|
335
|
+
app.get('/api/prs/:id/checks/:jobId/logs', { schema: checkLogsSchema }, async (req, reply) => {
|
|
336
|
+
const { id, jobId } = req.params;
|
|
337
|
+
const { tail } = req.query;
|
|
338
|
+
const accountId = accountIdOf(req);
|
|
339
|
+
const ctx = await getPrWriteContext(id, accountId);
|
|
340
|
+
if (!ctx) {
|
|
341
|
+
reply.status(404);
|
|
342
|
+
return { error: 'NotFound', message: `PR ${id} not found` };
|
|
343
|
+
}
|
|
344
|
+
const tailLines = Math.min(Math.max(tail ?? 200, 1), 1000);
|
|
345
|
+
const unavailable = (reason) => ({
|
|
346
|
+
available: false,
|
|
347
|
+
reason,
|
|
348
|
+
text: '',
|
|
349
|
+
totalLines: 0,
|
|
350
|
+
returnedLines: 0,
|
|
351
|
+
});
|
|
352
|
+
try {
|
|
353
|
+
const token = await getAccessToken(accountId);
|
|
354
|
+
const res = await ghRestGetText(token, `/repos/${ctx.owner}/${ctx.name}/actions/jobs/${jobId}/logs`);
|
|
355
|
+
if (!res.ok) {
|
|
356
|
+
const reason = res.status === 404 || res.status === 410
|
|
357
|
+
? 'Logs are no longer available (expired, or the job was re-run).'
|
|
358
|
+
: res.status === 403
|
|
359
|
+
? 'No permission to read GitHub Actions logs for this repo.'
|
|
360
|
+
: `Couldn't fetch logs (GitHub returned ${res.status}).`;
|
|
361
|
+
return unavailable(reason);
|
|
362
|
+
}
|
|
363
|
+
// A job log can be many MB — normalise line endings, drop a trailing blank,
|
|
364
|
+
// and tail server-side so only the last N lines reach the browser. Guard the
|
|
365
|
+
// empty/blank body so it reports 0 lines (not [''] → a misleading "1 of 1").
|
|
366
|
+
const trimmed = res.text.replace(/\r\n/g, '\n').replace(/\n+$/, '');
|
|
367
|
+
const lines = trimmed === '' ? [] : trimmed.split('\n');
|
|
368
|
+
const tailed = lines.slice(-tailLines);
|
|
369
|
+
const result = {
|
|
370
|
+
available: true,
|
|
371
|
+
text: tailed.join('\n'),
|
|
372
|
+
totalLines: lines.length,
|
|
373
|
+
returnedLines: tailed.length,
|
|
374
|
+
};
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return unavailable("Couldn't reach GitHub to fetch the logs.");
|
|
379
|
+
}
|
|
380
|
+
});
|
|
315
381
|
}
|
|
316
382
|
//# sourceMappingURL=prs.js.map
|
package/dist/db/queries.js
CHANGED
|
@@ -16,7 +16,7 @@ const REASON_PRIORITY = [
|
|
|
16
16
|
import { db, schema, isPg } from './client.js';
|
|
17
17
|
import { runTransaction } from './client.js';
|
|
18
18
|
import { config } from '../config.js';
|
|
19
|
-
import { computeTriage } from './triage.js';
|
|
19
|
+
import { computeApprovalInfoByPr, computeTriage, } from './triage.js';
|
|
20
20
|
import { getAccountUserId } from '../auth/account.js';
|
|
21
21
|
// Bind a JS Date into a raw-`sql` epoch comparison portably: Postgres columns are
|
|
22
22
|
// timestamptz (drizzle binds the Date through the codec), whereas SQLite columns
|
|
@@ -1073,8 +1073,10 @@ export async function markAllViewed(accountId, repoIds) {
|
|
|
1073
1073
|
// doesn't own (refId is a local PR/thread id). Defense-in-depth; the read path is
|
|
1074
1074
|
// already account-scoped.
|
|
1075
1075
|
async function ownsDismissRef(accountId, kind, refId) {
|
|
1076
|
-
if (kind === 'review_request' ||
|
|
1077
|
-
|
|
1076
|
+
if (kind === 'review_request' ||
|
|
1077
|
+
kind === 'watched_repo_pr' ||
|
|
1078
|
+
kind === 'pr_approved') {
|
|
1079
|
+
// All three reference a PR id directly.
|
|
1078
1080
|
const rows = await db
|
|
1079
1081
|
.select({ id: pullRequests.id })
|
|
1080
1082
|
.from(pullRequests)
|
|
@@ -1146,6 +1148,7 @@ export async function getCompletedDismissals(accountId, daysBefore = 90) {
|
|
|
1146
1148
|
const reviewDismissals = dismissals.filter((d) => d.kind === 'review_request');
|
|
1147
1149
|
const threadDismissals = dismissals.filter((d) => d.kind === 'thread');
|
|
1148
1150
|
const watchedDismissals = dismissals.filter((d) => d.kind === 'watched_repo_pr');
|
|
1151
|
+
const approvedDismissals = dismissals.filter((d) => d.kind === 'pr_approved');
|
|
1149
1152
|
const claudeDismissals = dismissals.filter((d) => d.kind === 'claude_review');
|
|
1150
1153
|
const items = [];
|
|
1151
1154
|
const referencedUsers = new Set();
|
|
@@ -1223,6 +1226,42 @@ export async function getCompletedDismissals(accountId, daysBefore = 90) {
|
|
|
1223
1226
|
});
|
|
1224
1227
|
}
|
|
1225
1228
|
}
|
|
1229
|
+
// pr_approved dismissals → their PRs (account-scoped). Same shape as a
|
|
1230
|
+
// review_request dismissal, a different kind tag.
|
|
1231
|
+
if (approvedDismissals.length > 0) {
|
|
1232
|
+
const prRows = await db
|
|
1233
|
+
.select()
|
|
1234
|
+
.from(pullRequests)
|
|
1235
|
+
.innerJoin(repos, eq(repos.id, pullRequests.repoId))
|
|
1236
|
+
.where(and(eq(pullRequests.accountId, accountId), inArray(pullRequests.id, approvedDismissals.map((d) => d.refId))))
|
|
1237
|
+
.execute();
|
|
1238
|
+
const byId = new Map(prRows.map((r) => [r.pull_requests.id, r]));
|
|
1239
|
+
for (const d of approvedDismissals) {
|
|
1240
|
+
const row = byId.get(d.refId);
|
|
1241
|
+
if (!row)
|
|
1242
|
+
continue;
|
|
1243
|
+
const { pull_requests: pr, repos: repo } = row;
|
|
1244
|
+
if (pr.authorId != null)
|
|
1245
|
+
referencedUsers.add(pr.authorId);
|
|
1246
|
+
const restorable = actionable.approvedPrIds.has(pr.id);
|
|
1247
|
+
items.push({
|
|
1248
|
+
kind: 'pr_approved',
|
|
1249
|
+
prId: pr.id,
|
|
1250
|
+
repoFullName: `${repo.owner}/${repo.name}`,
|
|
1251
|
+
number: pr.number,
|
|
1252
|
+
title: pr.title,
|
|
1253
|
+
authorId: pr.authorId,
|
|
1254
|
+
state: pr.state,
|
|
1255
|
+
openedAt: pr.openedAt.toISOString(),
|
|
1256
|
+
githubUrl: `https://github.com/${repo.owner}/${repo.name}/pull/${pr.number}`,
|
|
1257
|
+
dismissedAt: d.dismissedAt.toISOString(),
|
|
1258
|
+
restorable,
|
|
1259
|
+
...(restorable
|
|
1260
|
+
? {}
|
|
1261
|
+
: { reason: prClosedReason(pr.state) ?? 'No longer approved' }),
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1226
1265
|
// thread dismissals → their review threads + parent PR + last reply.
|
|
1227
1266
|
if (threadDismissals.length > 0) {
|
|
1228
1267
|
const threadIds = threadDismissals.map((d) => d.refId);
|
|
@@ -1396,6 +1435,7 @@ async function getActionableInboxIds(accountId) {
|
|
|
1396
1435
|
const empty = {
|
|
1397
1436
|
reviewRequestPrIds: new Set(),
|
|
1398
1437
|
watchedPrIds: new Set(),
|
|
1438
|
+
approvedPrIds: new Set(),
|
|
1399
1439
|
threadIds: new Set(),
|
|
1400
1440
|
claudeReviewIds: new Set(),
|
|
1401
1441
|
};
|
|
@@ -1409,6 +1449,12 @@ async function getActionableInboxIds(accountId) {
|
|
|
1409
1449
|
const open = await buildTimelinePrs(openRows, accountId);
|
|
1410
1450
|
const reviewRequestPrIds = new Set(open.filter((t) => t.reviewRequestedFromMe).map((t) => t.id));
|
|
1411
1451
|
const watchedPrIds = await getWatchedActionablePrIds(accountId, localUserId, open, openRows);
|
|
1452
|
+
// Your authored, open PRs with a standing approval (restorability source for the
|
|
1453
|
+
// pr_approved Done entries).
|
|
1454
|
+
const approvalInfo = await computeApprovalInfoByPr(open.map((t) => t.id));
|
|
1455
|
+
const approvedPrIds = new Set(open
|
|
1456
|
+
.filter((t) => t.authorId === localUserId && !t.isDraft && approvalInfo.get(t.id)?.approved)
|
|
1457
|
+
.map((t) => t.id));
|
|
1412
1458
|
const repoNameById = new Map();
|
|
1413
1459
|
for (const r of await listRepos(accountId))
|
|
1414
1460
|
repoNameById.set(r.id, r.fullName);
|
|
@@ -1416,13 +1462,14 @@ async function getActionableInboxIds(accountId) {
|
|
|
1416
1462
|
const claudeReviewIds = config.claudeReviewEnabled
|
|
1417
1463
|
? new Set((await getUnactionedClaudeReviews(accountId)).map((c) => c.reviewId))
|
|
1418
1464
|
: new Set();
|
|
1419
|
-
return { reviewRequestPrIds, watchedPrIds, threadIds, claudeReviewIds };
|
|
1465
|
+
return { reviewRequestPrIds, watchedPrIds, approvedPrIds, threadIds, claudeReviewIds };
|
|
1420
1466
|
}
|
|
1421
1467
|
export async function getMyTurn(accountId) {
|
|
1422
1468
|
const localUserId = await getAccountUserId(accountId);
|
|
1423
1469
|
const empty = {
|
|
1424
1470
|
awaitingReview: [],
|
|
1425
1471
|
yourPrs: [],
|
|
1472
|
+
approvedPrs: [],
|
|
1426
1473
|
threadsAwaiting: [],
|
|
1427
1474
|
watchedRepoPrs: [],
|
|
1428
1475
|
claudeReviewsToAction: [],
|
|
@@ -1449,6 +1496,9 @@ export async function getMyTurn(accountId) {
|
|
|
1449
1496
|
.execute();
|
|
1450
1497
|
const reviewDismissedAt = new Map();
|
|
1451
1498
|
const threadDismissedAt = new Map();
|
|
1499
|
+
// Dismissed "your PR was approved" entries. Keyed by PR id; honoured until a NEWER
|
|
1500
|
+
// approval lands (compared against the latest approving review's timestamp below).
|
|
1501
|
+
const approvedDismissedAt = new Map();
|
|
1452
1502
|
// Dismissed Claude-review run ids. Keyed by run id (not PR id): a fresh run gets
|
|
1453
1503
|
// a new id, so it naturally re-appears without a timestamp comparison.
|
|
1454
1504
|
const claudeDismissedIds = new Set();
|
|
@@ -1460,6 +1510,8 @@ export async function getMyTurn(accountId) {
|
|
|
1460
1510
|
reviewDismissedAt.set(d.refId, d.dismissedAt);
|
|
1461
1511
|
else if (d.kind === 'thread')
|
|
1462
1512
|
threadDismissedAt.set(d.refId, d.dismissedAt);
|
|
1513
|
+
else if (d.kind === 'pr_approved')
|
|
1514
|
+
approvedDismissedAt.set(d.refId, d.dismissedAt);
|
|
1463
1515
|
else if (d.kind === 'claude_review')
|
|
1464
1516
|
claudeDismissedIds.add(d.refId);
|
|
1465
1517
|
else if (d.kind === 'watched_repo_pr')
|
|
@@ -1496,9 +1548,38 @@ export async function getMyTurn(accountId) {
|
|
|
1496
1548
|
const others = await countOtherReviewers(t.id, localUserId);
|
|
1497
1549
|
return { ...toMyTurnPr(t), alsoRequested: others };
|
|
1498
1550
|
}));
|
|
1499
|
-
// 2. Your PRs
|
|
1551
|
+
// 2. Your authored, open PRs that have a standing approval (likely ready to merge).
|
|
1552
|
+
// An approving review lands them here; a "Done" dismissal hides them until a
|
|
1553
|
+
// NEWER approval arrives (compared against the latest approving review's
|
|
1554
|
+
// timestamp — not the PR's updatedAt, which any commit would bump and re-nag).
|
|
1555
|
+
// They leave automatically once the PR is merged/closed (drops out of `open`).
|
|
1556
|
+
const approvalInfo = await computeApprovalInfoByPr(open.map((t) => t.id));
|
|
1557
|
+
const approvedPrs = open
|
|
1558
|
+
.filter((t) => {
|
|
1559
|
+
// Drafts can't merge even when approved — don't claim "ready to merge".
|
|
1560
|
+
if (t.authorId !== localUserId || t.isDraft)
|
|
1561
|
+
return false;
|
|
1562
|
+
const info = approvalInfo.get(t.id);
|
|
1563
|
+
if (!info?.approved)
|
|
1564
|
+
return false;
|
|
1565
|
+
const dismissedAt = approvedDismissedAt.get(t.id);
|
|
1566
|
+
if (!dismissedAt)
|
|
1567
|
+
return true;
|
|
1568
|
+
const latest = info.latestApprovalAt?.getTime() ?? 0;
|
|
1569
|
+
return latest > dismissedAt.getTime();
|
|
1570
|
+
})
|
|
1571
|
+
.map((t) => ({
|
|
1572
|
+
...toMyTurnPr(t),
|
|
1573
|
+
approvals: approvalInfo.get(t.id)?.approvals ?? 0,
|
|
1574
|
+
mergeable: t.mergeable,
|
|
1575
|
+
mergeStateStatus: t.mergeStateStatus,
|
|
1576
|
+
}));
|
|
1577
|
+
const approvedShownIds = new Set(approvedPrs.map((i) => i.prId));
|
|
1578
|
+
// 3. Your PRs with new activity since you last looked — excluding ones already shown
|
|
1579
|
+
// under "approved" (the stronger, more actionable signal wins).
|
|
1500
1580
|
const yourPrs = open
|
|
1501
1581
|
.filter((t) => t.authorId === localUserId &&
|
|
1582
|
+
!approvedShownIds.has(t.id) &&
|
|
1502
1583
|
t.newSinceLastViewed != null &&
|
|
1503
1584
|
(t.newSinceLastViewed.comments > 0 ||
|
|
1504
1585
|
t.newSinceLastViewed.reviews > 0 ||
|
|
@@ -1517,6 +1598,7 @@ export async function getMyTurn(accountId) {
|
|
|
1517
1598
|
const inOtherSections = new Set([
|
|
1518
1599
|
...awaitingReview.map((i) => i.prId),
|
|
1519
1600
|
...yourPrs.map((i) => i.prId),
|
|
1601
|
+
...approvedPrs.map((i) => i.prId),
|
|
1520
1602
|
]);
|
|
1521
1603
|
const watchedRepoPrs = open
|
|
1522
1604
|
.filter((t) => watchedEligible.has(t.id) &&
|
|
@@ -1549,6 +1631,7 @@ export async function getMyTurn(accountId) {
|
|
|
1549
1631
|
return {
|
|
1550
1632
|
awaitingReview,
|
|
1551
1633
|
yourPrs,
|
|
1634
|
+
approvedPrs,
|
|
1552
1635
|
threadsAwaiting,
|
|
1553
1636
|
watchedRepoPrs,
|
|
1554
1637
|
claudeReviewsToAction,
|
package/dist/db/schema.pg.js
CHANGED
|
@@ -167,7 +167,7 @@ export const myTurnDismissals = pgTable('my_turn_dismissals', {
|
|
|
167
167
|
.notNull()
|
|
168
168
|
.references(() => accounts.id),
|
|
169
169
|
kind: text('kind', {
|
|
170
|
-
enum: ['review_request', 'thread', 'watched_repo_pr', 'claude_review'],
|
|
170
|
+
enum: ['review_request', 'thread', 'watched_repo_pr', 'pr_approved', 'claude_review'],
|
|
171
171
|
}).notNull(),
|
|
172
172
|
refId: integer('ref_id').notNull(),
|
|
173
173
|
dismissedAt: timestamp('dismissed_at', {
|
package/dist/db/schema.sqlite.js
CHANGED
|
@@ -193,7 +193,7 @@ export const myTurnDismissals = sqliteTable('my_turn_dismissals', {
|
|
|
193
193
|
.notNull()
|
|
194
194
|
.references(() => accounts.id),
|
|
195
195
|
kind: text('kind', {
|
|
196
|
-
enum: ['review_request', 'thread', 'watched_repo_pr', 'claude_review'],
|
|
196
|
+
enum: ['review_request', 'thread', 'watched_repo_pr', 'pr_approved', 'claude_review'],
|
|
197
197
|
}).notNull(),
|
|
198
198
|
refId: integer('ref_id').notNull(),
|
|
199
199
|
dismissedAt: integer('dismissed_at', { mode: 'timestamp' }).notNull(),
|
package/dist/db/triage.js
CHANGED
|
@@ -5,11 +5,17 @@ const { reviewRequests, prViews, events, reviews } = schema;
|
|
|
5
5
|
function emptyNew() {
|
|
6
6
|
return { commits: 0, comments: 0, reviews: 0 };
|
|
7
7
|
}
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Per-author latest review state → per-PR approval standing. A reviewer's standing
|
|
10
|
+
* decision is their latest non-"commented" review (approved / changes_requested);
|
|
11
|
+
* a PR is "approved" when at least one reviewer's standing decision is approved and
|
|
12
|
+
* none is changes_requested. Used both for the `approved_ready` reason tag and the
|
|
13
|
+
* "your PR was approved" My Turn section.
|
|
14
|
+
*/
|
|
15
|
+
export async function computeApprovalInfoByPr(prIds) {
|
|
16
|
+
const out = new Map();
|
|
11
17
|
if (prIds.length === 0)
|
|
12
|
-
return
|
|
18
|
+
return out;
|
|
13
19
|
const rows = await db
|
|
14
20
|
.select({
|
|
15
21
|
prId: reviews.prId,
|
|
@@ -26,25 +32,41 @@ async function computeApprovedByPr(prIds) {
|
|
|
26
32
|
if (r.state !== 'approved' && r.state !== 'changes_requested')
|
|
27
33
|
continue;
|
|
28
34
|
const key = `${r.prId}:${r.authorId}`;
|
|
29
|
-
const at = r.submittedAt.getTime();
|
|
30
35
|
const prev = latest.get(key);
|
|
31
|
-
if (!prev ||
|
|
32
|
-
latest.set(key, { state: r.state, at });
|
|
36
|
+
if (!prev || r.submittedAt.getTime() > prev.at.getTime()) {
|
|
37
|
+
latest.set(key, { prId: r.prId, state: r.state, at: r.submittedAt });
|
|
38
|
+
}
|
|
33
39
|
}
|
|
34
40
|
const byPr = new Map();
|
|
35
|
-
for (const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
if (v.state === 'approved')
|
|
41
|
+
for (const v of latest.values()) {
|
|
42
|
+
const entry = byPr.get(v.prId) ?? { approvals: 0, blocks: 0, latestApprovalAt: null };
|
|
43
|
+
if (v.state === 'approved') {
|
|
39
44
|
entry.approvals += 1;
|
|
40
|
-
|
|
45
|
+
if (!entry.latestApprovalAt || v.at.getTime() > entry.latestApprovalAt.getTime()) {
|
|
46
|
+
entry.latestApprovalAt = v.at;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
41
50
|
entry.blocks += 1;
|
|
42
|
-
|
|
51
|
+
}
|
|
52
|
+
byPr.set(v.prId, entry);
|
|
43
53
|
}
|
|
44
54
|
for (const [prId, e] of byPr) {
|
|
45
|
-
|
|
46
|
-
approved.
|
|
55
|
+
out.set(prId, {
|
|
56
|
+
approved: e.approvals > 0 && e.blocks === 0,
|
|
57
|
+
approvals: e.approvals,
|
|
58
|
+
latestApprovalAt: e.latestApprovalAt,
|
|
59
|
+
});
|
|
47
60
|
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/** Per-author latest review state → is the PR approved with no blocking review? */
|
|
64
|
+
async function computeApprovedByPr(prIds) {
|
|
65
|
+
const info = await computeApprovalInfoByPr(prIds);
|
|
66
|
+
const approved = new Set();
|
|
67
|
+
for (const [prId, e] of info)
|
|
68
|
+
if (e.approved)
|
|
69
|
+
approved.add(prId);
|
|
48
70
|
return approved;
|
|
49
71
|
}
|
|
50
72
|
/**
|
package/dist/github/client.js
CHANGED
|
@@ -29,6 +29,23 @@ async function ghRest(token, method, path, body) {
|
|
|
29
29
|
export function ghRestGetFor(token, path) {
|
|
30
30
|
return ghRest(token, 'GET', path);
|
|
31
31
|
}
|
|
32
|
+
// REST GET returning the raw response TEXT (not JSON), for endpoints with a plain-text
|
|
33
|
+
// body — notably the Actions job-logs endpoint, which 302-redirects to a signed
|
|
34
|
+
// download URL. fetch follows the redirect automatically AND strips the Authorization
|
|
35
|
+
// header on the cross-origin hop, so our token is never sent to the signed URL. Does
|
|
36
|
+
// NOT throw on a non-2xx status — returns it so the caller can degrade gracefully
|
|
37
|
+
// (logs expire after ~90 days / on a re-run → 404/410; missing actions:read → 403).
|
|
38
|
+
export async function ghRestGetText(token, path) {
|
|
39
|
+
const res = await fetch(`https://api.github.com${path}`, {
|
|
40
|
+
method: 'GET',
|
|
41
|
+
headers: {
|
|
42
|
+
authorization: `token ${token}`,
|
|
43
|
+
'x-github-api-version': '2022-11-28',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
const text = await res.text().catch(() => '');
|
|
47
|
+
return { status: res.status, ok: res.ok, text };
|
|
48
|
+
}
|
|
32
49
|
// REST POST (submitting a PR review — inline line comments require the REST
|
|
33
50
|
// reviews endpoint) for a specific account's token.
|
|
34
51
|
export function ghRestPostFor(token, path, body) {
|
package/dist/sync/upsert.js
CHANGED
|
@@ -185,13 +185,30 @@ function checkContextState(c) {
|
|
|
185
185
|
return 'unknown';
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
+
// A GitHub Actions check's detailsUrl is .../actions/runs/<runId>/job/<jobId> — parse
|
|
189
|
+
// the two ids so the frontend can fetch that job's logs on demand. Third-party CI
|
|
190
|
+
// (StatusContext / external CheckRuns) has a detailsUrl pointing elsewhere; no match →
|
|
191
|
+
// null, and the UI keeps it as a plain external link (logs aren't retrievable).
|
|
192
|
+
const ACTIONS_JOB_RE = /\/actions\/runs\/(\d+)\/job\/(\d+)/;
|
|
193
|
+
function parseActionsIds(url) {
|
|
194
|
+
const m = url ? ACTIONS_JOB_RE.exec(url) : null;
|
|
195
|
+
if (!m)
|
|
196
|
+
return { runId: null, jobId: null };
|
|
197
|
+
return { runId: Number(m[1]), jobId: Number(m[2]) };
|
|
198
|
+
}
|
|
188
199
|
export function checkRunsFrom(head) {
|
|
189
200
|
const nodes = head?.statusCheckRollup?.contexts?.nodes ?? [];
|
|
190
|
-
return nodes.map((c) =>
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
201
|
+
return nodes.map((c) => {
|
|
202
|
+
const url = c.__typename === 'CheckRun' ? c.detailsUrl : c.targetUrl;
|
|
203
|
+
const { runId, jobId } = c.__typename === 'CheckRun' ? parseActionsIds(url) : { runId: null, jobId: null };
|
|
204
|
+
return {
|
|
205
|
+
name: c.__typename === 'CheckRun' ? c.name : c.context,
|
|
206
|
+
state: checkContextState(c),
|
|
207
|
+
url,
|
|
208
|
+
runId,
|
|
209
|
+
jobId,
|
|
210
|
+
};
|
|
211
|
+
});
|
|
195
212
|
}
|
|
196
213
|
const REVIEW_STATES = new Set([
|
|
197
214
|
'approved',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pierre-review",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"description": "Dashboard for tracking your team's GitHub PR activity across repos — local (SQLite + gh) or self-hosted multi-tenant cloud (Postgres + GitHub App).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Alex Wakeman",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
.vis-time-axis{position:relative;overflow:hidden}.vis-time-axis.vis-foreground{top:0;left:0;width:100%}.vis-time-axis.vis-background{position:absolute;top:0;left:0;width:100%;height:100%}.vis-time-axis .vis-text{position:absolute;color:#4d4d4d;padding:3px;overflow:hidden;box-sizing:border-box;white-space:nowrap}.vis-time-axis .vis-text.vis-measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis-time-axis .vis-grid.vis-vertical{position:absolute;border-left:1px solid}.vis-time-axis .vis-grid.vis-vertical-rtl{position:absolute;border-right:1px solid}.vis-time-axis .vis-grid.vis-minor{border-color:#e5e5e5}.vis-time-axis .vis-grid.vis-major{border-color:#bfbfbf}.vis .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis-custom-time{background-color:#6e94ff;width:2px;cursor:move;z-index:1}.vis-custom-time>.vis-custom-time-marker{background-color:inherit;color:#fff;font-size:12px;white-space:nowrap;padding:3px 5px;top:0;cursor:initial;z-index:inherit}.vis-current-time{background-color:#ff7f6e;width:2px;z-index:1;pointer-events:none}.vis-rolling-mode-btn{height:40px;width:40px;position:absolute;top:7px;right:20px;border-radius:50%;font-size:28px;cursor:pointer;opacity:.8;color:#fff;font-weight:700;text-align:center;background:#3876c2}.vis-rolling-mode-btn:before{content:"⛶"}.vis-rolling-mode-btn:hover{opacity:1}.vis-panel{position:absolute;padding:0;margin:0;box-sizing:border-box}.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right,.vis-panel.vis-top,.vis-panel.vis-bottom{border:1px #bfbfbf}.vis-panel.vis-center,.vis-panel.vis-left,.vis-panel.vis-right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis-left.vis-panel.vis-vertical-scroll,.vis-right.vis-panel.vis-vertical-scroll{height:100%;overflow-x:hidden;overflow-y:scroll}.vis-left.vis-panel.vis-vertical-scroll{direction:rtl}.vis-left.vis-panel.vis-vertical-scroll .vis-content,.vis-right.vis-panel.vis-vertical-scroll{direction:ltr}.vis-right.vis-panel.vis-vertical-scroll .vis-content{direction:rtl}.vis-panel.vis-center,.vis-panel.vis-top,.vis-panel.vis-bottom{border-left-style:solid;border-right-style:solid}.vis-background{overflow:hidden}.vis-panel>.vis-content{position:relative}.vis-panel .vis-shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px #000c}.vis-panel .vis-shadow.vis-top{top:-1px;left:0}.vis-panel .vis-shadow.vis-bottom{bottom:-1px;left:0}.vis-graph-group0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis-graph-group1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis-graph-group2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis-graph-group3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis-graph-group4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis-graph-group5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis-graph-group6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis-graph-group7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis-graph-group8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis-graph-group9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis-timeline .vis-fill{fill-opacity:.1;stroke:none}.vis-timeline .vis-bar{fill-opacity:.5;stroke-width:1px}.vis-timeline .vis-point{stroke-width:2px;fill-opacity:1}.vis-timeline .vis-legend-background{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis-timeline .vis-outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis-timeline .vis-icon-fill{fill-opacity:.3;stroke:none}.vis-timeline{position:relative;border:1px solid #bfbfbf;overflow:hidden;padding:0;margin:0;box-sizing:border-box}.vis-loading-screen{width:100%;height:100%;position:absolute;top:0;left:0}.vis [class*=span]{min-height:0;width:auto}.vis-item{position:absolute;color:#1a1a1a;border-color:#97b0f8;border-width:1px;background-color:#d5ddf6;display:inline-block;z-index:1}.vis-item.vis-selected{border-color:#ffc200;background-color:#fff785;z-index:2}.vis-editable.vis-selected{cursor:move}.vis-item.vis-point.vis-selected{background-color:#fff785}.vis-item.vis-box{text-align:center;border-style:solid;border-radius:2px}.vis-item.vis-point{background:none}.vis-item.vis-dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis-item.vis-range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis-item.vis-background{border:none;background-color:#d5ddf666;box-sizing:border-box;padding:0;margin:0}.vis-item .vis-item-overflow{position:relative;width:100%;height:100%;padding:0;margin:0;overflow:hidden}.vis-item-visible-frame{white-space:nowrap}.vis-item.vis-range .vis-item-content{position:relative;display:inline-block}.vis-item.vis-background .vis-item-content{position:absolute;display:inline-block}.vis-item.vis-line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis-item .vis-item-content{white-space:nowrap;box-sizing:border-box;padding:5px}.vis-item .vis-onUpdateTime-tooltip{position:absolute;background:#4f81bd;color:#fff;width:200px;text-align:center;white-space:nowrap;padding:5px;border-radius:1px;transition:.4s;-o-transition:.4s;-moz-transition:.4s;-webkit-transition:.4s}.vis-item .vis-delete,.vis-item .vis-delete-rtl{position:absolute;top:0;width:24px;height:24px;box-sizing:border-box;padding:0 5px;cursor:pointer;transition:background .2s linear}.vis-item .vis-delete{right:-24px}.vis-item .vis-delete-rtl{left:-24px}.vis-item .vis-delete:after,.vis-item .vis-delete-rtl:after{content:"×";color:red;font-family:arial,sans-serif;font-size:22px;font-weight:700;transition:color .2s linear}.vis-item .vis-delete:hover,.vis-item .vis-delete-rtl:hover{background:red}.vis-item .vis-delete:hover:after,.vis-item .vis-delete-rtl:hover:after{color:#fff}.vis-item .vis-drag-center{position:absolute;width:100%;height:100%;top:0;left:0;cursor:move}.vis-item.vis-range .vis-drag-left{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;left:-4px;cursor:w-resize}.vis-item.vis-range .vis-drag-right{position:absolute;width:24px;max-width:20%;min-width:2px;height:100%;top:0;right:-4px;cursor:e-resize}.vis-range.vis-item.vis-readonly .vis-drag-left,.vis-range.vis-item.vis-readonly .vis-drag-right{cursor:auto}.vis-item.vis-cluster{vertical-align:center;text-align:center;border-style:solid;border-radius:2px}.vis-item.vis-cluster-line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis-item.vis-cluster-dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}div.vis-tooltip{position:absolute;visibility:hidden;padding:5px;white-space:nowrap;font-family:verdana;font-size:14px;color:#000;background-color:#f5f4ed;border-radius:3px;border:1px solid #808074;box-shadow:3px 3px 10px #0003;pointer-events:none;z-index:5}.vis-itemset{position:relative;padding:0;margin:0;box-sizing:border-box}.vis-itemset .vis-background,.vis-itemset .vis-foreground{position:absolute;width:100%;height:100%;overflow:visible}.vis-axis{position:absolute;width:100%;height:0;left:0;z-index:1}.vis-foreground .vis-group{position:relative;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis-foreground .vis-group:last-child{border-bottom:none}.vis-nesting-group{cursor:pointer}.vis-label.vis-nested-group.vis-group-level-unknown-but-gte1{background:#f5f5f5}.vis-label.vis-nested-group.vis-group-level-0{background-color:#fff}.vis-ltr .vis-label.vis-nested-group.vis-group-level-0 .vis-inner{padding-left:0}.vis-rtl .vis-label.vis-nested-group.vis-group-level-0 .vis-inner{padding-right:0}.vis-label.vis-nested-group.vis-group-level-1{background-color:#0000000d}.vis-ltr .vis-label.vis-nested-group.vis-group-level-1 .vis-inner{padding-left:15px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-1 .vis-inner{padding-right:15px}.vis-label.vis-nested-group.vis-group-level-2{background-color:#0000001a}.vis-ltr .vis-label.vis-nested-group.vis-group-level-2 .vis-inner{padding-left:30px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-2 .vis-inner{padding-right:30px}.vis-label.vis-nested-group.vis-group-level-3{background-color:#00000026}.vis-ltr .vis-label.vis-nested-group.vis-group-level-3 .vis-inner{padding-left:45px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-3 .vis-inner{padding-right:45px}.vis-label.vis-nested-group.vis-group-level-4{background-color:#0003}.vis-ltr .vis-label.vis-nested-group.vis-group-level-4 .vis-inner{padding-left:60px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-4 .vis-inner{padding-right:60px}.vis-label.vis-nested-group.vis-group-level-5{background-color:#00000040}.vis-ltr .vis-label.vis-nested-group.vis-group-level-5 .vis-inner{padding-left:75px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-5 .vis-inner{padding-right:75px}.vis-label.vis-nested-group.vis-group-level-6{background-color:#0000004d}.vis-ltr .vis-label.vis-nested-group.vis-group-level-6 .vis-inner{padding-left:90px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-6 .vis-inner{padding-right:90px}.vis-label.vis-nested-group.vis-group-level-7{background-color:#00000059}.vis-ltr .vis-label.vis-nested-group.vis-group-level-7 .vis-inner{padding-left:105px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-7 .vis-inner{padding-right:105px}.vis-label.vis-nested-group.vis-group-level-8{background-color:#0006}.vis-ltr .vis-label.vis-nested-group.vis-group-level-8 .vis-inner{padding-left:120px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-8 .vis-inner{padding-right:120px}.vis-label.vis-nested-group.vis-group-level-9{background-color:#00000073}.vis-ltr .vis-label.vis-nested-group.vis-group-level-9 .vis-inner{padding-left:135px}.vis-rtl .vis-label.vis-nested-group.vis-group-level-9 .vis-inner{padding-right:135px}.vis-label.vis-nested-group{background-color:#00000080}.vis-ltr .vis-label.vis-nested-group .vis-inner{padding-left:150px}.vis-rtl .vis-label.vis-nested-group .vis-inner{padding-right:150px}.vis-group-level-unknown-but-gte1{border:1px solid red}.vis-label.vis-nesting-group:before{display:inline-block;width:15px}.vis-label.vis-nesting-group.expanded:before{content:"▼"}.vis-label.vis-nesting-group.collapsed:before{content:"▶"}.vis-rtl .vis-label.vis-nesting-group.collapsed:before{content:"◀"}.vis-ltr .vis-label:not(.vis-nesting-group):not(.vis-group-level-0){padding-left:15px}.vis-rtl .vis-label:not(.vis-nesting-group):not(.vis-group-level-0){padding-right:15px}.vis-overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-labelset{position:relative;overflow:hidden;box-sizing:border-box}.vis-labelset .vis-label{position:relative;left:0;top:0;width:100%;color:#4d4d4d;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis-labelset .vis-label.draggable{cursor:pointer}.vis-group-is-dragging{background:#0000001a}.vis-labelset .vis-label:last-child{border-bottom:none}.vis-labelset .vis-label .vis-inner{display:inline-block;padding:5px}.vis-labelset .vis-label .vis-inner.vis-hidden{padding:0}div.vis-configuration{position:relative;display:block;float:left;font-size:12px}div.vis-configuration-wrapper{display:block;width:700px}div.vis-configuration-wrapper:after{clear:both;content:"";display:block}div.vis-configuration.vis-config-option-container{display:block;width:495px;background-color:#fff;border:2px solid #f7f8fa;border-radius:4px;margin-top:20px;left:10px;padding-left:5px}div.vis-configuration.vis-config-button{display:block;width:495px;height:25px;vertical-align:middle;line-height:25px;background-color:#f7f8fa;border:2px solid #ceced0;border-radius:4px;margin-top:20px;left:10px;padding-left:5px;cursor:pointer;margin-bottom:30px}div.vis-configuration.vis-config-button.hover{background-color:#4588e6;border:2px solid #214373;color:#fff}div.vis-configuration.vis-config-item{display:block;float:left;width:495px;height:25px;vertical-align:middle;line-height:25px}div.vis-configuration.vis-config-item.vis-config-s2{left:10px;background-color:#f7f8fa;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s3{left:20px;background-color:#e4e9f0;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-item.vis-config-s4{left:30px;background-color:#cfd8e6;padding-left:5px;border-radius:3px}div.vis-configuration.vis-config-header{font-size:18px;font-weight:700}div.vis-configuration.vis-config-label{width:120px;height:25px;line-height:25px}div.vis-configuration.vis-config-label.vis-config-s3{width:110px}div.vis-configuration.vis-config-label.vis-config-s4{width:100px}div.vis-configuration.vis-config-colorBlock{top:1px;width:30px;height:19px;border:1px solid #444444;border-radius:2px;padding:0;margin:0;cursor:pointer}input.vis-configuration.vis-config-checkbox{left:-5px}input.vis-configuration.vis-config-rangeinput{position:relative;top:-5px;width:60px;padding:1px;margin:0;pointer-events:none}input.vis-configuration.vis-config-range{-webkit-appearance:none;border:0px solid white;background-color:#0000;width:300px;height:20px}input.vis-configuration.vis-config-range::-webkit-slider-runnable-track{width:300px;height:5px;background:#dedede;background:linear-gradient(to bottom,#dedede,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#dedede",endColorstr="#c8c8c8",GradientType=0);border:1px solid #999999;box-shadow:#aaa 0 0 3px;border-radius:3px}input.vis-configuration.vis-config-range::-webkit-slider-thumb{-webkit-appearance:none;border:1px solid #14334b;height:17px;width:17px;border-radius:50%;background:#3876c2;background:linear-gradient(to bottom,#3876c2,#385380);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#3876c2",endColorstr="#385380",GradientType=0);box-shadow:#111927 0 0 1px;margin-top:-7px}input.vis-configuration.vis-config-range:focus{outline:none}input.vis-configuration.vis-config-range:focus::-webkit-slider-runnable-track{background:#9d9d9d;background:linear-gradient(to bottom,#9d9d9d,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#9d9d9d",endColorstr="#c8c8c8",GradientType=0)}input.vis-configuration.vis-config-range::-moz-range-track{width:300px;height:10px;background:#dedede;background:linear-gradient(to bottom,#dedede,#c8c8c8 99%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#dedede",endColorstr="#c8c8c8",GradientType=0);border:1px solid #999999;box-shadow:#aaa 0 0 3px;border-radius:3px}input.vis-configuration.vis-config-range::-moz-range-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:-moz-focusring{outline:1px solid white;outline-offset:-1px}input.vis-configuration.vis-config-range::-ms-track{width:300px;height:5px;background:transparent;border-color:transparent;border-width:6px 0;color:transparent}input.vis-configuration.vis-config-range::-ms-fill-lower{background:#777;border-radius:10px}input.vis-configuration.vis-config-range::-ms-fill-upper{background:#ddd;border-radius:10px}input.vis-configuration.vis-config-range::-ms-thumb{border:none;height:16px;width:16px;border-radius:50%;background:#385380}input.vis-configuration.vis-config-range:focus::-ms-fill-lower{background:#888}input.vis-configuration.vis-config-range:focus::-ms-fill-upper{background:#ccc}.vis-configuration-popup{position:absolute;background:#394c59d9;border:2px solid #f2faff;line-height:30px;height:30px;width:150px;text-align:center;color:#fff;font-size:14px;border-radius:4px;transition:opacity .3s ease-in-out}.vis-configuration-popup:after,.vis-configuration-popup:before{left:100%;top:50%;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.vis-configuration-popup:after{border-color:#88b7d500;border-left-color:#394c59d9;border-width:8px;margin-top:-8px}.vis-configuration-popup:before{border-color:#c2e1f500;border-left-color:#f2faff;border-width:12px;margin-top:-12px}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal{position:absolute;width:100%;height:0;border-bottom:1px solid}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor{border-color:#e5e5e5}.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major{border-color:#bfbfbf}.vis-data-axis .vis-y-axis.vis-major{width:100%;position:absolute;color:#4d4d4d;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-major.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-minor{position:absolute;width:100%;color:#bebebe;white-space:nowrap}.vis-data-axis .vis-y-axis.vis-minor.vis-measure{padding:0;margin:0;border:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title{position:absolute;color:#4d4d4d;white-space:nowrap;bottom:20px;text-align:center}.vis-data-axis .vis-y-axis.vis-title.vis-measure{padding:0;margin:0;visibility:hidden;width:auto}.vis-data-axis .vis-y-axis.vis-title.vis-left{bottom:0;transform-origin:left bottom;transform:rotate(-90deg)}.vis-data-axis .vis-y-axis.vis-title.vis-right{bottom:0;transform-origin:right bottom;transform:rotate(90deg)}.vis-legend{background-color:#f7fcffa6;padding:5px;border:1px solid #b3b3b3;box-shadow:2px 2px 10px #9a9a9a8c}.vis-legend-text{white-space:nowrap;display:inline-block}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
|
|
2
|
+
Theme: GitHub Dark
|
|
3
|
+
Description: Dark theme as seen on github.com
|
|
4
|
+
Author: github.com
|
|
5
|
+
Maintainer: @Hirse
|
|
6
|
+
Updated: 2021-05-15
|
|
7
|
+
|
|
8
|
+
Outdated base version: https://github.com/primer/github-syntax-dark
|
|
9
|
+
Current colors taken from GitHub's CSS
|
|
10
|
+
*/.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#79c0ff}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-comment,.hljs-code,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.left-0{left:0}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-1\.5{top:.375rem}.top-full{top:100%}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[60\]{z-index:60}.my-1{margin-top:.25rem;margin-bottom:.25rem}.-mb-px{margin-bottom:-1px}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-1{margin-left:.25rem}.ml-auto{margin-left:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-7{margin-top:1.75rem}.mt-auto{margin-top:auto}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.\!hidden{display:none!important}.hidden{display:none}.h-0{height:0px}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-\[120px\]{height:120px}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-60{max-height:15rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.max-h-80{max-height:20rem}.max-h-96{max-height:24rem}.max-h-\[40rem\]{max-height:40rem}.max-h-\[80vh\]{max-height:80vh}.max-h-\[82vh\]{max-height:82vh}.max-h-\[88vh\]{max-height:88vh}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-28{width:7rem}.w-3{width:.75rem}.w-4{width:1rem}.w-44{width:11rem}.w-5{width:1.25rem}.w-52{width:13rem}.w-56{width:14rem}.w-60{width:15rem}.w-64{width:16rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-96{width:24rem}.w-\[28rem\]{width:28rem}.w-\[34rem\]{width:34rem}.w-\[44rem\]{width:44rem}.w-\[60rem\]{width:60rem}.w-full{width:100%}.min-w-0{min-width:0px}.max-w-\[12rem\]{max-width:12rem}.max-w-\[14rem\]{max-width:14rem}.max-w-\[8rem\]{max-width:8rem}.max-w-\[90vw\]{max-width:90vw}.max-w-\[92vw\]{max-width:92vw}.max-w-\[94vw\]{max-width:94vw}.max-w-\[96vw\]{max-width:96vw}.max-w-\[calc\(100vw-2rem\)\]{max-width:calc(100vw - 2rem)}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-none{flex:none}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-help{cursor:help}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-rows-\[0fr\]{grid-template-rows:0fr}.grid-rows-\[1fr\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-0\.5{row-gap:.125rem}.gap-y-2{row-gap:.5rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(243 244 246 / var(--tw-divide-opacity, 1))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity, 1))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[1px\]{border-radius:1px}.rounded-\[2px\]{border-radius:2px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-r{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.border{border-width:1px}.border-2{border-width:2px}.border-y{border-top-width:1px;border-bottom-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-200{--tw-border-opacity: 1;border-color:rgb(253 230 138 / var(--tw-border-opacity, 1))}.border-amber-300{--tw-border-opacity: 1;border-color:rgb(252 211 77 / var(--tw-border-opacity, 1))}.border-amber-400{--tw-border-opacity: 1;border-color:rgb(251 191 36 / var(--tw-border-opacity, 1))}.border-amber-500\/40{border-color:#f59e0b66}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-blue-400{--tw-border-opacity: 1;border-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-gray-400{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1))}.border-gray-800{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity, 1))}.border-green-300{--tw-border-opacity: 1;border-color:rgb(134 239 172 / var(--tw-border-opacity, 1))}.border-green-500{--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.border-green-500\/40{border-color:#22c55e66}.border-purple-300{--tw-border-opacity: 1;border-color:rgb(216 180 254 / var(--tw-border-opacity, 1))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity, 1))}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.border-sky-300{--tw-border-opacity: 1;border-color:rgb(125 211 252 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-t-blue-500{--tw-border-opacity: 1;border-top-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.bg-\[\#8957e5\]\/15{background-color:#8957e526}.bg-amber-100{--tw-bg-opacity: 1;background-color:rgb(254 243 199 / var(--tw-bg-opacity, 1))}.bg-amber-400\/5{background-color:#fbbf240d}.bg-amber-50{--tw-bg-opacity: 1;background-color:rgb(255 251 235 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-black\/50{background-color:#00000080}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-50\/40{background-color:#eff6ff66}.bg-blue-50\/50{background-color:#eff6ff80}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-300{--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-gray-500\/10{background-color:#6b72801a}.bg-gray-500\/20{background-color:#6b728033}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-gray-900\/40{background-color:#11182766}.bg-gray-950{--tw-bg-opacity: 1;background-color:rgb(3 7 18 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-500\/15{background-color:#22c55e26}.bg-orange-500\/10{background-color:#f973161a}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/15{background-color:#ef444426}.bg-sky-100{--tw-bg-opacity: 1;background-color:rgb(224 242 254 / var(--tw-bg-opacity, 1))}.bg-sky-500\/15{background-color:#0ea5e926}.bg-sky-500\/20{background-color:#0ea5e933}.bg-sky-500\/5{background-color:#0ea5e90d}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/95{background-color:#fffffff2}.bg-yellow-500\/10{background-color:#eab3081a}.fill-gray-400{fill:#9ca3af}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-0\.5{padding-bottom:.125rem}.pb-1{padding-bottom:.25rem}.pb-1\.5{padding-bottom:.375rem}.pb-3{padding-bottom:.75rem}.pl-0\.5{padding-left:.125rem}.pl-2{padding-left:.5rem}.pl-2\.5{padding-left:.625rem}.pr-1{padding-right:.25rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pr-28{padding-right:7rem}.pr-4{padding-right:1rem}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-\[1\.45\]{line-height:1.45}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-\[\#8957e5\]{--tw-text-opacity: 1;color:rgb(137 87 229 / var(--tw-text-opacity, 1))}.text-amber-200{--tw-text-opacity: 1;color:rgb(253 230 138 / var(--tw-text-opacity, 1))}.text-amber-500{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-amber-700\/80{color:#b45309cc}.text-amber-800{--tw-text-opacity: 1;color:rgb(146 64 14 / var(--tw-text-opacity, 1))}.text-blue-400\/50{color:#60a5fa80}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-500\/15{color:#3b82f626}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-emerald-500{--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity, 1))}.text-gray-100{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-400\/10{color:#9ca3af1a}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-green-300{--tw-text-opacity: 1;color:rgb(134 239 172 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-green-700\/70{color:#15803db3}.text-green-700\/80{color:#15803dcc}.text-orange-500{--tw-text-opacity: 1;color:rgb(249 115 22 / var(--tw-text-opacity, 1))}.text-orange-700{--tw-text-opacity: 1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.text-purple-500{--tw-text-opacity: 1;color:rgb(168 85 247 / var(--tw-text-opacity, 1))}.text-purple-600{--tw-text-opacity: 1;color:rgb(147 51 234 / var(--tw-text-opacity, 1))}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-sky-400\/80{color:#38bdf8cc}.text-sky-500{--tw-text-opacity: 1;color:rgb(14 165 233 / var(--tw-text-opacity, 1))}.text-sky-600{--tw-text-opacity: 1;color:rgb(2 132 199 / var(--tw-text-opacity, 1))}.text-sky-700{--tw-text-opacity: 1;color:rgb(3 105 161 / var(--tw-text-opacity, 1))}.text-violet-500{--tw-text-opacity: 1;color:rgb(139 92 246 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-700{--tw-text-opacity: 1;color:rgb(161 98 7 / var(--tw-text-opacity, 1))}.opacity-0{opacity:0}.opacity-45{opacity:.45}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-blue-500{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur{--tw-backdrop-blur: blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[grid-template-rows\]{transition-property:grid-template-rows;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-500{transition-duration:.5s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}:root{color-scheme:light dark}html,body,#root{height:100%;margin:0}body{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}body:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(3 7 18 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}body{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif}.brand-title{font-family:Great Vibes,ui-serif,cursive;font-weight:400;font-size:1.75rem;line-height:1;letter-spacing:.3px;padding-bottom:2px;cursor:default;-webkit-user-select:none;-moz-user-select:none;user-select:none}.focus-indicator{display:inline-flex;align-items:center;gap:7px;padding:2px 10px;border-radius:9999px;letter-spacing:.5px;text-transform:uppercase;color:#0284c7;background:#38bdf81f;border:1px solid rgba(56,189,248,.4);white-space:nowrap;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;font:inherit;font-size:11px;font-weight:600;transition:box-shadow .15s ease}.focus-indicator:hover{animation:ev-select-pulse 1.8s ease-in-out infinite}.dark .focus-indicator{color:#7dd3fc}.focus-indicator-dot{width:7px;height:7px;border-radius:9999px;background:#38bdf8;box-shadow:0 0 #38bdf899;animation:focus-dot-pulse 1.8s ease-in-out infinite}.focus-indicator-close{display:inline-flex;align-items:center;justify-content:center;margin-left:1px;margin-right:-4px;width:16px;height:16px;border-radius:9999px;font-size:10px;line-height:1;color:inherit;opacity:0;transition:background .15s ease,opacity .15s ease}.focus-indicator:hover .focus-indicator-close{opacity:.95;background:#38bdf840;animation:focus-close-wobble 1s ease-out}@keyframes focus-close-wobble{0%{transform:rotate(0)}12%{transform:rotate(-14deg)}28%{transform:rotate(11deg)}44%{transform:rotate(-8deg)}60%{transform:rotate(5deg)}76%{transform:rotate(-2deg)}to{transform:rotate(0)}}@keyframes focus-dot-pulse{0%,to{box-shadow:0 0 #38bdf88c}50%{box-shadow:0 0 0 5px #38bdf800}}@media(prefers-reduced-motion:reduce){.focus-indicator-dot,.focus-indicator:hover,.focus-indicator:hover .focus-indicator-close{animation:none}}.focus-frame{position:relative}.focus-frame:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:20;pointer-events:none;border:1.5px solid rgba(56,189,248,.8);border-radius:8px;animation:focus-frame-pulse 2.4s ease-in-out infinite}@keyframes focus-frame-pulse{0%,to{box-shadow:inset 0 0 0 1px #38bdf81f,inset 0 0 10px #38bdf81a}50%{box-shadow:inset 0 0 0 1px #38bdf847,inset 0 0 18px 2px #38bdf833}}@media(prefers-reduced-motion:reduce){.focus-frame:after{animation:none}}.filters-disabled{opacity:.45;pointer-events:none}.md-body{font-size:13px;line-height:1.5;word-break:break-word}.md-body>*:first-child{margin-top:0}.md-body>*:last-child{margin-bottom:0}.md-body p{margin:.5em 0}.md-body h1,.md-body h2,.md-body h3{font-weight:600;margin:.6em 0 .3em}.md-body ul,.md-body ol{margin:.5em 0;padding-left:1.4em}.md-body ul{list-style:disc}.md-body ol{list-style:decimal}.md-body li{margin:.15em 0}.md-body a{color:#3b82f6;text-decoration:underline}.md-body code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em;background:#7f7f7f2e;padding:.1em .3em;border-radius:4px}.md-body pre{margin:.5em 0;padding:.7em;border-radius:6px;overflow-x:auto;background:#0d1117}.md-body pre code{background:transparent;padding:0}.md-body blockquote{border-left:3px solid rgba(127,127,127,.4);padding-left:.8em;margin:.5em 0;color:#9ca3af}.md-body table{border-collapse:collapse;margin:.5em 0}.md-body th,.md-body td{border:1px solid rgba(127,127,127,.3);padding:.3em .6em}.md-body img{max-width:100%;max-height:24rem;width:auto;height:auto}.pr-summary-collapsed .pr-summary-tall-img{display:none}.md-body input[type=checkbox]{margin-right:.4em}.dark .vis-timeline{border-color:#1f2937}.dark .vis-panel .vis-content,.dark .vis-panel .vis-background,.dark .vis-labelset .vis-label,.dark .vis-foreground .vis-group{border-color:#1f2937;color:#e5e7eb}.dark .vis-time-axis .vis-text{color:#9ca3af}.dark .vis-time-axis .vis-grid.vis-minor{border-color:#1f2937}.dark .vis-time-axis .vis-grid.vis-major{border-color:#374151}.dark .vis-labelset .vis-label{color:#d1d5db}.dark .vis-current-time{background-color:#ef4444}.vis-labelset .vis-label.vis-nested-group{padding-left:.625rem;font-size:11px;opacity:.85}.vis-labelset .vis-label.tl-user-row .vis-inner{width:100%;max-width:264px}.tl-user{display:flex;align-items:flex-start;gap:5px;min-width:0;width:100%}.tl-user-main{display:flex;flex-direction:column;min-width:0;flex:1 1 auto;gap:1px}.tl-user-name-line{display:flex;align-items:center;gap:5px;min-width:0}.tl-collapse-caret{flex:none;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:-1px;padding:0;border:0;border-radius:3px;background:transparent;color:#9ca3af;font-size:13px;line-height:1;cursor:pointer}.tl-collapse-caret:hover{background:#7878782e;color:#374151}.dark .tl-collapse-caret:hover{color:#e5e7eb}.tl-focus-active .tl-collapse-caret{display:none}.tl-stats-toggle{flex:none;display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;border-radius:3px;background:transparent;color:#9ca3af;line-height:1;cursor:pointer}.tl-stats-toggle:hover{background:#7878782e;color:#374151}.dark .tl-stats-toggle:hover{color:#e5e7eb}.tl-user-avatar{flex:none;width:18px;height:18px;border-radius:9999px;-o-object-fit:cover;object-fit:cover;background:#e5e7eb}.dark .tl-user-avatar{background:#374151}.tl-user-avatar-fallback{display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#6b7280}.tl-user-name{font-size:12.5px;font-weight:600;flex:0 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tl-user-name-link{color:inherit;text-decoration:none;cursor:pointer}.tl-user-name-link:hover{text-decoration:underline}.tl-merger{flex:none;display:inline-flex;align-items:center}.tl-modal-header{display:flex;align-items:center;gap:6px;padding:4px 8px;cursor:move;-webkit-user-select:none;-moz-user-select:none;user-select:none;touch-action:none;border-bottom:1px solid #e5e7eb;background:#f9fafb;border-top-left-radius:.5rem;border-top-right-radius:.5rem}.dark .tl-modal-header{border-color:#374151;background:#11182799}.tl-modal-header:active{cursor:grabbing}.tl-grip{flex:none;color:#9ca3af}.tl-modal-title{font-size:11px;color:#9ca3af;margin-right:auto}.tl-modal-close{flex:none;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:4px;font-size:12px;line-height:1;color:#9ca3af;cursor:pointer}.tl-modal-close:hover{background:#94a3b833;color:#374151}.dark .tl-modal-close:hover{color:#e5e7eb}.vis-labelset .vis-label.tl-user-row,.vis-foreground .vis-group.tl-user-row{transition:max-height .22s ease,opacity .22s ease}@media(prefers-reduced-motion:reduce){.vis-labelset .vis-label.tl-user-row,.vis-foreground .vis-group.tl-user-row{transition:none}}.tl-repo-tint-0{--tl-tint: 59 130 246}.tl-repo-tint-1{--tl-tint: 139 92 246}.tl-repo-watch{display:inline-flex;align-items:center;margin-left:5px;color:#0ea5e9;vertical-align:middle}.vis-labelset .vis-label.tl-user-row[class*=tl-repo-tint-],.vis-foreground .vis-group.tl-user-row[class*=tl-repo-tint-],.vis-labelset .vis-label.tl-repo-header[class*=tl-repo-tint-],.vis-foreground .vis-group.tl-repo-header[class*=tl-repo-tint-]{background-color:rgb(var(--tl-tint) / .1)}.dark .vis-labelset .vis-label.tl-user-row[class*=tl-repo-tint-],.dark .vis-foreground .vis-group.tl-user-row[class*=tl-repo-tint-],.dark .vis-labelset .vis-label.tl-repo-header[class*=tl-repo-tint-],.dark .vis-foreground .vis-group.tl-repo-header[class*=tl-repo-tint-]{background-color:rgb(var(--tl-tint) / .13)}.vis-labelset .vis-label.tl-user-row:nth-child(2n),.vis-foreground .vis-group.tl-user-row:nth-child(2n){background-image:linear-gradient(#0f172a0d,#0f172a0d)}.dark .vis-labelset .vis-label.tl-user-row:nth-child(2n),.dark .vis-foreground .vis-group.tl-user-row:nth-child(2n){background-image:linear-gradient(#ffffff0d,#ffffff0d)}.vis-labelset .vis-label.tl-user-row,.vis-foreground .vis-group.tl-user-row{box-shadow:inset 0 -2px #0f172a33}.dark .vis-labelset .vis-label.tl-user-row,.dark .vis-foreground .vis-group.tl-user-row{box-shadow:inset 0 -2px #ffffff29}.vis-item.vis-range.pr-bar{border-radius:6px;border-width:1px;color:#fff;font-size:11px;cursor:pointer;z-index:2;min-width:4px}.vis-item.pr-emph{font-size:11px}.vis-item.pr-muted{opacity:.85;font-size:10px}.vis-item.pr-muted .pr-title{max-width:16ch}.pr-status{display:flex;align-items:center;gap:5px;padding:1px 4px 2px;font-size:9px;line-height:1.2}.pr-ci{display:inline-block;width:7px;height:7px;border-radius:50%}.pr-warn{color:#fdba74;font-weight:700}.pr-comment-mark{display:inline-flex;align-items:center;color:#e0f2fe;opacity:.85}.pr-comment-mark svg{display:block}.vis-item.pr-muted .pr-comment-mark{margin-left:2px;opacity:.75}.vis-item.pr-bar.pr-open{background-color:#1d4ed8;border-color:#3b82f6}.vis-item.pr-bar.pr-merged{background-color:#15803d;border-color:#22c55e}.vis-item.pr-bar.pr-closed{background-color:#4b5563;border-color:#9ca3af}.vis-item.pr-draft{background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.12),rgba(255,255,255,.12) 4px,transparent 4px,transparent 8px)}.vis-item.pr-stalled{box-shadow:0 0 0 2px #ef4444}.vis-item.vis-selected.pr-bar{overflow:visible;z-index:5;animation:ev-select-pulse 1.8s ease-in-out infinite}.vis-item.pr-bar.pr-focus-hidden{display:none}@media(prefers-reduced-motion:reduce){.vis-item.vis-selected.pr-bar{animation:none;box-shadow:0 0 0 3px #38bdf8d9,0 0 12px 3px #38bdf880}}.vis-item.pr-bar.pr-cross-linked,.vis-item.ev-cross-linked .ev-marker-inner,.vis-item.ev-cross-linked .ev-cluster-inner{animation:ev-select-pulse 1.8s ease-in-out infinite}.vis-item.pr-bar.pr-cross-linked{overflow:visible;z-index:5}.vis-item.ev-cross-linked .ev-marker-inner,.vis-item.ev-cross-linked .ev-cluster-inner{position:relative;z-index:5}.vis-item.ev-cross-linked .ev-marker-inner{border-radius:9999px}@media(prefers-reduced-motion:reduce){.vis-item.pr-bar.pr-cross-linked,.vis-item.ev-cross-linked .ev-marker-inner,.vis-item.ev-cross-linked .ev-cluster-inner{animation:none;box-shadow:0 0 0 3px #38bdf8d9,0 0 12px 3px #38bdf880}}.vis-item.ev-exit-glow .ev-marker-inner,.vis-item.ev-exit-glow .ev-cluster-inner{position:relative;z-index:5;animation:ev-select-pulse 1.8s ease-in-out infinite}.vis-item.ev-exit-glow .ev-marker-inner{border-radius:9999px}@media(prefers-reduced-motion:reduce){.vis-item.ev-exit-glow .ev-marker-inner,.vis-item.ev-exit-glow .ev-cluster-inner{animation:none;box-shadow:0 0 0 3px #38bdf8cc,0 0 12px 3px #38bdf880}}@keyframes ev-select-pulse{0%,to{box-shadow:0 0 0 3px #38bdf8d9,0 0 14px 5px #38bdf88c}50%{box-shadow:0 0 0 5px #38bdf866,0 0 8px 2px #38bdf840}}.vis-item.ev-selected:not(.ev-cross-linked) .ev-marker-inner,.vis-item.ev-selected:not(.ev-cross-linked) .ev-cluster-inner{position:relative;z-index:5;animation:ev-select-pulse 1.8s ease-in-out infinite}.vis-item.ev-selected:not(.ev-cross-linked) .ev-marker-inner{border-radius:9999px}@media(prefers-reduced-motion:reduce){.vis-item.ev-selected:not(.ev-cross-linked) .ev-marker-inner,.vis-item.ev-selected:not(.ev-cross-linked) .ev-cluster-inner{animation:none;box-shadow:0 0 0 3px #38bdf8d9,0 0 12px 3px #38bdf880}}.pr-bar-inner{display:flex;align-items:center;gap:4px;padding:0 2px}.pr-num{font-weight:700;opacity:.85}.pr-avatar{border-radius:9999px;flex-shrink:0;vertical-align:middle}.pr-author{font-size:10px;opacity:.8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:12ch}.vis-item.pr-muted .pr-author{max-width:9ch}.pr-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:22ch}.pr-draft-tag{font-size:9px;text-transform:uppercase;background:#00000040;border-radius:3px;padding:0 3px}.pr-stall{color:#fca5a5}.pr-dots{display:inline-flex;align-items:center;gap:2px;margin-left:2px}.pr-dot{display:inline-block;width:7px;height:7px;border-radius:50%}.pr-dot-n{font-size:9px;font-weight:700;margin-right:3px}.vis-item.ev-marker,.vis-item.ev-cluster{background:transparent;border:none;box-shadow:none;pointer-events:none}.vis-item.ev-marker .vis-dot,.vis-item.ev-cluster .vis-dot{display:none}.vis-item.ev-marker .vis-item-content,.vis-item.ev-cluster .vis-item-content{transform:translate(-50%);padding:0}.ev-marker-inner{display:flex;align-items:center;justify-content:center;cursor:pointer;position:relative;pointer-events:auto}.ev-marker-inner svg{display:block}.ev-cluster-inner{display:flex;align-items:center;justify-content:center;gap:2px;min-width:18px;height:16px;padding:0 4px;border-radius:9px;background:#475569;color:#fff;font-size:10px;font-weight:700;line-height:1;cursor:pointer;border:1px solid rgba(255,255,255,.25);position:relative;pointer-events:auto}.vis-item.ev-cluster.vis-selected,.vis-item.ev-marker.vis-selected{background:transparent;box-shadow:none}.vis-item.vis-background.cross-sep{border-top:1px solid rgba(99,102,241,.38);background:#6366f10f;pointer-events:none}.dark .vis-item.vis-background.cross-sep{border-top-color:#818cf86b;background:#818cf817}.vis-item.ev-own .ev-marker-inner:after,.vis-item.ev-own .ev-cluster-inner:after{content:"";position:absolute;bottom:100%;left:50%;width:0;height:14px;border-left:1.5px solid rgba(203,213,225,.85);transform:translate(-50%);pointer-events:none}.vis-item.ev-own .ev-marker-inner.ev-round:after{bottom:calc(100% - 3px);height:17px}.tl-cross-connectors{position:absolute;pointer-events:none;overflow:hidden;z-index:5}.tl-cross-connectors path{stroke:#cbd5e1d9;stroke-width:1.5;fill:none}.dark .tl-cross-connectors path{stroke:#94a3b8b3}.vis-item.ev-cross .ev-marker-inner{border-radius:9999px;background:#6366f11a}.vis-item.ev-cross:not(.ev-selected):not(.ev-cross-linked):not(.ev-exit-glow) .ev-marker-inner{box-shadow:inset 0 0 0 1px #6366f16b}.vis-item.ev-cross:not(.ev-selected):not(.ev-cross-linked):not(.ev-exit-glow) .ev-cluster-inner{box-shadow:0 0 0 2px #6366f140}.dark .vis-item.ev-cross .ev-marker-inner{background:#818cf829}.dark .vis-item.ev-cross:not(.ev-selected):not(.ev-cross-linked):not(.ev-exit-glow) .ev-marker-inner{box-shadow:inset 0 0 0 1px #818cf885}.dark .vis-item.ev-cross:not(.ev-selected):not(.ev-cross-linked):not(.ev-exit-glow) .ev-cluster-inner{box-shadow:0 0 0 2px #818cf852}.vis-item.vis-point .vis-dot{border-width:5px}.ev-pr_opened .vis-dot{border-color:#3b82f6}.ev-pr_merged .vis-dot{border-color:#8957e5}.ev-pr_closed .vis-dot{border-color:#9ca3af}.ev-review_submitted .vis-dot{border-color:#22c55e}.ev-review_comment .vis-dot{border-color:#f59e0b}.ev-pr_comment .vis-dot{border-color:#a78bfa}.ev-commit_pushed .vis-dot{border-color:#6b7280;border-width:4px}.ev-diamond .vis-dot{border-radius:0;transform:rotate(45deg)}.ev-square .vis-dot{border-radius:2px}.comment-new{border-left:3px solid #38bdf8;margin-left:-2px;border-radius:1px;background:#38bdf80d}@keyframes activity-flash{0%{background:#38bdf847}to{background:#38bdf800}}.activity-flash{animation:activity-flash 1.8s ease-out forwards}@keyframes myturn-pulse{0%,to{opacity:1}50%{opacity:.35}}.my-turn-ring,.vis-item.pr-myturn{position:relative;overflow:visible}.my-turn-ring:after,.vis-item.pr-myturn:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;border-radius:inherit;box-shadow:0 0 0 2px #3b82f6e6;animation:myturn-pulse 2s ease-in-out infinite;will-change:opacity}@media(prefers-reduced-motion:reduce){.my-turn-ring:after,.vis-item.pr-myturn:after{animation:none;opacity:.85}}.first\:border-0:first-child{border-width:0px}.first\:pt-0:first-child{padding-top:0}.last\:mb-0:last-child{margin-bottom:0}.last\:pb-0:last-child{padding-bottom:0}.hover\:border-blue-500:hover{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.hover\:border-gray-400:hover{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1))}.hover\:border-red-400:hover{--tw-border-opacity: 1;border-color:rgb(248 113 113 / var(--tw-border-opacity, 1))}.hover\:border-sky-400:hover{--tw-border-opacity: 1;border-color:rgb(56 189 248 / var(--tw-border-opacity, 1))}.hover\:bg-amber-100:hover{--tw-bg-opacity: 1;background-color:rgb(254 243 199 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-400:hover{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-50:hover{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-700:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-200\/60:hover{background-color:#e5e7eb99}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-green-50:hover{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.hover\:bg-purple-50:hover{--tw-bg-opacity: 1;background-color:rgb(250 245 255 / var(--tw-bg-opacity, 1))}.hover\:bg-red-50:hover{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.hover\:bg-sky-100:hover{--tw-bg-opacity: 1;background-color:rgb(224 242 254 / var(--tw-bg-opacity, 1))}.hover\:bg-sky-50:hover{--tw-bg-opacity: 1;background-color:rgb(240 249 255 / var(--tw-bg-opacity, 1))}.hover\:bg-sky-500\/25:hover{background-color:#0ea5e940}.hover\:text-amber-700:hover{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.hover\:text-blue-500:hover{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.focus\:opacity-100:focus{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-sky-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(56 189 248 / var(--tw-ring-opacity, 1))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus\:ring-offset-gray-950:focus{--tw-ring-offset-color: #030712}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:no-underline:disabled{text-decoration-line:none}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.group:hover .group-hover\:text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:opacity-100{opacity:1}@media(prefers-reduced-motion:reduce){.motion-reduce\:transition-none{transition-property:none}}.dark\:divide-gray-800:is(.dark *)>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(31 41 55 / var(--tw-divide-opacity, 1))}.dark\:border-amber-600:is(.dark *){--tw-border-opacity: 1;border-color:rgb(217 119 6 / var(--tw-border-opacity, 1))}.dark\:border-amber-700:is(.dark *){--tw-border-opacity: 1;border-color:rgb(180 83 9 / var(--tw-border-opacity, 1))}.dark\:border-amber-700\/60:is(.dark *){border-color:#b4530999}.dark\:border-amber-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(146 64 14 / var(--tw-border-opacity, 1))}.dark\:border-amber-900\/50:is(.dark *){border-color:#78350f80}.dark\:border-blue-600:is(.dark *){--tw-border-opacity: 1;border-color:rgb(37 99 235 / var(--tw-border-opacity, 1))}.dark\:border-blue-900\/50:is(.dark *){border-color:#1e3a8a80}.dark\:border-gray-600:is(.dark *){--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.dark\:border-gray-700:is(.dark *){--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.dark\:border-gray-800:is(.dark *){--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity, 1))}.dark\:border-green-600:is(.dark *){--tw-border-opacity: 1;border-color:rgb(22 163 74 / var(--tw-border-opacity, 1))}.dark\:border-green-700\/50:is(.dark *){border-color:#15803d80}.dark\:border-green-700\/60:is(.dark *){border-color:#15803d99}.dark\:border-purple-700:is(.dark *){--tw-border-opacity: 1;border-color:rgb(126 34 206 / var(--tw-border-opacity, 1))}.dark\:border-red-700\/60:is(.dark *){border-color:#b91c1c99}.dark\:border-red-900:is(.dark *){--tw-border-opacity: 1;border-color:rgb(127 29 29 / var(--tw-border-opacity, 1))}.dark\:border-sky-700:is(.dark *){--tw-border-opacity: 1;border-color:rgb(3 105 161 / var(--tw-border-opacity, 1))}.dark\:border-t-blue-400:is(.dark *){--tw-border-opacity: 1;border-top-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.dark\:bg-amber-900\/20:is(.dark *){background-color:#78350f33}.dark\:bg-amber-900\/40:is(.dark *){background-color:#78350f66}.dark\:bg-amber-950\/40:is(.dark *){background-color:#451a0366}.dark\:bg-blue-500\/5:is(.dark *){background-color:#3b82f60d}.dark\:bg-blue-900\/10:is(.dark *){background-color:#1e3a8a1a}.dark\:bg-blue-900\/20:is(.dark *){background-color:#1e3a8a33}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-800\/50:is(.dark *){background-color:#1f293780}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.dark\:bg-gray-900\/50:is(.dark *){background-color:#11182780}.dark\:bg-gray-900\/60:is(.dark *){background-color:#11182799}.dark\:bg-gray-900\/95:is(.dark *){background-color:#111827f2}.dark\:bg-gray-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(3 7 18 / var(--tw-bg-opacity, 1))}.dark\:bg-green-900\/20:is(.dark *){background-color:#14532d33}.dark\:bg-red-900\/20:is(.dark *){background-color:#7f1d1d33}.dark\:bg-sky-900\/50:is(.dark *){background-color:#0c4a6e80}.dark\:text-amber-200:is(.dark *){--tw-text-opacity: 1;color:rgb(253 230 138 / var(--tw-text-opacity, 1))}.dark\:text-amber-300:is(.dark *){--tw-text-opacity: 1;color:rgb(252 211 77 / var(--tw-text-opacity, 1))}.dark\:text-amber-300\/80:is(.dark *){color:#fcd34dcc}.dark\:text-amber-400:is(.dark *){--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.dark\:text-blue-300:is(.dark *){--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.dark\:text-blue-300\/40:is(.dark *){color:#93c5fd66}.dark\:text-blue-400:is(.dark *){--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.dark\:text-blue-400\/15:is(.dark *){color:#60a5fa26}.dark\:text-gray-100:is(.dark *){--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.dark\:text-gray-300:is(.dark *){--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.dark\:text-gray-300\/10:is(.dark *){color:#d1d5db1a}.dark\:text-gray-400:is(.dark *){--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.dark\:text-gray-500:is(.dark *){--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.dark\:text-gray-600:is(.dark *){--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.dark\:text-gray-700:is(.dark *){--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.dark\:text-gray-800:is(.dark *){--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.dark\:text-green-300:is(.dark *){--tw-text-opacity: 1;color:rgb(134 239 172 / var(--tw-text-opacity, 1))}.dark\:text-green-400:is(.dark *){--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.dark\:text-green-400\/70:is(.dark *){color:#4ade80b3}.dark\:text-green-400\/80:is(.dark *){color:#4ade80cc}.dark\:text-green-500:is(.dark *){--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.dark\:text-orange-400:is(.dark *){--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.dark\:text-purple-300:is(.dark *){--tw-text-opacity: 1;color:rgb(216 180 254 / var(--tw-text-opacity, 1))}.dark\:text-red-300:is(.dark *){--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.dark\:text-sky-300:is(.dark *){--tw-text-opacity: 1;color:rgb(125 211 252 / var(--tw-text-opacity, 1))}.dark\:text-sky-400:is(.dark *){--tw-text-opacity: 1;color:rgb(56 189 248 / var(--tw-text-opacity, 1))}.dark\:text-yellow-500:is(.dark *){--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.dark\:hover\:border-gray-500:hover:is(.dark *){--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity, 1))}.dark\:hover\:bg-amber-900\/40:hover:is(.dark *){background-color:#78350f66}.dark\:hover\:bg-blue-500:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-blue-900\/30:hover:is(.dark *){background-color:#1e3a8a4d}.dark\:hover\:bg-gray-700:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-gray-700\/60:hover:is(.dark *){background-color:#37415199}.dark\:hover\:bg-gray-800:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-gray-800\/60:hover:is(.dark *){background-color:#1f293799}.dark\:hover\:bg-gray-900:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-gray-900\/40:hover:is(.dark *){background-color:#11182766}.dark\:hover\:bg-gray-900\/50:hover:is(.dark *){background-color:#11182780}.dark\:hover\:bg-green-900\/30:hover:is(.dark *){background-color:#14532d4d}.dark\:hover\:bg-purple-900\/30:hover:is(.dark *){background-color:#581c874d}.dark\:hover\:bg-red-950:hover:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(69 10 10 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-sky-900\/30:hover:is(.dark *){background-color:#0c4a6e4d}.dark\:hover\:bg-sky-900\/40:hover:is(.dark *){background-color:#0c4a6e66}.dark\:hover\:text-amber-300:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(252 211 77 / var(--tw-text-opacity, 1))}.dark\:hover\:text-gray-100:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.dark\:hover\:text-gray-200:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.dark\:hover\:text-gray-300:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}@media(min-width:640px){.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}@media(min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}
|