@bloomscorp/blooms-ai-embed 0.1.0 → 0.2.0
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/CHANGELOG.md +146 -1
- package/README.md +85 -10
- package/dist/blooms-embed.css +1 -1
- package/dist/blooms-embed.js +1 -10
- package/dist/chunk-3U3MLDTP.js +1 -0
- package/dist/chunk-4PL37FNN.js +74 -0
- package/dist/chunk-53INJES5.js +1 -0
- package/dist/chunk-5NLZKRFI.js +3 -0
- package/dist/chunk-7ENRHCKA.js +3 -0
- package/dist/chunk-7NQRVCWL.js +1 -0
- package/dist/chunk-ACC77NVF.js +3 -0
- package/dist/chunk-EA7SZINY.js +1 -0
- package/dist/chunk-GWYYXSOG.js +3 -0
- package/dist/chunk-HLIQJSA7.js +24 -0
- package/dist/chunk-IRBW4XXQ.js +1 -0
- package/dist/chunk-OBI6OSSF.js +1 -0
- package/dist/chunk-OSBW6YXS.js +1 -0
- package/dist/chunk-OSUK4H76.js +3 -0
- package/dist/chunk-QVZ2D36I.js +1 -0
- package/dist/chunk-RL3EC5EG.js +3 -0
- package/dist/chunk-SPLW6L45.js +2 -0
- package/dist/chunk-T4IZD3WN.js +1 -0
- package/dist/chunk-UQVX3SID.js +3 -0
- package/dist/chunk-VQEBAAHK.js +1 -0
- package/dist/chunk-WFG2A6RA.js +3 -0
- package/dist/chunk-WQW7QCHM.js +7 -0
- package/dist/chunk-X2Q5WSIJ.js +2 -0
- package/dist/chunk-X5SAQDWB.js +3 -0
- package/dist/chunk-XZWMQ7QK.js +3 -0
- package/dist/chunk-YDIWMCSH.js +3 -0
- package/dist/chunk-ZZTWS6NP.js +3 -0
- package/dist/index.d.ts +221 -3
- package/dist/index.js +16 -6
- package/dist/media/poppins-latin-400.woff2 +0 -0
- package/dist/media/poppins-latin-500.woff2 +0 -0
- package/dist/media/poppins-latin-600.woff2 +0 -0
- package/dist/media/poppins-latin-700.woff2 +0 -0
- package/package.json +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,146 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@bloomscorp/blooms-ai-embed`.
|
|
4
4
|
|
|
5
|
+
## 0.2.0
|
|
6
|
+
|
|
7
|
+
Twelve new components, and the bundle is now code-split so adopting one does not
|
|
8
|
+
cost you all of them.
|
|
9
|
+
|
|
10
|
+
Upgrading is a drop-in **unless you branch on `customElements.get()`** or stage
|
|
11
|
+
`dist/` by hand — see *Action if you are upgrading* below.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Twelve new elements.** `<blooms-login>` is no longer the only thing you can
|
|
16
|
+
embed:
|
|
17
|
+
|
|
18
|
+
| | | |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `<blooms-crawl-insights>` | `<blooms-sitemap-crawl>` | `<blooms-sitemap-crawl-detail>` |
|
|
21
|
+
| `<blooms-keywords>` | `<blooms-keyword-detail>` | `<blooms-reports>` |
|
|
22
|
+
| `<blooms-gmc-analytics>` | `<blooms-social-media-calendar>` | `<blooms-smc-day-detail>` |
|
|
23
|
+
| `<blooms-influencer-dashboard>` | `<blooms-influencer-detail>` | `<blooms-blog-strategy>` |
|
|
24
|
+
|
|
25
|
+
Each takes its state through attributes or properties rather than a URL, since
|
|
26
|
+
a custom element cannot read the host page's address bar: `project-id` on most,
|
|
27
|
+
plus `crawl-id`, `keyword-id`, `influencer-id`, `strategy-id`, `event-id`,
|
|
28
|
+
`date-iso` where the component addresses one record. Components that used to
|
|
29
|
+
navigate now emit a `bloomsnavigate` event describing where they would have
|
|
30
|
+
gone — your app decides what that means.
|
|
31
|
+
|
|
32
|
+
Declared in `HTMLElementTagNameMap`, so TypeScript knows all thirteen tags.
|
|
33
|
+
|
|
34
|
+
- **`preload(...features)`.** Fetches a component's code before it is needed:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
await BloomsEmbed.preload('crawl-insights', 'keywords');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Optional and never throws — a failed preload just means the chunk is fetched
|
|
41
|
+
later, when the component is actually mounted.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **The bundle is code-split: one lazily-fetched chunk per component.** Shipping
|
|
46
|
+
thirteen components eagerly had grown the download to 162 kB gzipped, with the
|
|
47
|
+
three largest still unconverted — so every host paid for every component to use
|
|
48
|
+
one. Now:
|
|
49
|
+
|
|
50
|
+
| | Transfer (gzipped) |
|
|
51
|
+
|---|---|
|
|
52
|
+
| Loader + shared core | **~65 kB** |
|
|
53
|
+
| …plus one component | ~69 kB |
|
|
54
|
+
| …plus all thirteen | ~180 kB |
|
|
55
|
+
|
|
56
|
+
`dist/blooms-embed.js` is a ~3 kB loader; the components live in sibling
|
|
57
|
+
`dist/chunk-*.js` files that it imports by relative path on first use.
|
|
58
|
+
|
|
59
|
+
- **Elements are defined on demand, not at import.** A tag is registered the
|
|
60
|
+
first time an instance of it appears, and the browser upgrades the element that
|
|
61
|
+
was already there. Tags in your HTML behave exactly as before and there is
|
|
62
|
+
nothing to await. One observable difference:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
import { BloomsEmbed } from '@bloomscorp/blooms-ai-embed';
|
|
66
|
+
customElements.get('blooms-crawl-insights'); // undefined until one is used
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Setting a **property** before a component's chunk arrives is safe — the value
|
|
70
|
+
is applied once the component is defined. Attributes were never affected.
|
|
71
|
+
|
|
72
|
+
- **Write actions are enabled** for Social Media Calendar, Influencers and Blog
|
|
73
|
+
Strategy — create, edit, reschedule, delete, and the AI generation steps. They
|
|
74
|
+
were read-only in `0.1.x`, with controls that rendered and then returned 403.
|
|
75
|
+
|
|
76
|
+
### Action if you are upgrading
|
|
77
|
+
|
|
78
|
+
1. **If you bundle the package** (the recommended setup, and what the Electron
|
|
79
|
+
guide describes) — nothing to do. Webpack, Vite, esbuild and Rollup all follow
|
|
80
|
+
the dynamic imports and emit their own chunks.
|
|
81
|
+
|
|
82
|
+
2. **If you stage `dist/` by hand**, copy **all** of it. `chunk-*.js` must sit in
|
|
83
|
+
the same directory as `blooms-embed.js`. Copying only the entry leaves you with
|
|
84
|
+
a package that installs cleanly and renders every component as a blank
|
|
85
|
+
element, with one console error per component as the only clue.
|
|
86
|
+
|
|
87
|
+
3. **Remove any `customElements.get()` guard** around showing a component. It was
|
|
88
|
+
reliable in `0.1.x` because every tag was defined at import; it is not now.
|
|
89
|
+
Place the tag, or call `mount()`, and let the loader do its work.
|
|
90
|
+
|
|
91
|
+
### Known gaps, stated so they are not surprises
|
|
92
|
+
|
|
93
|
+
- `<blooms-keyword-detail>`'s Search Console section is **empty when embedded**.
|
|
94
|
+
The underlying route takes its project id as a query parameter and carries no
|
|
95
|
+
authorization of its own, and our allowlist pins project ids in the path — so
|
|
96
|
+
exposing it would have handed every embedded session cross-project Search
|
|
97
|
+
Console data. The route is being fixed rather than the allowlist widened.
|
|
98
|
+
- Report generation (Crawl Insights) and bulk delete (Reports) are hidden when
|
|
99
|
+
embedded: their output is delivered to the blooms.ai portal, which a host app
|
|
100
|
+
cannot reach. Starting a job whose result you cannot collect is worse than not
|
|
101
|
+
offering it.
|
|
102
|
+
|
|
103
|
+
## 0.1.1
|
|
104
|
+
|
|
105
|
+
Everything here came from the first production Electron integration reporting
|
|
106
|
+
against `0.1.0`. No API changes — upgrading is a drop-in.
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- **Poppins is now self-hosted.** The stylesheet carried 18 `@font-face` rules
|
|
111
|
+
pointing at `fonts.gstatic.com`, inherited from a redundant `@import` in the
|
|
112
|
+
portal's global stylesheet. On a third-party page that is blocked by a
|
|
113
|
+
`font-src 'self'` CSP — so components silently fell back to a system font and
|
|
114
|
+
no longer matched blooms.ai — and it needed the network, contradicting the
|
|
115
|
+
claim that sign-in renders offline.
|
|
116
|
+
|
|
117
|
+
The package now ships the Poppins latin subset (400/500/600/700, **31 kB**) in
|
|
118
|
+
`dist/media/`, referenced relative to the stylesheet so it resolves through
|
|
119
|
+
`assetBase` in every delivery mode. The stylesheet shrank from 12.6 kB to
|
|
120
|
+
7.8 kB.
|
|
121
|
+
|
|
122
|
+
**Action if you are upgrading:** copy `dist/media/` alongside
|
|
123
|
+
`dist/blooms-embed.css`. Copying only the CSS leaves the fonts behind and the
|
|
124
|
+
`@font-face` rules 404. You can now drop `https://fonts.gstatic.com` from your
|
|
125
|
+
`font-src`.
|
|
126
|
+
|
|
127
|
+
- **Documentation named a host that does not exist.** Examples used
|
|
128
|
+
`https://api.blooms.ai`, which has never resolved. The production API origin is
|
|
129
|
+
`https://z.bloomscorp.com`. Corrected throughout — it matters because this is
|
|
130
|
+
the value integrators pin in a CSP.
|
|
131
|
+
|
|
132
|
+
- **Google-provisioned accounts were described wrongly.** The docs said such
|
|
133
|
+
users should "set a password in the portal first". They cannot: password reset
|
|
134
|
+
refuses them with `409 PASSWORD_NOT_APPLICABLE` by design, so that an account
|
|
135
|
+
governed by Google never grows a second credential. There is no self-service
|
|
136
|
+
path — a blooms.ai admin must provision a separate local account. Embedded
|
|
137
|
+
Google sign-in is planned, not built.
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
- The `0.1.0` changelog understated what shipped. `mount()`, `projects()`,
|
|
142
|
+
`project()`, `setProject()` and `can(key, projectId)` were all present in that
|
|
143
|
+
release's type declarations; they are now listed below.
|
|
144
|
+
|
|
5
145
|
## 0.1.0
|
|
6
146
|
|
|
7
147
|
First release.
|
|
@@ -11,7 +151,12 @@ First release.
|
|
|
11
151
|
components locally instead of loading remote code into a renderer, and work offline.
|
|
12
152
|
- Importing the package defines the custom elements (`<blooms-login>`) as a side effect and
|
|
13
153
|
exports the typed `BloomsEmbed` SDK: `configure`, `mode`, `manifest`, `login`, `session`,
|
|
14
|
-
`resume`, `can`, `logout`, `on`.
|
|
154
|
+
`resume`, `can`, `projects`, `project`, `setProject`, `logout`, `on`, `mount`.
|
|
155
|
+
- Multi-project integrations: one token can span several projects, and `projects()` /
|
|
156
|
+
`setProject()` / `can(key, projectId)` switch between them locally with no re-authentication.
|
|
157
|
+
`can()` returns `false` for a project the session cannot act on rather than falling back.
|
|
158
|
+
- `mount(target, { feature })` renders a component in whichever mode `configure()` resolved —
|
|
159
|
+
the custom element directly, or the iframe shell for an opaque origin.
|
|
15
160
|
- Hand-written TypeScript declarations for the whole public surface, including
|
|
16
161
|
`<blooms-login>` in `HTMLElementTagNameMap` and `BloomsEmbed` on `Window`.
|
|
17
162
|
- Importing outside a browser throws an explanatory error naming the likely cause (SSR, or the
|
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ in that project, narrowed further to the features enabled on your token. No sess
|
|
|
44
44
|
|
|
45
45
|
BloomsEmbed.configure({
|
|
46
46
|
token: 'blm_embed_9f2c…',
|
|
47
|
-
apiBase: 'https://
|
|
47
|
+
apiBase: 'https://z.bloomscorp.com',
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
BloomsEmbed.on('session', event => {
|
|
@@ -59,11 +59,49 @@ That is the whole integration. Importing the package defines the elements and in
|
|
|
59
59
|
`<blooms-login>` renders the sign-in form, remembers the session across reloads, and revalidates
|
|
60
60
|
it on the next load.
|
|
61
61
|
|
|
62
|
+
### Elements in this bundle
|
|
63
|
+
|
|
64
|
+
| Tag | What it renders | Token ceiling it needs |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `<blooms-login>` | Sign-in form, session persistence, precise error states | — |
|
|
67
|
+
| `<blooms-crawl-insights>` | Crawl results: pages crawled, broken links, page issues, missing meta, duplicate titles, health score. Starts crawls and re-scans single URLs. | `crawl-insights` (or `crawl`) |
|
|
68
|
+
| `<blooms-sitemap-crawl>` | Crawl from a sitemap: start a run, watch progress, browse history. | `sitemap` (or `crawl`) |
|
|
69
|
+
| `<blooms-sitemap-crawl-detail>` | One sitemap run in detail. Takes `crawl-id`. | `sitemap` (or `crawl`) |
|
|
70
|
+
| `<blooms-keywords>` | Tracked keywords: rank, volume, difficulty, trend. Adds keywords, triggers a rank sync. | `manager` |
|
|
71
|
+
| `<blooms-keyword-detail>` | One keyword in detail. Takes `keyword-id`. Its Search Console section is empty when embedded — see below. | `manager` |
|
|
72
|
+
| `<blooms-reports>` | Report list and downloads. Generation and bulk delete are hidden when embedded. | `manager` |
|
|
73
|
+
| `<blooms-gmc-analytics>` | Google Merchant Centre overview: feed health, disapprovals, account issues. | `manager` |
|
|
74
|
+
| `<blooms-social-media-calendar>` | Content calendar: month and list views, statuses, attachments, assignees. Create, edit, reschedule, delete. Takes `event-id` to deep-link a drawer. | `social-media-calendar` |
|
|
75
|
+
| `<blooms-smc-day-detail>` | One day of the calendar. Takes `date-iso` (`YYYY-MM-DD`), required. | `social-media-calendar` |
|
|
76
|
+
| `<blooms-influencer-dashboard>` | Tracked influencers with tiers, platforms, latest metrics. Create and edit. | `influencer-management` |
|
|
77
|
+
| `<blooms-influencer-detail>` | One influencer: profile, platforms, snapshots. Takes `influencer-id`. | `influencer-management` |
|
|
78
|
+
| `<blooms-blog-strategy>` | The blog authoring workflow: topic → SEO research → outline → draft → visuals → metadata → review → publish → promotion → performance. Takes `strategy-id` and `step`. | `blog-publishing` |
|
|
79
|
+
|
|
80
|
+
A `manager` or `owner` ceiling covers all of them, so one token needs no edit as
|
|
81
|
+
you adopt more. The keys above matter only for a deliberately narrow ceiling —
|
|
82
|
+
and Keywords, Reports and GMC are gated on `manager` itself, so a narrow ceiling
|
|
83
|
+
cannot include them without including everything. A ceiling is never a grant: the
|
|
84
|
+
signed-in user's own per-project permissions are evaluated on every request.
|
|
85
|
+
|
|
86
|
+
Components that would navigate emit `bloomsnavigate` instead of routing — the
|
|
87
|
+
detail is in the Electron guide, and the payload is typed.
|
|
88
|
+
|
|
89
|
+
**Two deliberate gaps.** `<blooms-keyword-detail>`'s Search Console section is
|
|
90
|
+
empty when embedded: that route takes its project id as a query parameter and has
|
|
91
|
+
no authorization of its own, so exposing it would leak cross-project data — being
|
|
92
|
+
fixed server-side. Report generation and bulk delete are hidden because their
|
|
93
|
+
output is delivered to the blooms.ai portal, which your app cannot reach.
|
|
94
|
+
|
|
95
|
+
Feature elements render a sign-in prompt until a session exists, so you can place them
|
|
96
|
+
unconditionally. Each takes an optional `project-id`; omit it and the element follows the
|
|
97
|
+
session's active project, so `BloomsEmbed.setProject()` moves it.
|
|
98
|
+
|
|
62
99
|
Three things worth knowing:
|
|
63
100
|
|
|
64
|
-
- **`configure()` once, early.**
|
|
65
|
-
|
|
66
|
-
showing a skeleton meanwhile — so a slow `configure()`
|
|
101
|
+
- **`configure()` once, early.** An element placed in your HTML is upgraded when its chunk
|
|
102
|
+
arrives, which may be before or after your `configure()` call. Either order is fine: it waits
|
|
103
|
+
for configuration rather than failing, showing a skeleton meanwhile — so a slow `configure()`
|
|
104
|
+
is a slow first paint, not an error.
|
|
67
105
|
- **`apiBase` is optional** when you load the bundle from blooms.ai, because it defaults to the
|
|
68
106
|
bundle's own origin. When you install from npm the bundle's origin is *your* app, so **pass
|
|
69
107
|
`apiBase` explicitly**.
|
|
@@ -79,6 +117,7 @@ Three things worth knowing:
|
|
|
79
117
|
| `version` | `string` | Bundle version. |
|
|
80
118
|
| `configure` | `(config: BloomsEmbedConfig) => void` | Call first. Throws on a missing token or a token that is not `blm_embed_…`. |
|
|
81
119
|
| `mode` | `() => 'element' \| 'iframe' \| null` | The resolved rendering mode; `null` before `configure()`. |
|
|
120
|
+
| `preload` | `(...features: string[]) => Promise<void>` | Warms a component's lazy chunk before it is used. Optional, never throws. |
|
|
82
121
|
| `manifest` | `() => Promise<EmbedManifest>` | Pre-login bootstrap: project name, enabled features, theme, branding flag, session TTL. |
|
|
83
122
|
| `login` | `({ email, password }) => Promise<EmbedSessionState>` | Programmatic alternative to `<blooms-login>`, for hosts with their own form. |
|
|
84
123
|
| `session` | `() => EmbedSessionState \| null` | The current session, restored from storage by `configure()`. Synchronous. |
|
|
@@ -167,8 +206,10 @@ The element handles its own states: loading skeleton, signed-out form, signed-in
|
|
|
167
206
|
distinct messages for a wrong password, an account without access to the project, a deactivated
|
|
168
207
|
or banned account, and rate limiting.
|
|
169
208
|
|
|
170
|
-
Google sign-in is not offered
|
|
171
|
-
|
|
209
|
+
Google sign-in is not offered, and accounts created with Google **cannot use this form at all** —
|
|
210
|
+
they have no password and cannot set one (password reset refuses them by design, so that a
|
|
211
|
+
Google-governed account never grows a second credential). A blooms.ai admin must provision such
|
|
212
|
+
users a separate local account. Embedded Google sign-in is planned but not built.
|
|
172
213
|
|
|
173
214
|
---
|
|
174
215
|
|
|
@@ -210,7 +251,7 @@ These are read with fallbacks, so set only what you care about:
|
|
|
210
251
|
```js
|
|
211
252
|
BloomsEmbed.configure({
|
|
212
253
|
token: 'blm_embed_…',
|
|
213
|
-
apiBase: 'https://
|
|
254
|
+
apiBase: 'https://z.bloomscorp.com',
|
|
214
255
|
theme: { '--brand-primary': '#0f766e', '--radius-lg': '10px' },
|
|
215
256
|
});
|
|
216
257
|
```
|
|
@@ -236,7 +277,7 @@ React version):
|
|
|
236
277
|
import { useEffect } from 'react';
|
|
237
278
|
import { BloomsEmbed } from '@bloomscorp/blooms-ai-embed';
|
|
238
279
|
|
|
239
|
-
BloomsEmbed.configure({ token: 'blm_embed_…', apiBase: 'https://
|
|
280
|
+
BloomsEmbed.configure({ token: 'blm_embed_…', apiBase: 'https://z.bloomscorp.com' });
|
|
240
281
|
|
|
241
282
|
export function Login({ onSession }) {
|
|
242
283
|
useEffect(() => BloomsEmbed.on('session', e => onSession(e.session)), [onSession]);
|
|
@@ -339,7 +380,7 @@ cause is an unregistered origin or a missing privileged-scheme registration, not
|
|
|
339
380
|
|
|
340
381
|
```
|
|
341
382
|
default-src 'self' app:;
|
|
342
|
-
connect-src 'self' https://
|
|
383
|
+
connect-src 'self' https://z.bloomscorp.com;
|
|
343
384
|
style-src 'self' 'unsafe-inline';
|
|
344
385
|
img-src 'self' data: https:;
|
|
345
386
|
```
|
|
@@ -381,7 +422,7 @@ and add `BloomsEmbed` to `Window`.
|
|
|
381
422
|
```ts
|
|
382
423
|
import { BloomsEmbed, type EmbedSessionState } from '@bloomscorp/blooms-ai-embed';
|
|
383
424
|
|
|
384
|
-
BloomsEmbed.configure({ token: 'blm_embed_…', apiBase: 'https://
|
|
425
|
+
BloomsEmbed.configure({ token: 'blm_embed_…', apiBase: 'https://z.bloomscorp.com' });
|
|
385
426
|
|
|
386
427
|
const session: EmbedSessionState | null = await BloomsEmbed.resume();
|
|
387
428
|
if (session && BloomsEmbed.can('analytics')) { /* … */ }
|
|
@@ -407,6 +448,40 @@ In Electron, that also means: import it in the **renderer**, never in the main p
|
|
|
407
448
|
|
|
408
449
|
---
|
|
409
450
|
|
|
451
|
+
## Lazy loading
|
|
452
|
+
|
|
453
|
+
The bundle is code-split: a small loader plus one chunk per component, fetched the first time that
|
|
454
|
+
component is used. A page embedding one component downloads one component (~69 kB gzipped, against
|
|
455
|
+
~180 kB for the full set).
|
|
456
|
+
|
|
457
|
+
Nothing in your markup changes. A tag in your HTML is defined when its chunk arrives and the
|
|
458
|
+
browser upgrades the element that was already there. You never await anything.
|
|
459
|
+
|
|
460
|
+
Three things worth knowing:
|
|
461
|
+
|
|
462
|
+
- **Do not gate your UI on `customElements.get(tag)`.** It returns `undefined` until that
|
|
463
|
+
component has been used once. Before code splitting it was defined immediately, so a check like
|
|
464
|
+
this used to pass:
|
|
465
|
+
|
|
466
|
+
```js
|
|
467
|
+
import { BloomsEmbed } from '@bloomscorp/blooms-ai-embed';
|
|
468
|
+
if (customElements.get('blooms-keywords')) { /* no longer true up front */ }
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
- **Setting properties early is safe.** `el.projectId = '...'` on an element whose chunk has not
|
|
472
|
+
arrived is preserved and applied once the component is defined. Attributes were never affected.
|
|
473
|
+
|
|
474
|
+
- **Warm a chunk if you know what is next:**
|
|
475
|
+
|
|
476
|
+
```js
|
|
477
|
+
await BloomsEmbed.preload('crawl-insights', 'keywords');
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
If you stage `dist/` by hand instead of importing the package, copy **all** of it — `chunk-*.js`
|
|
481
|
+
must stay beside `blooms-embed.js`, and `media/*.woff2` beside the stylesheet.
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
410
485
|
## Security notes worth reading once
|
|
411
486
|
|
|
412
487
|
- The embed token is publishable, but it is not a secret to be careless with: it is what ties
|
package/dist/blooms-embed.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@charset "UTF-8";@font-face{font-family:Poppins;font-style:normal;font-weight:300;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLDz8Z11lFc-K.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Poppins;font-style:normal;font-weight:300;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLDz8Z1JlFc-K.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Poppins;font-style:normal;font-weight:300;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLDz8Z1xlFQ.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrJJbecmNE.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Poppins;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrJJnecmNE.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Poppins;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiEyp8kv8JHgFVrJJfecg.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLGT9Z11lFc-K.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Poppins;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLGT9Z1JlFc-K.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Poppins;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLGT9Z1xlFQ.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLEj6Z11lFc-K.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Poppins;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLEj6Z1JlFc-K.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Poppins;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLCz7Z11lFc-K.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Poppins;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLCz7Z1JlFc-K.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Poppins;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:800;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLDD4Z11lFc-K.woff2) format("woff2");unicode-range:U+0900-097F,U+1CD0-1CF9,U+200C-200D,U+20A8,U+20B9,U+20F0,U+25CC,U+A830-A839,U+A8E0-A8FF,U+11B00-11B09}@font-face{font-family:Poppins;font-style:normal;font-weight:800;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLDD4Z1JlFc-K.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Poppins;font-style:normal;font-weight:800;font-display:swap;src:url(https://fonts.gstatic.com/s/poppins/v24/pxiByp8kv8JHgFVrLDD4Z1xlFQ.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--color-primary-soft: #E3D8F1;--color-secondary: #DABECA;--color-accent: #E84855;--color-accent-soft: #f5c5c9;--color-text: #5D5F71;--color-text-muted: #9395a5;--color-bg: #f7f5fb;--color-card-bg: #FFFFFF;--color-sidebar-bg: #FFFFFF;--color-rail-bg: #f3f0f8;--color-border: #ede9f6;--color-hover: #f5f2fb;--font-sans: "Poppins", system-ui, -apple-system, sans-serif;--radius-sm: 6px;--radius-md: 10px;--radius-lg: 16px;--radius-full: 9999px;--shadow-sm: 0 1px 4px rgba(0, 0, 0, .06);--shadow-md: 0 4px 16px rgba(0, 0, 0, .08);--shadow-lg: 0 8px 32px rgba(0, 0, 0, .1);--z-agent-button: 9000;--z-agent-widget: 9100;--z-agent-menu: 9200;--z-agent-banner: 9300}@keyframes agent-halo-spin{to{transform:rotate(360deg)}}@keyframes agent-halo-pulse{0%,to{opacity:.8}50%{opacity:1}}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{font-size:16px;-webkit-text-size-adjust:100%;scroll-behavior:smooth}body{font-family:var(--font-sans);font-size:14px;color:var(--color-text);background-color:var(--color-bg);line-height:1.6;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.bui-tooltip{position:fixed;z-index:100000;max-width:260px;padding:7px 11px;border-radius:12px;background:#fff;color:#1d1d1f;border:1px solid rgba(0,0,0,.06);box-shadow:0 8px 26px #00000029,0 2px 6px #0000001a;font-family:var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);font-size:12.5px;font-weight:500;line-height:1.45;letter-spacing:.01em;text-align:left;white-space:normal;word-break:break-word;pointer-events:none;opacity:0;transform:scale(.92);transform-origin:center;transition:opacity .13s ease,transform .14s cubic-bezier(.34,1.56,.64,1)}.bui-tooltip--in{opacity:1;transform:scale(1)}.bui-tooltip__tail{position:absolute;z-index:-1;width:9px;height:9px;background:#fff;border:1px solid rgba(0,0,0,.06);border-radius:2px;transform:rotate(45deg)}.bui-tooltip__tail.is-bottom{bottom:-5px}.bui-tooltip__tail.is-top{top:-5px}.bui-tooltip__tail.is-right{right:-5px}.bui-tooltip__tail.is-left{left:-5px}@media (prefers-reduced-motion: reduce){.bui-tooltip{transition:opacity .1s ease;transform:none}.bui-tooltip--in{transform:none}}h1,h2,h3,h4,h5,h6{font-family:var(--font-sans);font-weight:700;line-height:1.3;color:var(--color-text)}a{color:var(--color-accent);text-decoration:none}a:hover{text-decoration:underline}p{line-height:1.7}.btn{display:inline-flex;align-items:center;gap:6px;padding:9px 18px;border-radius:var(--radius-md);font-family:var(--font-sans);font-size:13px;font-weight:600;cursor:pointer;border:1px solid transparent;transition:background .15s,border-color .15s,box-shadow .15s,opacity .15s;text-decoration:none;white-space:nowrap}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.btn-primary{background:var(--color-accent);color:#fff;border-color:var(--color-accent)}.btn-primary:hover{background:#d13d4a;border-color:#d13d4a;box-shadow:0 2px 8px #e848554d;text-decoration:none}.btn-outline{background:transparent;color:var(--color-text);border-color:var(--color-border)}.btn-outline:hover{background:var(--color-hover);border-color:#d5d0e4;text-decoration:none}.btn-ghost{background:transparent;color:var(--color-text-muted);border-color:transparent}.btn-ghost:hover{background:var(--color-hover);color:var(--color-text)}.btn-sm{padding:6px 12px;font-size:12px;border-radius:var(--radius-sm)}.btn-lg{padding:12px 24px;font-size:15px;border-radius:12px}input,textarea,select{font-family:var(--font-sans);font-size:14px;color:var(--color-text)}.text-muted{color:var(--color-text-muted)}.text-accent{color:var(--color-accent)}.text-sm{font-size:12px}.text-xs{font-size:11px}.font-semibold{font-weight:600}.font-bold{font-weight:700}.flex{display:flex}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:8px}.gap-4{gap:16px}.w-full{width:100%}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-secondary)}router-outlet+*{animation:fadeInUp .2s ease}@keyframes fadeInUp{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.pane-section{display:flex;flex-direction:column;gap:24px;max-width:520px}.pane-hd{display:flex;flex-direction:column;gap:4px;padding-bottom:20px;border-bottom:1px solid var(--color-border)}.pane-hd--row{flex-direction:row;align-items:flex-start;justify-content:space-between;gap:16px}.pane-title{font-size:15px;font-weight:700;color:var(--color-text);margin:0}.pane-desc{font-size:12px;color:var(--color-text-muted);margin:0;line-height:1.5}.pane-form{display:flex;flex-direction:column;gap:18px}.pane-success{font-size:12px;font-weight:500;color:#065f46;background:#d1fae5;border:1px solid #a7f3d0;border-radius:var(--radius-sm);padding:8px 12px;margin:0}.field{display:flex;flex-direction:column;gap:6px}.field__label{font-size:12px;font-weight:600;color:var(--color-text);letter-spacing:.02em;text-transform:uppercase}.field__input{padding:9px 13px;border:1px solid var(--color-border);border-radius:var(--radius-md);font-family:var(--font-sans);font-size:13px;color:var(--color-text);background:var(--color-bg);outline:none;transition:border-color .15s,box-shadow .15s;width:100%}.field__input:focus{border-color:var(--color-accent);box-shadow:0 0 0 3px #e8485514}.field__input--locked{opacity:.55;cursor:not-allowed;color:var(--color-text-muted)}.field__input:disabled{cursor:not-allowed}.field textarea.field__input{resize:vertical}.field__hint{font-size:11px;color:var(--color-text-muted)}@media (max-width: 768px){.btn{padding:8px 14px}.detail-table-wrap,.pages-table-wrap,.diff-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}.result-summary,.insight-grid,.pr-stats-grid{grid-template-columns:1fr 1fr!important}.sitemap-form{flex-direction:column}.pr-detail__cols,.diff-screen__body{grid-template-columns:1fr!important}.diff-files{display:none}.diff-files.mobile-show{display:block}.pr-filters__top{flex-direction:column;align-items:flex-start}.pr-filters__right{width:100%}.pr-search{max-width:100%!important;flex:1}.repo-card{flex-direction:column;align-items:flex-start}.repo-card__right{align-self:flex-start;flex-wrap:wrap}.history-item{flex-direction:column}.results-toolbar{flex-direction:column;align-items:flex-start}.diff-screen__title-row{flex-direction:column}.diff-screen__header-right{align-self:flex-start}}
|
|
1
|
+
@charset "UTF-8";:root{--color-primary-soft: #E3D8F1;--color-secondary: #DABECA;--color-accent: #E84855;--color-accent-soft: #f5c5c9;--color-text: #5D5F71;--color-text-muted: #9395a5;--color-bg: #f7f5fb;--color-card-bg: #FFFFFF;--color-sidebar-bg: #FFFFFF;--color-rail-bg: #f3f0f8;--color-border: #ede9f6;--color-hover: #f5f2fb;--font-sans: "Poppins", system-ui, -apple-system, sans-serif;--radius-sm: 6px;--radius-md: 10px;--radius-lg: 16px;--radius-full: 9999px;--shadow-sm: 0 1px 4px rgba(0, 0, 0, .06);--shadow-md: 0 4px 16px rgba(0, 0, 0, .08);--shadow-lg: 0 8px 32px rgba(0, 0, 0, .1);--z-agent-button: 9000;--z-agent-widget: 9100;--z-agent-menu: 9200;--z-agent-banner: 9300}@keyframes agent-halo-spin{to{transform:rotate(360deg)}}@keyframes agent-halo-pulse{0%,to{opacity:.8}50%{opacity:1}}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{font-size:16px;-webkit-text-size-adjust:100%;scroll-behavior:smooth}body{font-family:var(--font-sans);font-size:14px;color:var(--color-text);background-color:var(--color-bg);line-height:1.6;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.bui-tooltip{position:fixed;z-index:100000;max-width:260px;padding:7px 11px;border-radius:12px;background:#fff;color:#1d1d1f;border:1px solid rgba(0,0,0,.06);box-shadow:0 8px 26px #00000029,0 2px 6px #0000001a;font-family:var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);font-size:12.5px;font-weight:500;line-height:1.45;letter-spacing:.01em;text-align:left;white-space:normal;word-break:break-word;pointer-events:none;opacity:0;transform:scale(.92);transform-origin:center;transition:opacity .13s ease,transform .14s cubic-bezier(.34,1.56,.64,1)}.bui-tooltip--in{opacity:1;transform:scale(1)}.bui-tooltip__tail{position:absolute;z-index:-1;width:9px;height:9px;background:#fff;border:1px solid rgba(0,0,0,.06);border-radius:2px;transform:rotate(45deg)}.bui-tooltip__tail.is-bottom{bottom:-5px}.bui-tooltip__tail.is-top{top:-5px}.bui-tooltip__tail.is-right{right:-5px}.bui-tooltip__tail.is-left{left:-5px}@media (prefers-reduced-motion: reduce){.bui-tooltip{transition:opacity .1s ease;transform:none}.bui-tooltip--in{transform:none}}h1,h2,h3,h4,h5,h6{font-family:var(--font-sans);font-weight:700;line-height:1.3;color:var(--color-text)}a{color:var(--color-accent);text-decoration:none}a:hover{text-decoration:underline}p{line-height:1.7}.btn{display:inline-flex;align-items:center;gap:6px;padding:9px 18px;border-radius:var(--radius-md);font-family:var(--font-sans);font-size:13px;font-weight:600;cursor:pointer;border:1px solid transparent;transition:background .15s,border-color .15s,box-shadow .15s,opacity .15s;text-decoration:none;white-space:nowrap}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.btn-primary{background:var(--color-accent);color:#fff;border-color:var(--color-accent)}.btn-primary:hover{background:#d13d4a;border-color:#d13d4a;box-shadow:0 2px 8px #e848554d;text-decoration:none}.btn-outline{background:transparent;color:var(--color-text);border-color:var(--color-border)}.btn-outline:hover{background:var(--color-hover);border-color:#d5d0e4;text-decoration:none}.btn-ghost{background:transparent;color:var(--color-text-muted);border-color:transparent}.btn-ghost:hover{background:var(--color-hover);color:var(--color-text)}.btn-sm{padding:6px 12px;font-size:12px;border-radius:var(--radius-sm)}.btn-lg{padding:12px 24px;font-size:15px;border-radius:12px}input,textarea,select{font-family:var(--font-sans);font-size:14px;color:var(--color-text)}.text-muted{color:var(--color-text-muted)}.text-accent{color:var(--color-accent)}.text-sm{font-size:12px}.text-xs{font-size:11px}.font-semibold{font-weight:600}.font-bold{font-weight:700}.flex{display:flex}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:8px}.gap-4{gap:16px}.w-full{width:100%}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-secondary)}router-outlet+*{animation:fadeInUp .2s ease}@keyframes fadeInUp{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.pane-section{display:flex;flex-direction:column;gap:24px;max-width:520px}.pane-hd{display:flex;flex-direction:column;gap:4px;padding-bottom:20px;border-bottom:1px solid var(--color-border)}.pane-hd--row{flex-direction:row;align-items:flex-start;justify-content:space-between;gap:16px}.pane-title{font-size:15px;font-weight:700;color:var(--color-text);margin:0}.pane-desc{font-size:12px;color:var(--color-text-muted);margin:0;line-height:1.5}.pane-form{display:flex;flex-direction:column;gap:18px}.pane-success{font-size:12px;font-weight:500;color:#065f46;background:#d1fae5;border:1px solid #a7f3d0;border-radius:var(--radius-sm);padding:8px 12px;margin:0}.field{display:flex;flex-direction:column;gap:6px}.field__label{font-size:12px;font-weight:600;color:var(--color-text);letter-spacing:.02em;text-transform:uppercase}.field__input{padding:9px 13px;border:1px solid var(--color-border);border-radius:var(--radius-md);font-family:var(--font-sans);font-size:13px;color:var(--color-text);background:var(--color-bg);outline:none;transition:border-color .15s,box-shadow .15s;width:100%}.field__input:focus{border-color:var(--color-accent);box-shadow:0 0 0 3px #e8485514}.field__input--locked{opacity:.55;cursor:not-allowed;color:var(--color-text-muted)}.field__input:disabled{cursor:not-allowed}.field textarea.field__input{resize:vertical}.field__hint{font-size:11px;color:var(--color-text-muted)}@media (max-width: 768px){.btn{padding:8px 14px}.detail-table-wrap,.pages-table-wrap,.diff-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}.result-summary,.insight-grid,.pr-stats-grid{grid-template-columns:1fr 1fr!important}.sitemap-form{flex-direction:column}.pr-detail__cols,.diff-screen__body{grid-template-columns:1fr!important}.diff-files{display:none}.diff-files.mobile-show{display:block}.pr-filters__top{flex-direction:column;align-items:flex-start}.pr-filters__right{width:100%}.pr-search{max-width:100%!important;flex:1}.repo-card{flex-direction:column;align-items:flex-start}.repo-card__right{align-self:flex-start;flex-wrap:wrap}.history-item{flex-direction:column}.results-toolbar{flex-direction:column;align-items:flex-start}.diff-screen__title-row{flex-direction:column}.diff-screen__header-right{align-self:flex-start}}@font-face{font-family:Poppins;font-style:normal;font-weight:400;font-display:swap;src:url("./media/poppins-latin-400.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:500;font-display:swap;src:url("./media/poppins-latin-500.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:600;font-display:swap;src:url("./media/poppins-latin-600.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Poppins;font-style:normal;font-weight:700;font-display:swap;src:url("./media/poppins-latin-700.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
|