HannesVonEssen commited on
Commit
7f00c04
·
verified ·
1 Parent(s): 53274ca

Restore Space styling and add native Hugging Face login

Browse files
README.md CHANGED
@@ -4,6 +4,8 @@ emoji: 🟩
4
  colorFrom: green
5
  colorTo: blue
6
  sdk: static
 
 
7
  pinned: false
8
  short_description: Interactive architecture graph for any HF model
9
  models:
 
4
  colorFrom: green
5
  colorTo: blue
6
  sdk: static
7
+ hf_oauth: true
8
+ hf_oauth_expiration_minutes: 43200
9
  pinned: false
10
  short_description: Interactive architecture graph for any HF model
11
  models:
hf-shell-css-04b3600b8d38.css ADDED
@@ -0,0 +1,1423 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ /* /next landing variant (hfnx-*): catalog-first hero replacing the SPA
3
+ hero + gallery; everything below (articles, showcase, products,
4
+ footer) stays the SPA's own. Active only with ?next_landing=1. */
5
+ /* Keep main.hero alive (it occupies the shell grid's "hero" area and
6
+ the brand nav sits in the sibling "nav" area - removing the hero
7
+ collapses the grid and the nav drifts). Hide only its children. */
8
+ body.hfnx-active main.hero[data-page="landing"] > *:not(.hfnx) { display: none !important; }
9
+ /* flatten the hero's own grid: its column template (incl. a minmax
10
+ 500px video column) survives even with children hidden, making the
11
+ grid wider than the viewport and pushing the centered title right */
12
+ body.hfnx-active main.hero[data-page="landing"] {
13
+ display: block !important; width: 100%; max-width: 100%;
14
+ }
15
+ body.hfnx-active .gallery-section[data-page="landing"] { display: none !important; }
16
+ /* hfnx owns the top chrome: hide the SPA's top-right brand bar and host
17
+ the adopted .brand-stack (real product dropdown) top-LEFT instead */
18
+ body.hfnx-active .landing-nav-wrap { display: none !important; }
19
+ .hfnx { display: none; }
20
+ body.hfnx-active .hfnx { display: block; grid-column: 1 / -1; width: 100%; }
21
+ /* Route policy for the injected hfnx block: the landing route gets the
22
+ full hfnx layout; the logged-in dashboard/bookmarks (route-hf-models)
23
+ and the feature/showcase pages keep ONLY the top menu (brand + nav +
24
+ auth chip) so the site chrome stays consistent; every other route
25
+ (article login/editor/admin, blog preview, viewer, owner) hides hfnx
26
+ entirely - without this the landing hero renders on top of those
27
+ pages because hfnx forces main.hero visible. */
28
+ body.hfnx-active.route-hf-models .hfnx > *:not(.hfnx-top),
29
+ body.hfnx-active.route-hf-watchlist .hfnx > *:not(.hfnx-top),
30
+ body.hfnx-active.route-hf-prerelease .hfnx > *:not(.hfnx-top),
31
+ body.hfnx-active.route-hf-blog-index .hfnx > *:not(.hfnx-top) { display: none !important; }
32
+ body.hfnx-active.route-hf-watchlist .hfnx,
33
+ body.hfnx-active.route-hf-prerelease .hfnx,
34
+ body.hfnx-active.route-hf-blog-index .hfnx { padding-bottom: 0; }
35
+ /* the OAuth login / loading screens (route-hf-models without a content
36
+ surface) were designed full-viewport without chrome - no navbar */
37
+ body.hfnx-active.route-hf-models:not(.hf-models-content-active) .hfnx { display: none !important; }
38
+ body.hfnx-active.route-hf-models .hfnx { padding-bottom: 6px; }
39
+ /* feature + placement pages were designed to stand alone: no navbar,
40
+ and no landing sections below (interactive-articles rail) */
41
+ body.hfnx-active.route-hf-feature-preview .hfnx,
42
+ .page.route-hf-feature-preview .hfnx { display: none !important; }
43
+ body.route-hf-feature-preview .blogs-with-graphs { display: none !important; }
44
+ /* the interactive-articles rail is a landing section - never render it
45
+ on any other route (viewer, owner galleries, blog/docs pages, ...);
46
+ the blog index reuses the rail's card styling and hydrated figures,
47
+ so its own section is exempt */
48
+ body:not(.route-landing) .blogs-with-graphs:not(.hf-blog-index),
49
+ .page:not(.route-landing) .blogs-with-graphs:not(.hf-blog-index) { display: none !important; }
50
+ /* the blog/docs panel has no named grid area - without an explicit
51
+ span, shell auto-placement drops it into the narrow "nav" column
52
+ (squeezing the hero/navbar to the leftover fraction) as soon as the
53
+ rail above it is hidden */
54
+ .page.route-hf-blog-preview .hf-blog-preview,
55
+ body.route-hf-blog-preview .hf-blog-preview {
56
+ grid-column: 1 / -1;
57
+ }
58
+ .page.route-hf-watchlist .hf-watchlist-page,
59
+ body.route-hf-watchlist .hf-watchlist-page {
60
+ grid-column: 1 / -1;
61
+ width: 100%;
62
+ justify-self: stretch;
63
+ }
64
+ .page.route-hf-blog-index .hf-blog-index,
65
+ body.route-hf-blog-index .hf-blog-index {
66
+ grid-column: 1 / -1;
67
+ width: 100%;
68
+ justify-self: stretch;
69
+ }
70
+ /* the prerelease section reuses the .hf-blog-preview container exactly
71
+ (width min(100%,1040px), centered) - span the shell columns and pin
72
+ the blog article width/margins so the box centers like the blog */
73
+ .page.route-hf-prerelease .hf-prerelease,
74
+ body.route-hf-prerelease .hf-prerelease,
75
+ /* companion mode: same article box, shown below the viewer on the
76
+ normal model route (route class is the viewer's, not prerelease's) */
77
+ .page .hf-prerelease.hf-prerelease--companion,
78
+ body .hf-prerelease.hf-prerelease--companion {
79
+ grid-column: 1 / -1;
80
+ width: min(100%, 1040px);
81
+ margin: clamp(24px, 5vw, 62px) auto clamp(42px, 7vw, 92px);
82
+ justify-self: center;
83
+ }
84
+ /* let the injected panel fill the blog-width container (drop the
85
+ fragment's own max-widths/padding so it matches the blog article box) */
86
+ .hf-prerelease .k3wrap,
87
+ .hf-prerelease .wrap { max-width: none; margin: 0; padding: 0; }
88
+ .hf-blog-index__inner {
89
+ max-width: 900px;
90
+ margin: 0 auto;
91
+ padding: 16px 22px 80px;
92
+ }
93
+ .hf-blog-index__crumbs { font-size: 14px; color: #7d92ab; margin: 0 0 26px; }
94
+ .hf-blog-index__crumbs a { color: #9db4cc; text-decoration: none; }
95
+ .hf-blog-index__title { font-size: 34px; margin: 0 0 8px; color: #eef4fb; letter-spacing: -0.01em; }
96
+ .hf-blog-index__lede { color: #9db4cc; margin: 0 0 34px; max-width: 640px; font-size: 16px; }
97
+ .hf-blog-index__post {
98
+ display: flex;
99
+ gap: 20px;
100
+ align-items: center;
101
+ text-decoration: none;
102
+ color: inherit;
103
+ border: 1px solid rgba(125, 146, 171, 0.18);
104
+ border-radius: 16px;
105
+ padding: 18px;
106
+ margin-bottom: 18px;
107
+ background: rgba(13, 21, 36, 0.6);
108
+ transition: border-color 0.15s ease;
109
+ }
110
+ .hf-blog-index__post:hover { border-color: rgba(156, 255, 99, 0.45); }
111
+ .hf-blog-index__thumb {
112
+ display: block;
113
+ flex: 0 0 210px;
114
+ width: 210px;
115
+ border-radius: 10px;
116
+ overflow: hidden;
117
+ background: rgba(5, 9, 20, 0.7);
118
+ }
119
+ .hf-blog-index__thumb img { display: block; width: 100%; height: auto; }
120
+ .hf-blog-index__thumb--figure { aspect-ratio: 404 / 238; position: relative; }
121
+ .hf-blog-index__still {
122
+ display: block; width: 100%; height: 100%;
123
+ position: absolute; top: 0; left: 0; object-fit: cover;
124
+ }
125
+ .hf-blog-index__thumb--figure .hf-blog-index__figurebox {
126
+ position: absolute;
127
+ top: 0;
128
+ left: 0;
129
+ width: 404px;
130
+ height: 238px;
131
+ transform-origin: top left;
132
+ pointer-events: none;
133
+ --blogs-figure-height: 238px;
134
+ /* stays hidden (still shows through) until a real scale is applied */
135
+ opacity: 0;
136
+ }
137
+ .hf-blog-index__thumb--figure .hf-blog-index__figurebox[data-scaled="true"] {
138
+ opacity: 1;
139
+ }
140
+ /* the rail sizes the figure wells for its card grid (the LiquidAI one
141
+ is a narrow --compact well); in the index thumb the cloned well must
142
+ fill the whole 404x238 stage */
143
+ .hf-blog-index__figurebox .blogs-with-graphs__image-wrap {
144
+ display: block !important;
145
+ width: 404px !important;
146
+ max-width: none !important;
147
+ height: 238px !important;
148
+ margin: 0 !important;
149
+ padding: 0 !important;
150
+ }
151
+ .hf-blog-index__figurebox .blogs-with-graphs__live {
152
+ width: 100% !important;
153
+ height: 238px !important;
154
+ min-height: 238px !important;
155
+ }
156
+ .hf-blog-index__figurebox [data-blogs-figure-source] {
157
+ width: 100% !important;
158
+ height: 100% !important;
159
+ }
160
+ .hf-blog-index__body { min-width: 0; }
161
+ .hf-blog-index__body h2 { margin: 0 0 6px; font-size: 20px; color: #eef4fb; }
162
+ .hf-blog-index__body p { margin: 0 0 10px; color: #9db4cc; font-size: 15px; line-height: 1.55; }
163
+ .hf-blog-index__meta { color: #62788f; font-size: 13px; }
164
+ .hf-blog-index__date {
165
+ font-size: 11.5px;
166
+ font-weight: 700;
167
+ letter-spacing: 0.12em;
168
+ text-transform: uppercase;
169
+ }
170
+ @media (max-width: 640px) {
171
+ .hf-blog-index__post { flex-direction: column; align-items: stretch; }
172
+ .hf-blog-index__thumb { flex: none; width: 100%; }
173
+ }
174
+ .hf-blog-index__backlinks { margin-top: 40px; color: #9db4cc; font-size: 15px; }
175
+ .hf-blog-index__backlinks a { color: #88d7ff; text-decoration: none; }
176
+ body.hfnx-active.route-hf-models .hfnx-top,
177
+ body.hfnx-active.route-hf-watchlist .hfnx-top,
178
+ body.hfnx-active.route-hf-blog-index .hfnx-top {
179
+ position: relative;
180
+ z-index: 20;
181
+ /* mirror the landing hero container - min(100vw - 52px, 1560px)
182
+ centered - so the brand sits 26px from the side and 24px from the
183
+ top on every route the navbar appears on */
184
+ width: min(100%, 1612px);
185
+ margin: 0 auto 8px;
186
+ padding: 24px 26px 10px;
187
+ border-bottom: 0;
188
+ background: transparent;
189
+ backdrop-filter: blur(18px);
190
+ }
191
+ /* prerelease reuses the blog-article route chrome exactly: the shell
192
+ already insets it, so the navbar only needs a 2px top nudge (matches
193
+ route-hf-blog-preview, not the wider blog-index navbar) */
194
+ body.hfnx-active.route-hf-prerelease .hfnx-top {
195
+ position: relative;
196
+ z-index: 20;
197
+ width: 100%;
198
+ margin: 0 0 8px;
199
+ padding: 2px 0 10px;
200
+ border-bottom: 0;
201
+ background: transparent;
202
+ backdrop-filter: none;
203
+ -webkit-backdrop-filter: none;
204
+ }
205
+ /* the blog index is a plain scrolling page - the blurred navbar plate
206
+ reads as a stray rectangle on it */
207
+ body.hfnx-active.route-hf-blog-index .hfnx-top,
208
+ body.hfnx-active.route-hf-prerelease .hfnx-top {
209
+ backdrop-filter: none;
210
+ -webkit-backdrop-filter: none;
211
+ }
212
+ body.hfnx-active.route-hf-models.hf-models-content-active .hfnx {
213
+ padding-bottom: 0;
214
+ }
215
+ body.hfnx-active.route-hf-models.hf-models-content-active .hf-models-page:not(.hf-article-login-page) {
216
+ align-content: start;
217
+ align-items: stretch;
218
+ min-height: 0;
219
+ padding-top: 0;
220
+ }
221
+ body.hfnx-active.route-hf-models.hf-models-content-active .hf-models-shell {
222
+ width: min(100%, 1240px);
223
+ margin: 0 auto;
224
+ }
225
+ body.hfnx-active.route-hf-article-login .hfnx,
226
+ body.hfnx-active.route-hf-article-picker .hfnx,
227
+ body.hfnx-active.route-hf-article-editor .hfnx,
228
+ body.hfnx-active.route-hf-article-admin .hfnx,
229
+ body.hfnx-active.route-viewer .hfnx,
230
+ body.hfnx-active.route-owner .hfnx { display: none !important; }
231
+ /* the blog preview (quickstart guide) keeps the top menu like the
232
+ dashboard routes - same landing-mirrored geometry */
233
+ body.hfnx-active.route-hf-blog-preview .hfnx > *:not(.hfnx-top) { display: none !important; }
234
+ body.hfnx-active.route-hf-blog-preview .hfnx { padding-bottom: 0; }
235
+ body.hfnx-active.route-hf-blog-preview .hfnx-top {
236
+ position: relative;
237
+ z-index: 20;
238
+ /* the landing shell already insets this route 26px/22px - only a
239
+ 2px top nudge is needed to land the brand at the usual 26/24 */
240
+ width: 100%;
241
+ margin: 0 0 8px;
242
+ padding: 2px 0 10px;
243
+ border-bottom: 0;
244
+ background: transparent;
245
+ backdrop-filter: blur(18px);
246
+ }
247
+ .hfnx-top { display: flex; align-items: center; gap: 22px; padding: 2px 0 6px; }
248
+ /* The landing brand-stack was built for the top-RIGHT corner: trigger
249
+ align-self flex-end + a hover translateX slide that aligns it with
250
+ the wider dropdown. Anchored top-LEFT it must not move at all - the
251
+ menu drops down left-aligned underneath instead. */
252
+ /* the hero h1 (a transformed sibling painted later) otherwise sits
253
+ ABOVE the open dropdown and steals :hover over its right half -
254
+ keep the whole top bar, menu included, on top */
255
+ body.hfnx-active .hfnx-top { position: relative; z-index: 30; }
256
+ body.hfnx-active .hfnx-top .brand-stack { align-items: flex-start; width: max-content; }
257
+ body.hfnx-active .hfnx-top .brand-stack::after {
258
+ left: -24px;
259
+ right: -40px;
260
+ height: 42px;
261
+ }
262
+ body.hfnx-active .hfnx-top .brand-stack__trigger {
263
+ align-self: flex-start !important; transform: none !important;
264
+ }
265
+ body.hfnx-active .hfnx-top .brand-stack:hover .brand-stack__trigger,
266
+ body.hfnx-active .hfnx-top .brand-stack:focus-within .brand-stack__trigger {
267
+ transform: none !important;
268
+ }
269
+ body.hfnx-active .hfnx-top .brand-stack__menu {
270
+ position: absolute !important; left: 0 !important; right: auto !important;
271
+ transform: translate(0, -6px) !important;
272
+ isolation: isolate;
273
+ }
274
+ body.hfnx-active .hfnx-top .brand-stack:hover .brand-stack__menu,
275
+ body.hfnx-active .hfnx-top .brand-stack:focus-within .brand-stack__menu,
276
+ body.hfnx-active .hfnx-top .brand-stack.is-open .brand-stack__menu {
277
+ transform: translate(0, 0) !important;
278
+ }
279
+ body.hfnx-active .hfnx-top .brand-stack__item {
280
+ position: relative;
281
+ z-index: 1;
282
+ border-radius: 16px;
283
+ transition: opacity 180ms ease, transform 180ms ease, background 180ms ease, box-shadow 180ms ease;
284
+ }
285
+ body.hfnx-active .hfnx-top .brand-stack__item:hover,
286
+ body.hfnx-active .hfnx-top .brand-stack__item:focus-visible,
287
+ body.hfnx-active .hfnx-top .brand-stack__item.is-nearest {
288
+ opacity: 1;
289
+ transform: translateY(-1px);
290
+ background: rgba(255, 255, 255, 0.055);
291
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 12px 28px rgba(0, 0, 0, 0.2);
292
+ outline: none;
293
+ }
294
+ /* while the dropdown is open the trigger highlights like a first menu
295
+ item when the pointer is nearest to it */
296
+ body.hfnx-active .hfnx-top .brand-stack__trigger {
297
+ border-radius: 16px;
298
+ transition: opacity 180ms ease, background 180ms ease, box-shadow 180ms ease;
299
+ }
300
+ body.hfnx-active .hfnx-top .brand-stack:hover .brand-stack__trigger.is-nearest,
301
+ body.hfnx-active .hfnx-top .brand-stack:focus-within .brand-stack__trigger.is-nearest {
302
+ opacity: 1;
303
+ background: rgba(255, 255, 255, 0.055);
304
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 12px 28px rgba(0, 0, 0, 0.2);
305
+ }
306
+ .hfnx-top__nav { display: flex; align-items: center; gap: 18px; margin-left: 8px; }
307
+ .hfnx-nav-menu {
308
+ position: relative;
309
+ display: inline-flex;
310
+ align-items: center;
311
+ }
312
+ .hfnx-nav-menu::after {
313
+ content: "";
314
+ position: absolute;
315
+ top: 100%;
316
+ left: -18px;
317
+ right: -18px;
318
+ height: 14px;
319
+ z-index: 49;
320
+ }
321
+ .hfnx-nav-menu__panel {
322
+ position: absolute;
323
+ top: calc(100% + 10px);
324
+ /* item text (1px border + 7px panel pad + 12px item pad) left-aligns
325
+ with the trigger text */
326
+ left: -20px;
327
+ z-index: 50;
328
+ display: grid;
329
+ gap: 2px;
330
+ min-width: 184px;
331
+ padding: 7px;
332
+ border: 1px solid rgba(255, 255, 255, 0.11);
333
+ border-radius: 16px;
334
+ background: rgba(8, 15, 27, 0.86);
335
+ box-shadow: 0 22px 54px rgba(0, 0, 0, 0.38);
336
+ backdrop-filter: blur(18px) saturate(1.15);
337
+ -webkit-backdrop-filter: blur(18px) saturate(1.15);
338
+ opacity: 0;
339
+ pointer-events: none;
340
+ transform: translate(0, -4px);
341
+ transition: opacity 150ms ease, transform 150ms ease;
342
+ }
343
+ .hfnx-nav-menu:hover .hfnx-nav-menu__panel,
344
+ .hfnx-nav-menu:focus-within .hfnx-nav-menu__panel {
345
+ opacity: 1;
346
+ pointer-events: auto;
347
+ transform: translate(0, 0);
348
+ }
349
+ .hfnx-nav-menu__item {
350
+ display: block;
351
+ padding: 9px 12px;
352
+ border-radius: 11px;
353
+ line-height: 1;
354
+ }
355
+ .hfnx-nav-menu__item:hover,
356
+ .hfnx-nav-menu__item:focus-visible {
357
+ background: rgba(255, 255, 255, 0.065);
358
+ }
359
+ .hfnx-auth {
360
+ margin-left: auto; position: relative; display: flex; align-items: center; gap: 9px;
361
+ }
362
+ .hfnx-auth__pill {
363
+ display: inline-flex; align-items: center; gap: 0; padding: 8px 13px;
364
+ border-radius: 999px; border: 1px solid rgba(136, 215, 255, 0.18);
365
+ color: var(--muted-strong, #c5d0e3); background: rgba(136, 215, 255, 0.045);
366
+ font: 600 13px "Inter", sans-serif; line-height: 1; white-space: nowrap;
367
+ transition: color 0.15s, border-color 0.15s, background 0.15s, transform 0.15s;
368
+ }
369
+ /* The short model label only surfaces on very narrow phones (see the
370
+ max-width 374px block below); everywhere else the full name shows. */
371
+ .hfnx-auth__pill-name-short { display: none; }
372
+ .hfnx-auth__pill-status { margin-left: 4px; color: var(--sky, #88d7ff); }
373
+ .hfnx-auth__pill[data-pill-live="1"] .hfnx-auth__pill-status { color: var(--lime, #7cff9b); font-weight: 700; }
374
+ .hfnx-auth__pill[data-pill-live="1"] { border-color: rgba(124, 255, 155, 0.42); background: rgba(124, 255, 155, 0.08); }
375
+ .hfnx-auth__pill:hover,
376
+ .hfnx-auth__pill:focus-visible {
377
+ color: var(--text, #f5f8ff); border-color: rgba(136, 215, 255, 0.46);
378
+ background: rgba(136, 215, 255, 0.09); transform: translateY(-1px); outline: none;
379
+ }
380
+ @media (max-width: 640px) {
381
+ /* Phone: brand + account on the first row, nav links wrap to a
382
+ second row that scrolls horizontally (no visible scrollbar). */
383
+ .hfnx-top { flex-wrap: wrap; gap: 8px 16px; }
384
+ .hfnx-top__nav {
385
+ order: 3;
386
+ flex: 1 0 100%;
387
+ margin-left: 0;
388
+ overflow-x: auto;
389
+ scrollbar-width: none;
390
+ -webkit-overflow-scrolling: touch;
391
+ padding: 2px 0 4px;
392
+ }
393
+ .hfnx-top__nav::-webkit-scrollbar { display: none; }
394
+ .hfnx-top__nav a { white-space: nowrap; }
395
+ .hfnx-nav-menu__panel { display: none; }
396
+ .hfnx-auth { gap: 6px; }
397
+ .hfnx-auth__pill {
398
+ flex-direction: column;
399
+ justify-content: center;
400
+ gap: 2px;
401
+ padding: 6px 8px;
402
+ font-size: 12px;
403
+ line-height: 1;
404
+ }
405
+ .hfnx-auth__pill-status { margin-left: 0; }
406
+ .hfnx-auth__login { padding-left: 10px; padding-right: 10px; }
407
+ }
408
+ .hfnx-auth__login {
409
+ display: inline-block; padding: 9px 18px; border-radius: 999px;
410
+ border: 1px solid var(--stroke, rgba(255,255,255,0.1));
411
+ color: var(--muted-strong, #c5d0e3); font: 600 13.5px "Inter", sans-serif;
412
+ background: rgba(255, 255, 255, 0.04); transition: all 0.15s; cursor: pointer;
413
+ }
414
+ .hfnx-auth__login:hover { border-color: rgba(156, 255, 99, 0.4); color: var(--text, #f5f8ff); }
415
+ /* Narrow phones: the stacked release pill still wrapped the top row on
416
+ real devices (brand on line one, pill + Log in on line two). Shrink
417
+ the pill and the Log in button so brand + pill + login share ONE row
418
+ down to 320px. These blocks sit AFTER the base .hfnx-auth__login rule
419
+ on purpose: same specificity, so source order is what lets the
420
+ media-query padding/font-size win. */
421
+ @media (max-width: 480px) {
422
+ .hfnx-top { gap: 8px 10px; }
423
+ .hfnx-auth__pill { font-size: 11px; padding: 6px 7px; }
424
+ .hfnx-auth__login { padding: 8px 9px; font-size: 12.5px; }
425
+ }
426
+ @media (max-width: 374px) {
427
+ .hfnx-auth { gap: 4px; }
428
+ .hfnx-auth__pill { font-size: 10.5px; padding: 5px 6px; }
429
+ /* "Qwen3.8-Max" no longer fits next to the brand at 320-374px wide;
430
+ swap in the short label (kept in sync by appendQwen38Pill). */
431
+ .hfnx-auth__pill-name-long { display: none; }
432
+ .hfnx-auth__pill-name-short { display: inline; }
433
+ .hfnx-auth__login { padding: 7px 8px; font-size: 12px; }
434
+ }
435
+ .hfnx-auth__chip {
436
+ display: flex; align-items: center; gap: 9px; padding: 5px 13px 5px 6px;
437
+ border-radius: 999px; border: 1px solid var(--stroke, rgba(255,255,255,0.1));
438
+ background: rgba(255, 255, 255, 0.04); cursor: pointer;
439
+ font: 600 13.5px "Inter", sans-serif; color: var(--text, #f5f8ff);
440
+ transition: border-color 0.15s;
441
+ }
442
+ .hfnx-auth__chip:hover { border-color: rgba(156, 255, 99, 0.4); }
443
+ .hfnx-auth__avatar {
444
+ width: 26px; height: 26px; border-radius: 50%; object-fit: cover;
445
+ background: #fff; display: block;
446
+ }
447
+ .hfnx-auth__avatar--letter {
448
+ display: flex; align-items: center; justify-content: center;
449
+ background: linear-gradient(135deg, rgba(156, 255, 99, 0.9), rgba(136, 215, 255, 0.85));
450
+ color: #07100d; font: 700 13px "Inter", sans-serif;
451
+ }
452
+ .hfnx-auth__menu {
453
+ position: absolute; right: 0; top: calc(100% + 8px); z-index: 30; min-width: 180px;
454
+ display: none; padding: 6px;
455
+ background: #0a121f; border: 1px solid var(--stroke, rgba(255,255,255,0.1));
456
+ border-radius: 14px; box-shadow: 0 24px 54px rgba(0, 0, 0, 0.45);
457
+ }
458
+ .hfnx-auth__menu.is-open { display: grid; gap: 2px; }
459
+ .hfnx-auth__item {
460
+ display: block; width: 100%; text-align: left; padding: 9px 14px; border: 0;
461
+ border-radius: 10px; background: transparent; cursor: pointer;
462
+ color: var(--muted-strong, #c5d0e3); font: 500 13.5px "Inter", sans-serif;
463
+ }
464
+ .hfnx-auth__item:hover { background: rgba(255, 255, 255, 0.05); color: var(--text, #f5f8ff); }
465
+ .hfnx-top__nav a { color: var(--muted, #91a0ba); font-size: 13.5px; transition: color 0.15s; }
466
+ .hfnx-top__nav a:hover { color: var(--text, #f5f8ff); }
467
+ .hfnx-hero { padding: 30px 0 0; text-align: center; }
468
+ /* desktop: slide the title + search bar aside while the brand product
469
+ menu is open so the dropdown never overlaps them */
470
+ .hfnx-hero, .hfnx-command { transition: transform 240ms ease; }
471
+ @media (min-width: 981px) {
472
+ body.hfnx-menu-open .hfnx-hero,
473
+ body.hfnx-menu-open .hfnx-command { transform: translateX(150px); }
474
+ }
475
+ /* max-width:none beats the route-landing .hero h1 { max-width:10.5ch }
476
+ rule - with nowrap text that shrunk box centered while the TEXT
477
+ overflowed it to the right, looking off-center */
478
+ body.hfnx-active .hfnx-hero h1 {
479
+ margin: 0 auto; white-space: nowrap; max-width: none !important;
480
+ width: 100%;
481
+ font-size: clamp(1.3rem, 4.2vw, 3.3rem); font-weight: 800;
482
+ line-height: 1.04; letter-spacing: -0.04em;
483
+ }
484
+ .hfnx-hero h1 em { font-style: normal; color: var(--lime, #9cff63); }
485
+ .hfnx-hero p {
486
+ margin: 16px auto 0; max-width: 56ch; color: var(--muted-strong, #c5d0e3);
487
+ font-size: 15.5px; line-height: 1.6;
488
+ }
489
+ .hfnx-command { padding: 26px 0 16px; }
490
+ /* The search+filters block follows the scroll over the results (like
491
+ /models) - also with an empty (trending) field, as a reminder that
492
+ everything shown is searchable. position:sticky scoped to the
493
+ catalog section releases it automatically once the results end,
494
+ and re-engages when scrolling back up into them. */
495
+ /* .page's overflow:hidden makes it the sticky containing block (which
496
+ never scrolls) - overflow:clip clips identically without creating a
497
+ scroll container, so the stick block tracks the viewport */
498
+ body.hfnx-active .page.route-landing { overflow: clip; }
499
+ /* Armed (searching) but NOT pinned: zero visual change - the block is
500
+ fully transparent and identical to the normal page. The glass +
501
+ bottom fade live on a pseudo-layer that fades in only when pinned. */
502
+ /* top:-72px lets the search bar + button scroll briefly out of view;
503
+ the compact overlay then glides in 72px later (image-1 trigger). The
504
+ pinned state snaps top back to 0 - the FLIP glide masks the jump. */
505
+ .hfnx-stick-anchor { display: block; height: 0; width: 100%; }
506
+ /* the pin swap collapses the stick by ~200px (spacer-compensated, net
507
+ zero). Chrome's scroll anchoring may still pick a node INSIDE the
508
+ stick as its anchor and "follow" it upward when the layout collapses,
509
+ scrolling the page back to the top mid-gesture on mobile (observed
510
+ via mobile_scroll_snapback field events: ~230px up, no programmatic
511
+ call, stick pinned). Exclude the whole stick from anchor selection. */
512
+ .hfnx-stick, .hfnx-stick *, #hfnx-stick-spacer { overflow-anchor: none; }
513
+ .hfnx-stick.is-sticky { position: sticky; top: -72px; z-index: 6; }
514
+ .hfnx-stick.is-sticky.is-pinned { top: 0; }
515
+ /* same non-blur transparent-black as the /models toolbar, with the
516
+ fade-out starting above the bar's bottom edge like /models */
517
+ .hfnx-stick::before {
518
+ content: ""; position: absolute; inset: 0 -22px -34px -22px; z-index: -1;
519
+ background: linear-gradient(180deg, rgba(5, 9, 20, 0.97) calc(100% - 52px), rgba(5, 9, 20, 0));
520
+ opacity: 0; transition: opacity 220ms ease; pointer-events: none;
521
+ }
522
+ .hfnx-stick.is-pinned::before { opacity: 1; }
523
+ .hfnx-stick.arch-open::before { opacity: 1; }
524
+ /* past the pin threshold but the compact swap still waiting for the
525
+ gesture to settle (coarse pointers): show the glass right away so
526
+ the expanded pills never float transparently over the grid */
527
+ .hfnx-stick.is-cover::before { opacity: 1; }
528
+ /* the swap animation's frozen snapshot lives inside a wrap that IS
529
+ the glass - the snapshot's own backdrop would double-darken it */
530
+ .hfnx-stick--swap-clone::before { display: none !important; }
531
+ /* while the morph wrap is the glass, the facsimile beneath keeps its
532
+ own backdrop off - two stacked 0.97 gradients turn the fade skirt
533
+ nearly opaque and it blinks when the wrap goes. Removing the class
534
+ at wrap-fade start crossfades the two identical gradients. */
535
+ .hfnx-stick--glass-wait::before { opacity: 0 !important; }
536
+ /* suppress the ::before opacity transition for the single-frame
537
+ wrap-to-glass handoff */
538
+ .hfnx-stick--glass-flip::before { transition: none !important; }
539
+ /* between the sticky point and the pin threshold the stuck stick is
540
+ progressively hidden from the bottom in lockstep with the scroll
541
+ (--stick-clip, set per scroll event): pill rows dissolve into the
542
+ rising edge and the first card is never covered. The mask mimics
543
+ the glass ::before's own 52px bottom fade, just moved up by the
544
+ clip - no hard edge. The oversized mask box (+44px sideways,
545
+ +134px vertically at -22,-100) keeps the glass's side/bottom bleed
546
+ painted. Paint-only - layout untouched, snapback protections
547
+ unaffected. */
548
+ .hfnx-stick.is-condensing {
549
+ -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - var(--stick-clip, 0px) - 86px), transparent calc(100% - var(--stick-clip, 0px) - 34px));
550
+ -webkit-mask-size: calc(100% + 44px) calc(100% + 134px);
551
+ -webkit-mask-position: -22px -100px;
552
+ -webkit-mask-repeat: no-repeat;
553
+ mask-image: linear-gradient(180deg, #000 calc(100% - var(--stick-clip, 0px) - 86px), transparent calc(100% - var(--stick-clip, 0px) - 34px));
554
+ mask-size: calc(100% + 44px) calc(100% + 134px);
555
+ mask-position: -22px -100px;
556
+ mask-repeat: no-repeat;
557
+ }
558
+ /* pinned: compact /models-style single row - the search bar + button
559
+ join the sort/browse row, match-count collapses, pills drop below */
560
+ /* input resizes instantly so the spacer compensation is exact in the
561
+ same frame; the FLIP glide masks the size change visually */
562
+ .hfnx-stick .hfnx-hint { transition: opacity 160ms ease, max-height 200ms ease; overflow: hidden; max-height: 40px; }
563
+ .hfnx-stick.is-pinned { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; padding: 10px 0 12px; }
564
+ .hfnx-stick.is-pinned .hfnx-command { flex: 1 1 380px; min-width: 280px; padding: 0; margin: 0; }
565
+ .hfnx-stick.is-pinned .hfnx-command__bar { max-width: none; }
566
+ .hfnx-stick.is-pinned .hfnx-command__input { padding: 10px 16px 10px 44px; font-size: 14px; }
567
+ .hfnx-stick.is-pinned .hfnx-command__go { padding: 0 20px; }
568
+ .hfnx-stick.is-pinned .hfnx-hint { display: none; }
569
+ .hfnx-stick.is-pinned .hfnx-filterbar { display: contents; }
570
+ .hfnx-stick.is-pinned .hfnx-status { display: none; }
571
+ .hfnx-stick.is-pinned .hfnx-sort { margin-left: 0; }
572
+ .hfnx-stick.is-pinned .hfnx-pills {
573
+ flex-basis: 100%; flex-wrap: nowrap; gap: 6px; margin-top: 0;
574
+ overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch;
575
+ scrollbar-width: none;
576
+ }
577
+ .hfnx-stick.is-pinned .hfnx-pills::-webkit-scrollbar { display: none; }
578
+ .hfnx-stick.is-pinned .hfnx-pill { flex: none; }
579
+ /* the arch panel is a flex item of the pinned row: without a basis it
580
+ sizes to max-content (all 39 concept pills in one line, ~7000px) and
581
+ runs off the right edge of the phone. Pin it to the row width; its
582
+ pills row then scrolls horizontally like the category pills above. */
583
+ .hfnx-stick.is-pinned .hfnx-archpanel {
584
+ flex-basis: 100%; min-width: 0; max-width: 100%;
585
+ margin-top: 0; padding: 10px 12px;
586
+ }
587
+ .hfnx-command__bar { display: flex; gap: 10px; align-items: stretch; max-width: 860px; margin: 0 auto; }
588
+ .hfnx-command__wrap { position: relative; flex: 1; }
589
+ .hfnx-command__input {
590
+ width: 100%; padding: 17px 20px 17px 48px;
591
+ background: rgba(255, 255, 255, 0.05);
592
+ border: 1px solid rgba(156, 255, 99, 0.22); border-radius: 16px;
593
+ color: var(--text, #f5f8ff); font: 500 16px "Inter", sans-serif;
594
+ outline: none; transition: border-color 0.15s, box-shadow 0.15s;
595
+ }
596
+ .hfnx-command__input::placeholder { color: #5c6b81; font-weight: 400; }
597
+ .hfnx-command__input:focus {
598
+ border-color: rgba(156, 255, 99, 0.55);
599
+ box-shadow: 0 0 0 3px rgba(156, 255, 99, 0.1), 0 18px 44px rgba(0, 0, 0, 0.35);
600
+ }
601
+ .hfnx-command__icon {
602
+ position: absolute; left: 17px; top: 50%; transform: translateY(-50%);
603
+ width: 18px; height: 18px; color: #5c6b81; pointer-events: none;
604
+ }
605
+ .hfnx-command__go {
606
+ padding: 0 26px; border: 0; border-radius: 16px; cursor: pointer;
607
+ background: var(--lime, #9cff63); color: #07100d;
608
+ font: 700 15px "Inter", sans-serif; white-space: nowrap;
609
+ transition: transform 0.12s, box-shadow 0.12s;
610
+ }
611
+ .hfnx-command__go:hover { transform: translateY(-1px); box-shadow: 0 10px 28px rgba(156, 255, 99, 0.24); }
612
+ .hfnx-hint {
613
+ max-width: 860px; margin: 9px auto 0; min-height: 18px;
614
+ color: var(--muted, #91a0ba); font-size: 12.5px; text-align: center;
615
+ }
616
+ .hfnx-hint b { color: var(--lime, #9cff63); font-weight: 600; }
617
+ .hfnx-hint kbd {
618
+ font: 600 11px "Inter", sans-serif; color: var(--muted-strong, #c5d0e3);
619
+ border: 1px solid var(--stroke, rgba(255,255,255,0.1)); border-bottom-width: 2px;
620
+ border-radius: 5px; padding: 1px 6px; margin: 0 1px;
621
+ }
622
+ .hfnx-notify {
623
+ display: none; max-width: 860px; margin: 14px auto 4px; padding: 16px 18px;
624
+ border: 1px solid rgba(156, 255, 99, 0.22); border-radius: 16px;
625
+ background: linear-gradient(120deg, rgba(156, 255, 99, 0.05), rgba(136, 215, 255, 0.04));
626
+ text-align: left; position: relative;
627
+ }
628
+ .hfnx-notify.is-visible { display: block; }
629
+ .hfnx-notify__close {
630
+ position: absolute; top: 10px; right: 12px; width: 26px; height: 26px;
631
+ border: none; border-radius: 8px; background: none; cursor: pointer;
632
+ color: var(--muted, #91a0ba); font-size: 17px; line-height: 26px; padding: 0;
633
+ }
634
+ .hfnx-notify__close:hover { color: var(--text, #f5f8ff); background: rgba(255, 255, 255, 0.06); }
635
+ .hfnx-notify__title { margin: 0 0 4px; font-size: 15px; font-weight: 700; color: var(--text, #f5f8ff); }
636
+ .hfnx-notify__sub { margin: 0 0 12px; font-size: 13px; color: var(--muted, #91a0ba); line-height: 1.5; }
637
+ .hfnx-notify__row { display: flex; gap: 10px; flex-wrap: wrap; }
638
+ .hfnx-notify__email {
639
+ flex: 1 1 240px; padding: 12px 16px; border-radius: 12px;
640
+ background: rgba(255, 255, 255, 0.05); border: 1px solid var(--stroke, rgba(255,255,255,0.1));
641
+ color: var(--text, #f5f8ff); font: 14px "Inter", sans-serif; outline: none;
642
+ }
643
+ .hfnx-notify__email:focus { border-color: rgba(156, 255, 99, 0.45); }
644
+ .hfnx-notify__btn {
645
+ padding: 12px 22px; border: 0; border-radius: 12px; cursor: pointer;
646
+ background: var(--lime, #9cff63); color: #07100d;
647
+ font: 700 14px "Inter", sans-serif; white-space: nowrap;
648
+ box-shadow: 0 0 0 rgba(156, 255, 99, 0);
649
+ transition: transform 0.14s ease, box-shadow 0.14s ease, filter 0.14s ease;
650
+ }
651
+ .hfnx-notify__btn:hover:not(:disabled),
652
+ .hfnx-notify__btn:focus-visible:not(:disabled) {
653
+ transform: translateY(-1px);
654
+ filter: brightness(1.04) saturate(1.04);
655
+ box-shadow: 0 12px 30px rgba(156, 255, 99, 0.22);
656
+ outline: none;
657
+ }
658
+ .hfnx-notify__btn:disabled { opacity: 0.55; cursor: default; }
659
+ .hfnx-notify__optin {
660
+ display: flex; gap: 5px; align-items: flex-start; margin-top: 11px;
661
+ color: var(--muted, #91a0ba); font-size: 12px; line-height: 1.5; cursor: pointer;
662
+ }
663
+ .hfnx-notify__optin input { margin-top: 2px; accent-color: var(--lime, #9cff63); }
664
+ .hfnx-notify__optin a { color: var(--muted-strong, #c5d0e3); text-decoration: underline; }
665
+ .hfnx-notify__feedback { margin: 10px 0 0; font-size: 13px; color: var(--lime, #9cff63); }
666
+ .hfnx-notify__feedback.is-error { color: #ff9d9d; }
667
+ /* watch popover: the shared notify panel, anchored under the search-results
668
+ watch pill. JS computes left/top/width against the offset parent; at
669
+ narrow widths it spans the full row under the status bar instead. */
670
+ .hfnx-notify--popover {
671
+ position: absolute; z-index: 60; margin: 0; max-width: none;
672
+ padding: 16px;
673
+ background: #0b1322;
674
+ border: 1px solid #434a78;
675
+ border-radius: 14px;
676
+ box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
677
+ }
678
+ .hfnx-notify--popover .hfnx-notify__title { padding-right: 26px; }
679
+ /* the pinned (condensed sticky) bar hides the status row, so an open
680
+ popover would float unanchored - hide it together with its anchor */
681
+ .hfnx-stick.is-pinned .hfnx-notify--popover { display: none; }
682
+ .hfnx-filterbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 14px; }
683
+ .hfnx-status { color: var(--muted, #91a0ba); font-size: 13px; }
684
+ .hfnx-status b { color: var(--text, #f5f8ff); font-weight: 600; }
685
+ .hfnx-status .hfnx-dot {
686
+ display: inline-block; width: 7px; height: 7px; border-radius: 999px;
687
+ background: var(--lime, #9cff63); margin-right: 7px; vertical-align: 1px;
688
+ animation: hfnx-pulse 2.6s ease-in-out infinite;
689
+ }
690
+ @keyframes hfnx-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
691
+ .hfnx-sort {
692
+ margin-left: auto;
693
+ border: 1px solid var(--stroke, rgba(255,255,255,0.1));
694
+ border-radius: 999px; color: var(--text, #f5f8ff); font: 13px "Inter", sans-serif;
695
+ padding: 8px 36px 8px 14px; outline: none; cursor: pointer;
696
+ /* custom chevron - the native select arrow hugs the pill's right
697
+ edge; this one sits a step further in */
698
+ -webkit-appearance: none;
699
+ appearance: none;
700
+ background:
701
+ url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23c5d0e3' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
702
+ no-repeat right 12px center / 13px 13px,
703
+ rgba(255, 255, 255, 0.04);
704
+ }
705
+ .hfnx-sort option { background: #0a121f; }
706
+ .hfnx-browse {
707
+ color: var(--lime, #9cff63); font-size: 0.76rem; font-weight: 700;
708
+ letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
709
+ }
710
+ .hfnx-browse:hover { text-decoration: underline; }
711
+ .hfnx-pills { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
712
+ .hfnx-pill {
713
+ background: transparent; border: 1px solid var(--stroke, rgba(255,255,255,0.1));
714
+ border-radius: 999px; color: var(--muted, #91a0ba); font: 12.5px "Inter", sans-serif;
715
+ padding: 6px 13px; cursor: pointer; transition: all 0.15s; white-space: nowrap;
716
+ }
717
+ .hfnx-stick.is-pinned .hfnx-pill { padding-inline: 10px; font-size: 12px; }
718
+ .hfnx-pill:hover { color: var(--text, #f5f8ff); border-color: rgba(156, 255, 99, 0.35); }
719
+ .hfnx-pill.is-on { color: #07100d; background: var(--lime, #9cff63); border-color: var(--lime, #9cff63); font-weight: 600; }
720
+ .hfnx-pill__count { opacity: 0.6; margin-left: 3px; font-variant-numeric: tabular-nums; }
721
+ .hfnx-pill__avatar {
722
+ width: 15px; height: 15px; border-radius: 4px; object-fit: cover;
723
+ vertical-align: -3px; margin: -2px 6px -1px -3px;
724
+ }
725
+ .hfnx-pill__avatar--user { border-radius: 50%; }
726
+ .hfnx-pill--archtoggle svg,
727
+ .hfnx-pill--orgtoggle svg { width: 13px; height: 13px; fill: currentColor; vertical-align: -2px; margin-right: 6px; }
728
+ .hfnx-pill--archtoggle.is-open,
729
+ .hfnx-pill--orgtoggle.is-open { border-color: rgba(156, 255, 99, 0.55); color: var(--text, #f5f8ff); }
730
+ .hfnx-archpanel {
731
+ margin-top: 10px; padding: 12px 14px; border-radius: 16px;
732
+ border: 1px solid rgba(156, 255, 99, 0.22);
733
+ background: linear-gradient(120deg, rgba(156, 255, 99, 0.045), rgba(136, 215, 255, 0.035));
734
+ text-align: left;
735
+ }
736
+ .hfnx-archpanel[hidden] { display: none !important; }
737
+ .hfnx-archpanel__hint { margin: 0 0 10px; font-size: 12.5px; color: var(--muted, #91a0ba); }
738
+ .hfnx-archpanel__hint a { color: var(--muted-strong, #c5d0e3); }
739
+ .hfnx-archpanel__pills { margin-top: 0; }
740
+ /* Mobile: the open panel behaves as a bounded sheet. The sticky stick
741
+ with the full 34-pill box was taller than the screen, so its bottom
742
+ pills were unreachable: scrolling just moved the grid beneath.
743
+ Instead the pill list wraps (also in pinned mode) and scrolls inside
744
+ its own box, overscroll-contained so browsing pills never scrolls
745
+ the page, its height cap keeps the whole stuck stick on screen, and
746
+ the unselected category pills hide to give the sheet more room
747
+ (active ones and the cog stay for context and closing). */
748
+ @media (max-width: 720px) {
749
+ .hfnx-stick.arch-open #hfnx-pills .hfnx-pill:not(.is-on):not(.hfnx-pill--archtoggle):not(.hfnx-pill--orgtoggle) {
750
+ display: none;
751
+ }
752
+ .hfnx-stick.arch-open .hfnx-archpanel__pills {
753
+ flex-wrap: wrap;
754
+ flex-basis: auto;
755
+ overflow-x: hidden;
756
+ overflow-y: auto;
757
+ max-height: 340px;
758
+ max-height: min(46dvh, 380px);
759
+ overscroll-behavior: contain;
760
+ -webkit-overflow-scrolling: touch;
761
+ padding-bottom: 4px;
762
+ }
763
+ }
764
+ .hfnx-archlearn {
765
+ margin-left: 10px; font-size: 12.5px; font-weight: 700;
766
+ color: var(--sky, #88d7ff); text-decoration: none; white-space: nowrap;
767
+ }
768
+ .hfnx-archlearn:hover { text-decoration: underline; }
769
+ .hfnx-arch-tooltip {
770
+ position: fixed; z-index: 2147483647; pointer-events: none;
771
+ max-width: min(360px, calc(100vw - 16px));
772
+ background: #111422; border: 1px solid #2f354a; border-radius: 8px;
773
+ padding: 0.4rem 0.6rem; font-size: 0.83rem; line-height: 1.45;
774
+ color: var(--text, #f5f8ff); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
775
+ opacity: 0; transition: opacity 0.15s ease; text-align: left;
776
+ }
777
+ .hfnx-arch-tooltip.is-visible { opacity: 1; }
778
+ .hfnx-arch-tooltip strong { color: #fff; }
779
+ .hfnx-grid { position: relative; margin-top: 20px; }
780
+ .hfnx-card {
781
+ position: absolute; top: 0; left: 0; color: var(--text, #f5f8ff);
782
+ display: flex; flex-direction: column; gap: 13px; padding: 13px;
783
+ border: 1px solid var(--stroke, rgba(255,255,255,0.1)); border-radius: 22px;
784
+ background: rgba(255, 255, 255, 0.04);
785
+ box-shadow: 0 18px 42px rgba(0, 0, 0, 0.26);
786
+ cursor: pointer; text-align: left;
787
+ transition: transform 170ms ease, border-color 170ms ease, box-shadow 170ms ease;
788
+ }
789
+ .hfnx-card:hover, .hfnx-card:focus-visible {
790
+ transform: translateY(-4px);
791
+ border-color: rgba(156, 255, 99, 0.32);
792
+ box-shadow: 0 24px 54px rgba(0, 0, 0, 0.34), 0 0 0 1px rgba(156, 255, 99, 0.12);
793
+ outline: none;
794
+ }
795
+ .hfnx-card__art {
796
+ display: flex; position: relative; align-items: center; justify-content: center;
797
+ padding: 18px 16px 14px; border-radius: 16px;
798
+ border: 1px solid rgba(255, 255, 255, 0.07);
799
+ background:
800
+ radial-gradient(circle at 50% 0%, rgba(136, 215, 255, 0.12), transparent 52%),
801
+ radial-gradient(circle at 20% 12%, rgba(156, 255, 99, 0.1), transparent 32%),
802
+ linear-gradient(180deg, rgba(9, 16, 29, 0.92), rgba(5, 9, 20, 0.98));
803
+ overflow: hidden; min-height: 90px;
804
+ }
805
+ .hfnx-card__img { width: 100%; height: auto; display: block; }
806
+ .hfnx-card__level {
807
+ position: absolute; left: 16px; right: 16px; top: 18px; bottom: 14px;
808
+ width: calc(100% - 32px); height: calc(100% - 32px);
809
+ object-fit: contain; opacity: 0; transition: opacity 380ms ease;
810
+ pointer-events: none;
811
+ }
812
+ .hfnx-card__level.is-on { opacity: 1; }
813
+ .hfnx-card__img { transition: opacity 380ms ease; }
814
+ .hfnx-card__art.is-leveled .hfnx-card__img { opacity: 0; }
815
+ .hfnx-card__video {
816
+ position: absolute; inset: 0; width: 100%; height: 100%;
817
+ border-radius: inherit;
818
+ object-fit: contain; opacity: 0; transition: opacity 200ms ease;
819
+ pointer-events: none;
820
+ }
821
+ .hfnx-card__video.is-on { opacity: 1; }
822
+ .hfnx-card__meta { display: grid; gap: 6px; padding: 0 4px 3px; }
823
+ .hfnx-new-count {
824
+ appearance: none; -webkit-appearance: none;
825
+ display: inline-flex; align-items: center;
826
+ margin: -6px -7px; padding: 6px 7px;
827
+ border: 0; border-radius: 999px; background: transparent;
828
+ color: #9cff63; font: inherit; font-weight: 600; line-height: inherit;
829
+ cursor: pointer; white-space: nowrap;
830
+ transition: color 150ms ease, background 150ms ease, box-shadow 150ms ease;
831
+ }
832
+ .hfnx-new-count-control { display: inline-flex; align-items: center; }
833
+ .hfnx-new-count-separator {
834
+ /* Flex-item edge whitespace collapses, so the " · " spacing must be
835
+ margins, not text spaces. */
836
+ margin: 0 0.45ch;
837
+ opacity: 1;
838
+ transition: opacity 150ms ease;
839
+ }
840
+ .hfnx-new-count-control:has(.hfnx-new-count:not(.is-on):hover) .hfnx-new-count-separator {
841
+ opacity: 0;
842
+ }
843
+ /* At rest this is deliberately just the existing green status text.
844
+ Hover/focus reveals the same green outline as the regular filter
845
+ pills; activation fills it without moving the surrounding sentence. */
846
+ .hfnx-new-count:hover {
847
+ background: rgba(156, 255, 99, 0.055);
848
+ box-shadow: inset 0 0 0 1px rgba(156, 255, 99, 0.35);
849
+ }
850
+ .hfnx-new-count:focus-visible {
851
+ outline: none;
852
+ background: rgba(156, 255, 99, 0.07);
853
+ box-shadow: inset 0 0 0 1px rgba(156, 255, 99, 0.55), 0 0 0 2px rgba(156, 255, 99, 0.16);
854
+ }
855
+ .hfnx-new-count.is-on {
856
+ color: #07100d; background: var(--lime, #9cff63);
857
+ box-shadow: inset 0 0 0 1px var(--lime, #9cff63);
858
+ }
859
+ .hfnx-new-count.is-on:hover { background: #b1ff85; box-shadow: inset 0 0 0 1px #b1ff85; }
860
+ .hfnx-card__new { display: inline-block; margin-left: 7px; padding: 1px 6px 1.5px; border-radius: 999px; background: rgba(156, 255, 99, 0.14); border: 1px solid rgba(156, 255, 99, 0.34); color: #9cff63; font-size: 9.5px; font-weight: 700; letter-spacing: 0.08em; vertical-align: 2px; }
861
+ .hfnx-card__label { display: flex; align-items: flex-start; gap: 9px; line-height: 1.3; }
862
+ .hfnx-card__avatar {
863
+ width: 20px; height: 20px; flex: 0 0 20px; margin-top: 1px;
864
+ border-radius: 6px; object-fit: cover; background: #fff; padding: 1px;
865
+ }
866
+ .hfnx-card__avatar--user { border-radius: 50%; }
867
+ .hfnx-card__dot { width: 8px; flex: 0 0 8px; height: 8px; align-self: center; border-radius: 999px; background: var(--lime, #9cff63); }
868
+ .hfnx-card__title { font-size: 1rem; font-weight: 700; overflow-wrap: anywhere; }
869
+ .hfnx-card__owner { color: #8d9cb6; font-weight: 600; }
870
+ .hfnx-card__sub { color: var(--muted, #91a0ba); font-size: 0.8rem; }
871
+ .hfnx-card__action {
872
+ color: var(--lime, #9cff63); font-size: 0.72rem; font-weight: 700;
873
+ letter-spacing: 0.08em; text-transform: uppercase; margin-top: 1px;
874
+ }
875
+ /* Kimi K3 prerelease teaser card: a heavily blurred K2.7-Code architecture
876
+ graph with the release time in the visitor's own timezone in front. */
877
+ .hfnx-card--k3 .hfnx-card__art { min-height: 168px; padding: 0; }
878
+ .hfnx-card__img--k3blur {
879
+ position: absolute; inset: 0; width: 100%; height: 100%;
880
+ object-fit: cover; object-position: center 30%;
881
+ filter: blur(9px) saturate(1.4) brightness(1.03);
882
+ transform: scale(1.08);
883
+ }
884
+ .hfnx-k3__shade {
885
+ position: absolute; inset: 0; border-radius: inherit;
886
+ background: radial-gradient(86% 72% at 50% 47%, rgba(4, 9, 16, 0.62), rgba(4, 9, 16, 0.12));
887
+ }
888
+ .hfnx-k3__over {
889
+ position: absolute; inset: 0; display: flex; flex-direction: column;
890
+ align-items: center; justify-content: center; gap: 1px; text-align: center;
891
+ padding: 10px; pointer-events: none;
892
+ }
893
+ .hfnx-k3__tag { font-size: 10px; font-weight: 800; letter-spacing: 3px; text-transform: uppercase; color: #9cffcf; }
894
+ .hfnx-k3__rel { margin-top: 9px; font-size: 10px; font-weight: 700; letter-spacing: 2px; text-transform: uppercase; color: #9fc0d6; }
895
+ .hfnx-k3__time { font-size: 46px; font-weight: 800; line-height: 1; color: #eef8ff; font-variant-numeric: tabular-nums; text-shadow: 0 0 22px rgba(120, 220, 255, 0.55); }
896
+ .hfnx-k3__subo { margin-top: 5px; font-size: 12px; font-weight: 600; color: #bfd4e7; }
897
+ .hfnx-skel {
898
+ position: absolute; top: 0; left: 0; border-radius: 22px;
899
+ border: 1px solid var(--stroke, rgba(255,255,255,0.1));
900
+ background:
901
+ linear-gradient(100deg, transparent 32%, rgba(156, 255, 99, 0.05) 48%, rgba(136, 215, 255, 0.06) 52%, transparent 68%),
902
+ rgba(255, 255, 255, 0.03);
903
+ background-size: 220% 100%, auto;
904
+ animation: hfnx-pulse 2.2s ease-in-out infinite;
905
+ }
906
+ .hfnx-showmore { display: none; text-align: center; margin-top: 26px; }
907
+ .hfnx-showmore.is-visible { display: block; }
908
+ .hfnx-showmore button {
909
+ padding: 12px 26px; border-radius: 999px; cursor: pointer;
910
+ background: rgba(255, 255, 255, 0.05); border: 1px solid var(--stroke, rgba(255,255,255,0.1));
911
+ color: var(--muted-strong, #c5d0e3); font: 600 13.5px "Inter", sans-serif; transition: all 0.15s;
912
+ }
913
+ .hfnx-showmore button:hover { border-color: rgba(156, 255, 99, 0.4); color: var(--text, #f5f8ff); }
914
+ .hfnx-empty { display: none; text-align: center; color: var(--muted, #91a0ba); padding: 46px 0 30px; font-size: 15px; }
915
+ .hfnx-empty.is-visible { display: block; }
916
+ .hfnx-empty b { color: var(--text, #f5f8ff); }
917
+ .hfnx-empty__cta {
918
+ display: inline-block; margin-top: 14px; padding: 11px 22px; border-radius: 12px;
919
+ background: var(--lime, #9cff63); color: #07100d; font-weight: 700; font-size: 14px;
920
+ }
921
+ .hfnx-empty__didyou { display: block; margin-top: 16px; font-size: 13px; }
922
+ .hfnx-empty__suggs {
923
+ display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;
924
+ margin-top: 10px;
925
+ }
926
+ .hfnx-empty__sugg {
927
+ display: inline-block; padding: 8px 14px; border-radius: 999px;
928
+ border: 1px solid var(--stroke, rgba(255, 255, 255, 0.1));
929
+ background: rgba(255, 255, 255, 0.04);
930
+ color: var(--text, #f5f8ff); font-size: 13px; text-decoration: none;
931
+ }
932
+ .hfnx-empty__sugg:hover { border-color: rgba(156, 255, 99, 0.45); }
933
+ .hfnx-empty__hint {
934
+ display: block; max-width: 460px; margin: 18px auto 0;
935
+ font-size: 13px; line-height: 1.55; color: var(--muted, #91a0ba);
936
+ }
937
+ .hfnx-bottom { margin-bottom: 26px; }
938
+
939
+ /* ------------------------------------------------------------------ */
940
+ /* Dashboard catalog cards: same language as the /models gcards - art */
941
+ /* well with the frameless graph, owner avatar row, actions pinned to */
942
+ /* the card bottom, hover video / level tour overlays. */
943
+ /* ------------------------------------------------------------------ */
944
+ .hf-model-card--catalog .hf-model-card__art,
945
+ .hf-model-card--graph-preview .hf-model-card__art {
946
+ display: flex; position: relative; align-items: center; justify-content: center;
947
+ margin: 0 0 10px; padding: 20px 18px 16px;
948
+ border-radius: 12px; border: 1px solid rgba(255, 255, 255, 0.06);
949
+ background:
950
+ radial-gradient(circle at 50% 0%, rgba(136, 215, 255, 0.12), transparent 52%),
951
+ radial-gradient(circle at 20% 12%, rgba(156, 255, 99, 0.1), transparent 32%),
952
+ linear-gradient(180deg, rgba(9, 16, 29, 0.92), rgba(5, 9, 20, 0.98)), #050914;
953
+ overflow: hidden;
954
+ }
955
+ .hf-model-card--catalog .hf-model-card__graph,
956
+ .hf-model-card--graph-preview .hf-model-card__graph {
957
+ position: relative; z-index: 1; display: block;
958
+ width: 100%; max-width: none; height: auto; padding: 0;
959
+ filter: saturate(0.98) contrast(1.04) drop-shadow(0 16px 26px rgba(0, 0, 0, 0.24));
960
+ transition: opacity 380ms ease;
961
+ }
962
+ .hf-model-card__art.is-leveled .hf-model-card__graph { opacity: 0; }
963
+ .hf-model-card__video {
964
+ position: absolute; inset: 0; width: 100%; height: 100%;
965
+ border-radius: inherit; object-fit: contain;
966
+ opacity: 0; transition: opacity 200ms ease; pointer-events: none;
967
+ }
968
+ .hf-model-card__video.is-on { opacity: 1; }
969
+ .hf-model-card__level {
970
+ position: absolute; left: 18px; right: 18px; top: 20px; bottom: 16px;
971
+ width: calc(100% - 36px); height: calc(100% - 36px);
972
+ object-fit: contain; opacity: 0; transition: opacity 380ms ease;
973
+ pointer-events: none;
974
+ }
975
+ .hf-model-card__level.is-on { opacity: 1; }
976
+ .hf-model-card__id { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
977
+ .hf-model-card__avatar {
978
+ width: 28px; height: 28px; border-radius: 8px; object-fit: cover;
979
+ background: #fff; padding: 2px; flex: none;
980
+ }
981
+ .hf-model-card__avatar--user { border-radius: 50%; }
982
+ .hf-model-card__id-text { min-width: 0; }
983
+ .hf-model-card--catalog .hf-model-card__repo { font-size: 13.5px; }
984
+ .hf-model-card--catalog .hf-model-card__meta { margin-top: 0; }
985
+
986
+ /* sticky column titles on the /next dashboard: seamless until pinned,
987
+ then the same non-blur dark gradient + bottom fade as /models; the
988
+ bulk button glides up beside its title (FLIP in JS) */
989
+ body.hfnx-active .page.route-hf-models {
990
+ overflow: clip;
991
+ position: relative;
992
+ isolation: isolate;
993
+ }
994
+ body.hfnx-active .hf-models-column__head {
995
+ position: sticky; top: 0; z-index: 32;
996
+ display: grid; grid-template-columns: minmax(0, 1fr) auto;
997
+ gap: 10px; align-items: center; min-height: 46px;
998
+ margin: -6px -10px 8px; padding: 10px 10px 8px;
999
+ }
1000
+ /* ONE shared veil spans the full page width behind every pinned head,
1001
+ painted in the page's own tone - the per-column near-black boxes had
1002
+ hard edges at each column boundary */
1003
+ .hf-models-sticky-veil {
1004
+ position: fixed; top: 0; left: 0; right: 0; height: 96px;
1005
+ z-index: 24; pointer-events: none; opacity: 0;
1006
+ transition: opacity 200ms ease;
1007
+ background: linear-gradient(
1008
+ 180deg,
1009
+ rgba(11, 15, 32, 0.97) 0%,
1010
+ rgba(11, 15, 32, 0.9) 46%,
1011
+ rgba(11, 15, 32, 0) 100%);
1012
+ }
1013
+ .hf-models-sticky-veil.is-visible { opacity: 1; }
1014
+ body.hfnx-active .hf-models-column__head > h3 { margin: 0; }
1015
+ body.hfnx-active .hf-models-column__head > * {
1016
+ position: relative;
1017
+ z-index: 2;
1018
+ }
1019
+ body.hfnx-active .hf-models-column__head h3 { white-space: nowrap; }
1020
+ body.hfnx-active .hf-models-column__head.is-pinned {
1021
+ min-height: 46px;
1022
+ }
1023
+
1024
+ /* ---- dashboard declutter: counts live as badges in the column heads,
1025
+ the intro count line and the stat pill row are redundant ---- */
1026
+ body.hfnx-active .hf-models-dashboard__stats { display: none !important; }
1027
+ body.hfnx-active #hf-models-dashboard-intro { display: none; }
1028
+ /* professional column titles: quiet small-caps label + neutral count
1029
+ badge (accent only when non-zero); the base h3's own sticky box is
1030
+ disabled - the head wrapper is the one sticky element */
1031
+ body.hfnx-active .hf-models-column h3 {
1032
+ position: static; top: auto; z-index: auto;
1033
+ padding: 0; margin: 0; border: 0; border-radius: 0;
1034
+ background: none; backdrop-filter: none; box-shadow: none;
1035
+ display: flex; align-items: center; justify-content: space-between;
1036
+ font-size: 11.5px; letter-spacing: 0.16em; text-transform: uppercase;
1037
+ color: var(--muted, #91a0ba); font-weight: 650;
1038
+ }
1039
+ body.hfnx-active .hf-models-column h3[data-count]::after {
1040
+ content: attr(data-count);
1041
+ display: inline-grid; place-items: center;
1042
+ min-width: 20px; height: 20px; padding: 0 7px;
1043
+ border-radius: 999px; font-size: 11px; font-weight: 700;
1044
+ letter-spacing: 0; background: rgba(255, 255, 255, 0.07);
1045
+ color: var(--muted, #91a0ba);
1046
+ }
1047
+ body.hfnx-active .hf-models-column h3:not([data-count="0"]):not([data-count="..."])[data-count]::after {
1048
+ background: rgba(156, 255, 99, 0.16);
1049
+ color: var(--lime, #9cff63);
1050
+ }
1051
+ /* empty dashboard fits the viewport: no filler height, no scrollbar */
1052
+ body.hfnx-active .hf-models-dashboard { padding-bottom: 24px; }
1053
+ body.hfnx-active .hf-models-column { min-height: 0; }
1054
+ body.hfnx-active .hf-models-column__list:empty { min-height: 0; }
1055
+ /* ready/featured card actions side by side */
1056
+ body.hfnx-active .hf-model-card__actions { flex-wrap: nowrap; }
1057
+ body.hfnx-active .hf-model-card__actions .hf-model-card__button {
1058
+ flex: 1 1 0; min-width: 0; padding: 7px 8px;
1059
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
1060
+ white-space: nowrap; font-size: 13px; border-radius: 10px;
1061
+ }
1062
+ /* "Write article" carries more text than "Feature" - split the row
1063
+ asymmetrically so its label gets breathing room */
1064
+ body.hfnx-active .hf-model-card__actions .hf-model-card__button--write { flex-grow: 1.22; }
1065
+ body.hfnx-active .hf-model-card__actions .hf-model-card__button--feature { flex-grow: 0.78; }
1066
+ /* bulk buttons: quieter, structured - full-width slim bars */
1067
+ body.hfnx-active .hf-models-dashboard__button {
1068
+ width: 100%; margin: 0 0 12px; padding: 7px 14px;
1069
+ display: inline-flex; align-items: center; justify-content: center; gap: 8px;
1070
+ border-radius: 10px; font-size: 13.5px; font-weight: 650;
1071
+ }
1072
+ body.hfnx-active .hf-models-column__head .hf-models-dashboard__button {
1073
+ width: auto; min-width: 0; min-height: 25px;
1074
+ margin: 0; padding: 3px 11px;
1075
+ border-radius: 8px; font-size: 12px;
1076
+ white-space: nowrap;
1077
+ }
1078
+ body.hfnx-active .hf-models-dashboard__button--primary {
1079
+ background: linear-gradient(180deg, #a6ff70, #8df453);
1080
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
1081
+ }
1082
+ body.hfnx-active .hf-models-dashboard__button--secondary .hf-button-icon { width: 13px; height: 13px; }
1083
+ /* frosted glass panel for the brand dropdown - DASHBOARD only: the
1084
+ landing slides the title + search bar aside instead, so the items
1085
+ float free there (no box) */
1086
+ body.hfnx-active.route-hf-models .hfnx-top .brand-stack__menu {
1087
+ background: rgba(10, 18, 31, 0.72);
1088
+ -webkit-backdrop-filter: blur(18px) saturate(1.25);
1089
+ backdrop-filter: blur(18px) saturate(1.25);
1090
+ border: 1px solid rgba(255, 255, 255, 0.12);
1091
+ border-radius: 18px;
1092
+ padding: 14px;
1093
+ box-shadow: 0 30px 70px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.08);
1094
+ }
1095
+ /* browsers without backdrop-filter still get an opaque panel instead
1096
+ of page text bleeding through the dropdown */
1097
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
1098
+ body.hfnx-active.route-hf-models .hfnx-top .brand-stack__menu {
1099
+ background: rgba(10, 16, 28, 0.96);
1100
+ }
1101
+ }
1102
+ /* mobile landing: nothing slides aside there, so free-floating items
1103
+ would collide with the hero - the tap-opened dropdown gets the same
1104
+ frosted panel as the dashboard route */
1105
+ @media (max-width: 860px) {
1106
+ body.hfnx-active .hfnx-top .brand-stack__menu {
1107
+ background: rgba(10, 18, 31, 0.9);
1108
+ -webkit-backdrop-filter: blur(18px) saturate(1.25);
1109
+ backdrop-filter: blur(18px) saturate(1.25);
1110
+ border: 1px solid rgba(255, 255, 255, 0.12);
1111
+ border-radius: 18px;
1112
+ padding: 14px;
1113
+ box-shadow: 0 30px 70px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.08);
1114
+ }
1115
+ }
1116
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
1117
+ @media (max-width: 860px) {
1118
+ body.hfnx-active .hfnx-top .brand-stack__menu {
1119
+ background: rgba(10, 16, 28, 0.97);
1120
+ }
1121
+ }
1122
+ }
1123
+ /* generous invisible hover halo: the item cards can extend past the
1124
+ menu's border box (and pointers cut corners between items) - without
1125
+ this, grazing just outside the box drops :hover mid-menu and the
1126
+ dropdown vanishes */
1127
+ body.hfnx-active .hfnx-top .brand-stack__menu::after {
1128
+ content: "";
1129
+ position: absolute;
1130
+ inset: -20px -26px -26px -20px;
1131
+ z-index: 0;
1132
+ }
1133
+
1134
+ /* ------------------------------------------------------------------ */
1135
+ /* Logged-in dashboard restyle (/next only): match the landing design */
1136
+ /* language - floating sections on the page glow instead of one giant */
1137
+ /* bordered box, lime CTAs, pill chips, gcard-style model cards. The */
1138
+ /* legacy (non-next) dashboard keeps its original styling untouched. */
1139
+ /* ------------------------------------------------------------------ */
1140
+ body.hfnx-active .hf-models-page {
1141
+ background: transparent !important;
1142
+ }
1143
+ body.hfnx-active .hf-models-dashboard {
1144
+ --hf-models-column-title-sticky-top: max(14px, env(safe-area-inset-top));
1145
+ border: 0;
1146
+ border-radius: 0;
1147
+ background: transparent;
1148
+ box-shadow: none;
1149
+ padding: 8px 0 60px;
1150
+ }
1151
+ body.hfnx-active .hf-models-dashboard__top { align-items: flex-start; gap: 18px; }
1152
+ body.hfnx-active .hf-models-dashboard__heading .eyebrow {
1153
+ display: inline-flex; align-items: center; gap: 8px;
1154
+ font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
1155
+ color: var(--muted, #91a0ba); background: none; border: 0; padding: 0;
1156
+ }
1157
+ body.hfnx-active .hf-models-dashboard__heading .eyebrow::before {
1158
+ content: ""; width: 7px; height: 7px; border-radius: 50%;
1159
+ background: var(--lime, #9cff63); box-shadow: 0 0 12px rgba(156, 255, 99, 0.8);
1160
+ }
1161
+ body.hfnx-active .hf-models-dashboard__heading h2 {
1162
+ margin: 10px 0 6px; font-size: clamp(30px, 3.4vw, 44px); line-height: 1.04;
1163
+ letter-spacing: -0.04em; color: var(--text, #f5f8ff); font-weight: 800;
1164
+ }
1165
+ body.hfnx-active .hf-models-dashboard__intro {
1166
+ color: var(--muted, #91a0ba); font-size: 15px; margin: 0;
1167
+ }
1168
+ body.hfnx-active .hf-models-dashboard__user {
1169
+ display: none;
1170
+ }
1171
+ body.hfnx-active .hf-bookmarks-page {
1172
+ padding: 8px 0 26px;
1173
+ }
1174
+ body.hfnx-active .hf-bookmarks-page__heading .eyebrow {
1175
+ display: inline-flex; align-items: center; gap: 8px;
1176
+ font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
1177
+ color: var(--muted, #91a0ba); background: none; border: 0; padding: 0;
1178
+ }
1179
+ body.hfnx-active .hf-bookmarks-page__heading .eyebrow::before {
1180
+ content: ""; width: 7px; height: 7px; border-radius: 50%;
1181
+ background: var(--lime, #9cff63); box-shadow: 0 0 12px rgba(156, 255, 99, 0.8);
1182
+ }
1183
+ body.hfnx-active .hf-bookmarks-page__heading h2 {
1184
+ margin: 10px 0 6px; font-size: clamp(30px, 3.4vw, 44px); line-height: 1.04;
1185
+ letter-spacing: -0.04em; color: var(--text, #f5f8ff); font-weight: 800;
1186
+ }
1187
+ body.hfnx-active .hf-bookmarks-page__intro {
1188
+ color: var(--muted, #91a0ba); font-size: 15px; margin: 0;
1189
+ }
1190
+ /* stat chips -> landing pill language, lime hover/active */
1191
+ body.hfnx-active .hf-models-dashboard__stats { gap: 8px; margin: 20px 0 4px; }
1192
+ body.hfnx-active .hf-models-dashboard__stat {
1193
+ display: inline-flex; align-items: center; gap: 8px;
1194
+ border: 1px solid var(--stroke, rgba(255,255,255,0.09));
1195
+ background: rgba(255, 255, 255, 0.035); border-radius: 999px;
1196
+ padding: 7px 15px; color: var(--muted-strong, #c5d0e3);
1197
+ font: 600 13px "Inter", sans-serif; cursor: pointer;
1198
+ transition: border-color 0.15s, color 0.15s, transform 0.12s;
1199
+ box-shadow: none;
1200
+ }
1201
+ body.hfnx-active .hf-models-dashboard__stat:hover {
1202
+ border-color: rgba(156, 255, 99, 0.45); color: var(--text, #f5f8ff);
1203
+ transform: translateY(-1px);
1204
+ }
1205
+ body.hfnx-active .hf-models-dashboard__stat-count {
1206
+ display: inline-grid; place-items: center; min-width: 22px; height: 22px;
1207
+ padding: 0 6px; border-radius: 999px; background: rgba(156, 255, 99, 0.14);
1208
+ color: var(--lime, #9cff63); font-weight: 800; font-size: 12px;
1209
+ }
1210
+ /* columns: floating glass panels like landing sections */
1211
+ body.hfnx-active .hf-models-dashboard__columns { gap: 14px; }
1212
+ body.hfnx-active .hf-models-column {
1213
+ border: 1px solid var(--stroke, rgba(255,255,255,0.09));
1214
+ background: rgba(255, 255, 255, 0.028);
1215
+ border-radius: 18px; padding: 18px 16px 16px;
1216
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.045);
1217
+ }
1218
+ body.hfnx-active .hf-models-column > h3 {
1219
+ margin: -4px 0 12px; font-size: 12px; letter-spacing: 0.14em;
1220
+ text-transform: uppercase; color: var(--muted, #91a0ba); font-weight: 600;
1221
+ border-color: rgba(156, 255, 99, 0.12);
1222
+ background:
1223
+ radial-gradient(circle at 12% 0%, rgba(156, 255, 99, 0.1), transparent 42%),
1224
+ linear-gradient(180deg, rgba(7, 14, 25, 0.92), rgba(4, 9, 17, 0.78));
1225
+ }
1226
+ body.hfnx-active .hf-models-dashboard__bookmarks {
1227
+ border: 0; background: transparent; box-shadow: none; padding: 0;
1228
+ margin-top: 18px;
1229
+ }
1230
+ body.hfnx-active .hf-models-column__intro {
1231
+ color: var(--muted, #91a0ba); font-size: 13px; margin-top: -6px;
1232
+ }
1233
+ /* model cards -> gcard language: dark art well, hover lift, lime edge */
1234
+ body.hfnx-active .hf-model-card {
1235
+ border: 1px solid var(--stroke, rgba(255,255,255,0.09));
1236
+ background: linear-gradient(180deg, rgba(11, 18, 32, 0.85), rgba(6, 11, 22, 0.92));
1237
+ border-radius: 16px; padding: 14px 14px 12px;
1238
+ transition: transform 0.16s ease, border-color 0.16s ease, box-shadow 0.16s ease;
1239
+ box-shadow: none;
1240
+ }
1241
+ body.hfnx-active .hf-model-card:hover {
1242
+ transform: translateY(-3px);
1243
+ border-color: rgba(156, 255, 99, 0.35);
1244
+ box-shadow: 0 16px 44px rgba(0, 0, 0, 0.42);
1245
+ }
1246
+ body.hfnx-active .hf-model-card__repo {
1247
+ color: var(--text, #f5f8ff); font-weight: 700; font-size: 14px;
1248
+ letter-spacing: -0.01em; overflow-wrap: anywhere;
1249
+ }
1250
+ body.hfnx-active .hf-model-card__meta {
1251
+ color: var(--muted, #91a0ba); font-size: 12px; margin-top: 2px;
1252
+ }
1253
+ body.hfnx-active .hf-model-card__preview-link {
1254
+ display: block; margin: 12px 0 10px; border-radius: 12px; overflow: hidden;
1255
+ }
1256
+ /* one frame only: the catalog art well paints the backdrop, so the
1257
+ inner preview keeps no box of its own; the framed-card fallback is
1258
+ self-contained and needs neither */
1259
+ body.hfnx-active .hf-model-card__preview {
1260
+ display: block; margin: 0 auto; padding: 0;
1261
+ background: none; border-radius: 0; height: auto; min-height: 0; max-height: none;
1262
+ }
1263
+ body.hfnx-active .hf-model-card--catalog .hf-model-card__preview,
1264
+ body.hfnx-active .hf-model-card--graph-preview .hf-model-card__preview { padding: 0; }
1265
+ body.hfnx-active .hf-model-card { display: flex; flex-direction: column; }
1266
+ body.hfnx-active .hf-model-card__actions {
1267
+ display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 2px;
1268
+ }
1269
+ body.hfnx-active .hf-model-card[data-dashboard-bucket="ready"] .hf-model-card__actions,
1270
+ body.hfnx-active .hf-model-card[data-dashboard-bucket="featured"] .hf-model-card__actions {
1271
+ grid-area: auto;
1272
+ width: 100%;
1273
+ height: auto;
1274
+ display: flex;
1275
+ flex-wrap: nowrap;
1276
+ align-items: stretch;
1277
+ align-self: stretch;
1278
+ margin-top: auto;
1279
+ padding-top: 8px;
1280
+ }
1281
+ body.hfnx-active .hf-model-card[data-dashboard-bucket="ready"] .hf-model-card__button,
1282
+ body.hfnx-active .hf-model-card[data-dashboard-bucket="featured"] .hf-model-card__button {
1283
+ width: 100%;
1284
+ min-width: 0;
1285
+ min-height: 36px;
1286
+ height: auto;
1287
+ flex: 1 1 100%;
1288
+ flex-direction: row;
1289
+ white-space: nowrap;
1290
+ }
1291
+ /* buttons: primary = lime CTA, everything else = outline pill */
1292
+ body.hfnx-active .hf-models-dashboard__button,
1293
+ body.hfnx-active .hf-model-card__button {
1294
+ border-radius: 10px; border: 1px solid var(--stroke, rgba(255,255,255,0.09));
1295
+ background: rgba(255, 255, 255, 0.05); color: var(--muted-strong, #c5d0e3);
1296
+ font: 620 13.5px/1.2 "Inter", sans-serif; padding: 7px 14px; cursor: pointer;
1297
+ transition: all 0.14s ease; box-shadow: none; text-shadow: none;
1298
+ }
1299
+ body.hfnx-active .hf-models-dashboard__button:hover,
1300
+ body.hfnx-active .hf-models-dashboard__button:focus-visible,
1301
+ body.hfnx-active .hf-model-card__button:hover,
1302
+ body.hfnx-active .hf-model-card__button:focus-visible {
1303
+ border-color: rgba(156, 255, 99, 0.45); color: var(--text, #f5f8ff);
1304
+ transform: translateY(-1px);
1305
+ outline: none;
1306
+ }
1307
+ body.hfnx-active .hf-models-dashboard__button--primary,
1308
+ body.hfnx-active .hf-model-card__button--primary {
1309
+ background: var(--lime, #9cff63); border-color: transparent; color: #07100d;
1310
+ font-weight: 700;
1311
+ }
1312
+ body.hfnx-active .hf-models-dashboard__button--primary:hover,
1313
+ body.hfnx-active .hf-models-dashboard__button--primary:focus-visible,
1314
+ body.hfnx-active .hf-model-card__button--primary:hover,
1315
+ body.hfnx-active .hf-model-card__button--primary:focus-visible {
1316
+ color: #07100d; box-shadow: 0 10px 28px rgba(156, 255, 99, 0.24);
1317
+ border-color: transparent; filter: brightness(1.04) saturate(1.04);
1318
+ }
1319
+ body.hfnx-active.route-hf-models .hf-models-page:not(.hf-article-login-page) .hf-models-login__actions {
1320
+ display: flex;
1321
+ align-items: center;
1322
+ flex-wrap: nowrap;
1323
+ gap: 12px;
1324
+ }
1325
+ body.hfnx-active.route-hf-models .hf-models-page:not(.hf-article-login-page) .hf-models-login__button {
1326
+ flex: 0 1 360px;
1327
+ width: auto;
1328
+ min-width: min(100%, 286px);
1329
+ padding: 0 22px;
1330
+ white-space: nowrap;
1331
+ }
1332
+ body.hfnx-active.route-hf-models .hf-models-page:not(.hf-article-login-page) .hf-models-login__back {
1333
+ flex: 0 0 auto;
1334
+ width: auto;
1335
+ min-width: 136px;
1336
+ margin: 0;
1337
+ padding: 0 18px;
1338
+ white-space: nowrap;
1339
+ }
1340
+ body.hfnx-active.route-hf-article-login .hf-models-login__actions,
1341
+ .page.route-hf-article-login .hf-models-login__actions {
1342
+ display: flex;
1343
+ align-items: center;
1344
+ flex-wrap: wrap;
1345
+ gap: 12px;
1346
+ }
1347
+ body.hfnx-active.route-hf-article-login .hf-models-login__button,
1348
+ .page.route-hf-article-login .hf-models-login__button {
1349
+ flex: 0 0 auto;
1350
+ width: auto;
1351
+ min-width: min(100%, 292px);
1352
+ padding: 0 22px;
1353
+ white-space: nowrap;
1354
+ }
1355
+ body.hfnx-active.route-hf-article-login .hf-models-login__back,
1356
+ .page.route-hf-article-login .hf-models-login__back {
1357
+ flex: 0 0 auto;
1358
+ width: auto;
1359
+ min-width: 132px;
1360
+ margin: 0;
1361
+ padding: 0 18px;
1362
+ white-space: nowrap;
1363
+ }
1364
+ @media (max-width: 720px) {
1365
+ body.hfnx-active.route-hf-models .hf-models-page:not(.hf-article-login-page) .hf-models-login__actions,
1366
+ body.hfnx-active.route-hf-article-login .hf-models-login__actions,
1367
+ .page.route-hf-article-login .hf-models-login__actions {
1368
+ display: grid;
1369
+ grid-template-columns: 1fr;
1370
+ }
1371
+ body.hfnx-active.route-hf-models .hf-models-page:not(.hf-article-login-page) .hf-models-login__button,
1372
+ body.hfnx-active.route-hf-models .hf-models-page:not(.hf-article-login-page) .hf-models-login__back,
1373
+ body.hfnx-active.route-hf-article-login .hf-models-login__button,
1374
+ body.hfnx-active.route-hf-article-login .hf-models-login__back,
1375
+ .page.route-hf-article-login .hf-models-login__button,
1376
+ .page.route-hf-article-login .hf-models-login__back {
1377
+ width: 100%;
1378
+ min-width: 0;
1379
+ white-space: normal;
1380
+ }
1381
+ }
1382
+ body.hfnx-active .hf-models-empty { color: var(--muted, #91a0ba); }
1383
+ /* loading screen: centered brand pulse + shimmer rows, landing tone */
1384
+ body.hfnx-active .hf-models-loading {
1385
+ display: grid; justify-items: center; align-content: center; gap: 8px;
1386
+ min-height: 46vh; text-align: center;
1387
+ border: 0; background: transparent; box-shadow: none;
1388
+ }
1389
+ body.hfnx-active .hf-models-loading[hidden] { display: none; }
1390
+ body.hfnx-active .hf-models-loading .eyebrow {
1391
+ font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
1392
+ color: var(--muted, #91a0ba); background: none; border: 0;
1393
+ justify-self: center; width: fit-content; margin: 0;
1394
+ }
1395
+ body.hfnx-active .hf-models-loading h2 {
1396
+ margin: 4px 0 2px; font-size: clamp(24px, 2.6vw, 34px);
1397
+ letter-spacing: -0.04em; color: var(--text, #f5f8ff); font-weight: 800;
1398
+ }
1399
+ body.hfnx-active .hf-models-loading .hf-models-login__status {
1400
+ color: var(--muted, #91a0ba); font-size: 14px;
1401
+ }
1402
+ body.hfnx-active .hf-models-loading::before {
1403
+ content: ""; width: 44px; height: 44px; border-radius: 14px; margin-bottom: 10px;
1404
+ background: linear-gradient(135deg, #9cff63, #57d364);
1405
+ box-shadow: 0 0 34px rgba(156, 255, 99, 0.45);
1406
+ animation: hfnx-load-pulse 1.15s ease-in-out infinite;
1407
+ }
1408
+ body.hfnx-active .hf-models-loading::after {
1409
+ content: ""; width: min(320px, 70vw); height: 8px; border-radius: 999px;
1410
+ margin-top: 18px;
1411
+ background: linear-gradient(90deg, rgba(255,255,255,0.05) 25%, rgba(156,255,99,0.28) 50%, rgba(255,255,255,0.05) 75%);
1412
+ background-size: 200% 100%;
1413
+ animation: hfnx-load-shimmer 1.3s linear infinite;
1414
+ }
1415
+ @keyframes hfnx-load-pulse {
1416
+ 0%, 100% { transform: scale(1); opacity: 1; }
1417
+ 50% { transform: scale(0.9); opacity: 0.75; }
1418
+ }
1419
+ @keyframes hfnx-load-shimmer {
1420
+ from { background-position: 200% 0; }
1421
+ to { background-position: -200% 0; }
1422
+ }
1423
+
hf-shell-css-2417117ca803.css ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ /* Preview-release landing: live model catalog gallery (hfpc-*).
3
+ Active only with ?blogs_with_graphs=1 / ?landing_blogs_with_graphs=1. */
4
+ body.hfpc-active .model-search,
5
+ body.hfpc-active .model-search-hit-shield { display: none !important; }
6
+ body.hfpc-active [data-page="landing"] .gallery:not(.hfpc-gallery) { display: none !important; }
7
+ /* Preview layout: gallery directly under the hero input; the proof
8
+ (feature cards) and creators strip move below the gallery so search
9
+ results render right where the user is typing. */
10
+ body.hfpc-active .gallery-section[data-page="landing"] { margin-top: 26px; }
11
+ body.hfpc-active .gallery-section[data-page="landing"] + .proof { margin-top: 44px; }
12
+ body.hfpc-active .proof + .hf-models-launch { margin-top: 20px; }
13
+ .hfpc-toolbar { display: grid; gap: 12px; margin: 4px 0 20px; }
14
+ .hfpc-toolbar__row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
15
+ .hfpc-sort {
16
+ background: rgba(255, 255, 255, 0.04); border: 1px solid var(--stroke, rgba(255,255,255,0.1));
17
+ border-radius: 999px; color: inherit; font: 13px "Inter", sans-serif;
18
+ padding: 9px 14px; outline: none; cursor: pointer;
19
+ }
20
+ .hfpc-sort option { background: #0a121f; }
21
+ .hfpc-count { color: var(--muted, #91a0ba); font-size: 13px; font-variant-numeric: tabular-nums; }
22
+ .hfpc-browse {
23
+ margin-left: auto; color: var(--lime, #9cff63); font-size: 0.8rem; font-weight: 600;
24
+ letter-spacing: 0.07em; text-transform: uppercase; text-decoration: none;
25
+ }
26
+ .hfpc-browse:hover { text-decoration: underline; }
27
+ .hfpc-filter {
28
+ background: transparent; border: 1px solid var(--stroke, rgba(255,255,255,0.1));
29
+ border-radius: 999px; color: var(--muted, #91a0ba); font: 12.5px "Inter", sans-serif;
30
+ padding: 6px 13px; cursor: pointer; transition: all 0.15s;
31
+ }
32
+ .hfpc-filter:hover { color: inherit; border-color: rgba(156, 255, 99, 0.35); }
33
+ .hfpc-filter.is-on {
34
+ color: #07100d; background: var(--lime, #9cff63);
35
+ border-color: var(--lime, #9cff63); font-weight: 600;
36
+ }
37
+ .hfpc-filter__count { opacity: 0.6; margin-left: 3px; font-variant-numeric: tabular-nums; }
38
+ .hfpc-gallery { position: relative; }
39
+ .hfpc-gallery .gallery-card { position: absolute; top: 0; left: 0; margin: 0; }
40
+ .hfpc-gallery .gallery-card__image { width: 100%; height: auto; display: block; }
41
+ .hfpc-gallery .gallery-card__sub { color: var(--muted, #91a0ba); font-size: 0.82rem; }
42
+ .hfpc-gallery .gallery-card__label.hfpc-has-avatar::before { display: none; }
43
+ .hfpc-avatar {
44
+ width: 20px; height: 20px; flex: 0 0 20px; border-radius: 6px;
45
+ object-fit: cover; background: #fff; padding: 1px; box-sizing: border-box;
46
+ align-self: center;
47
+ }
48
+ .hfpc-avatar--user { border-radius: 50%; }
49
+ .hfpc-empty { display: none; color: var(--muted, #91a0ba); padding: 34px 4px; font-size: 15px; }
50
+ .hfpc-empty.is-visible { display: block; }
51
+
hf-shell-css-4f6465bad160.css ADDED
The diff for this file is too large to render. See raw diff
 
index.html CHANGED
@@ -175,7 +175,15 @@
175
  }
176
  })();
177
  </script>
178
- <link rel="stylesheet" href="https://hfviewer.com/visualizer/hf-shell-css-4f6465bad160.css">
 
 
 
 
 
 
 
 
179
  <script>window.dataLayer=window.dataLayer||[];window.gtag=function(){};window.VIEWMYMODEL_HF_API_BASE="https://hfviewer.com/api";try{var u=new URL(window.location.href);var m=u.searchParams.get('model');if(m){window.__SX_DEEP_MODEL=m;u.searchParams.delete('model');window.history.replaceState(null,'',u.toString());}}catch(e){}</script>
180
  <style>
181
  /* --- injected by build_space_landing.py: sections stripped for the HF space --- */
@@ -5952,7 +5960,7 @@ body.sx-viewer-open { overflow: hidden; }
5952
  <canvas class="laser-layer" id="laserLayer" aria-hidden="true"></canvas>
5953
 
5954
  <script src="hf-shell-app.js"></script>
5955
- <link rel="stylesheet" href="https://hfviewer.com/visualizer/hf-shell-css-2417117ca803.css">
5956
  <script>
5957
  (function () {
5958
  "use strict";
@@ -6453,7 +6461,8 @@ body.sx-viewer-open { overflow: hidden; }
6453
  });
6454
  })();
6455
  </script>
6456
- <link rel="stylesheet" href="https://hfviewer.com/visualizer/hf-shell-css-04b3600b8d38.css">
 
6457
  <script>
6458
  (function () {
6459
  // "Log in" from the /next header lands on the same Visualize-my-models
@@ -10205,5 +10214,8 @@ body.sx-viewer-open { overflow: hidden; }
10205
  })();
10206
  </script>
10207
 
 
 
 
10208
  </body>
10209
  </html>
 
175
  }
176
  })();
177
  </script>
178
+ <link rel="stylesheet" href="hf-shell-css-4f6465bad160.css">
179
+ <script src="https://unpkg.com/es-module-shims@1.10.0/dist/es-module-shims.js"></script>
180
+ <script type="importmap">
181
+ {
182
+ "imports": {
183
+ "@huggingface/hub": "https://cdn.jsdelivr.net/npm/@huggingface/hub@2.11.2/+esm"
184
+ }
185
+ }
186
+ </script>
187
  <script>window.dataLayer=window.dataLayer||[];window.gtag=function(){};window.VIEWMYMODEL_HF_API_BASE="https://hfviewer.com/api";try{var u=new URL(window.location.href);var m=u.searchParams.get('model');if(m){window.__SX_DEEP_MODEL=m;u.searchParams.delete('model');window.history.replaceState(null,'',u.toString());}}catch(e){}</script>
188
  <style>
189
  /* --- injected by build_space_landing.py: sections stripped for the HF space --- */
 
5960
  <canvas class="laser-layer" id="laserLayer" aria-hidden="true"></canvas>
5961
 
5962
  <script src="hf-shell-app.js"></script>
5963
+ <link rel="stylesheet" href="hf-shell-css-2417117ca803.css">
5964
  <script>
5965
  (function () {
5966
  "use strict";
 
6461
  });
6462
  })();
6463
  </script>
6464
+ <link rel="stylesheet" href="hf-shell-css-04b3600b8d38.css">
6465
+ <link rel="stylesheet" href="style.css">
6466
  <script>
6467
  (function () {
6468
  // "Log in" from the /next header lands on the same Visualize-my-models
 
10214
  })();
10215
  </script>
10216
 
10217
+ <script src="space-shell.js"></script>
10218
+ <script type="module" src="space-auth.js"></script>
10219
+
10220
  </body>
10221
  </html>
space-auth.js ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ oauthHandleRedirectIfPresent,
3
+ oauthLoginUrl,
4
+ } from "@huggingface/hub";
5
+
6
+ const STORAGE_KEY = "hfviewer:space-native-oauth:v1";
7
+ const authHost = document.getElementById("hfnx-auth");
8
+
9
+ let oauthResult = readStoredResult();
10
+ let loginUrl = "";
11
+ let rendering = false;
12
+
13
+ function readStoredResult() {
14
+ try {
15
+ const value = localStorage.getItem(STORAGE_KEY);
16
+ return value ? JSON.parse(value) : null;
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ function writeStoredResult(value) {
23
+ try {
24
+ if (value) localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
25
+ else localStorage.removeItem(STORAGE_KEY);
26
+ } catch {
27
+ // Storage can be unavailable in privacy-focused browsers. The callback
28
+ // tab still remains signed in for the current render.
29
+ }
30
+ }
31
+
32
+ function userFromResult(result) {
33
+ const raw = result?.userInfo || result?.userinfo || result?.user_info || result?.user || {};
34
+ const username = String(
35
+ raw.preferred_username || raw.preferredUsername || raw.username || raw.name || ""
36
+ ).trim();
37
+ if (!username) return null;
38
+ return {
39
+ username,
40
+ name: String(raw.name || username).trim(),
41
+ picture: String(raw.picture || raw.avatar_url || raw.avatarUrl || "").trim(),
42
+ profile: String(raw.profile || `https://huggingface.co/${encodeURIComponent(username)}`).trim(),
43
+ };
44
+ }
45
+
46
+ function keepReleasePills() {
47
+ if (!authHost) return [];
48
+ return Array.from(authHost.children).filter((element) =>
49
+ element.classList.contains("hfnx-auth__pill")
50
+ );
51
+ }
52
+
53
+ function makeAvatar(user) {
54
+ if (user.picture) {
55
+ const image = document.createElement("img");
56
+ image.className = "hfnx-auth__avatar";
57
+ image.src = user.picture;
58
+ image.alt = "";
59
+ image.referrerPolicy = "no-referrer";
60
+ return image;
61
+ }
62
+ const letter = document.createElement("span");
63
+ letter.className = "hfnx-auth__avatar hfnx-auth__avatar--letter";
64
+ letter.textContent = user.username.charAt(0).toUpperCase();
65
+ return letter;
66
+ }
67
+
68
+ function makeLoggedOutControl() {
69
+ const link = document.createElement("a");
70
+ link.dataset.spaceNativeAuth = "login";
71
+ link.className = "space-native-auth-login";
72
+ link.textContent = "Log in";
73
+ link.title = "Sign in with Hugging Face";
74
+ link.target = "_blank";
75
+ link.rel = "noopener";
76
+ link.href = loginUrl || "#";
77
+ if (!loginUrl) link.setAttribute("aria-disabled", "true");
78
+ link.addEventListener("click", (event) => {
79
+ if (!loginUrl) event.preventDefault();
80
+ });
81
+ return link;
82
+ }
83
+
84
+ function makeLoggedInControl(user) {
85
+ const wrap = document.createElement("div");
86
+ wrap.dataset.spaceNativeAuth = "profile";
87
+ wrap.className = "space-native-auth-wrap";
88
+
89
+ const chip = document.createElement("button");
90
+ chip.type = "button";
91
+ chip.className = "hfnx-auth__chip";
92
+ chip.setAttribute("aria-haspopup", "menu");
93
+ chip.setAttribute("aria-expanded", "false");
94
+ chip.appendChild(makeAvatar(user));
95
+ const label = document.createElement("span");
96
+ label.textContent = user.username;
97
+ chip.appendChild(label);
98
+
99
+ const menu = document.createElement("div");
100
+ menu.className = "hfnx-auth__menu space-native-auth-menu";
101
+ menu.setAttribute("role", "menu");
102
+
103
+ const profile = document.createElement("a");
104
+ profile.className = "hfnx-auth__item";
105
+ profile.href = user.profile;
106
+ profile.target = "_blank";
107
+ profile.rel = "noopener";
108
+ profile.textContent = "Hugging Face profile";
109
+ profile.setAttribute("role", "menuitem");
110
+
111
+ const logout = document.createElement("button");
112
+ logout.type = "button";
113
+ logout.className = "hfnx-auth__item";
114
+ logout.textContent = "Log out";
115
+ logout.setAttribute("role", "menuitem");
116
+ logout.addEventListener("click", () => {
117
+ oauthResult = null;
118
+ writeStoredResult(null);
119
+ renderAuth();
120
+ });
121
+
122
+ const setOpen = (open) => {
123
+ menu.classList.toggle("is-open", open);
124
+ chip.setAttribute("aria-expanded", open ? "true" : "false");
125
+ };
126
+ chip.addEventListener("click", (event) => {
127
+ event.stopPropagation();
128
+ setOpen(!menu.classList.contains("is-open"));
129
+ });
130
+ document.addEventListener("click", () => setOpen(false));
131
+
132
+ menu.append(profile, logout);
133
+ wrap.append(chip, menu);
134
+ return wrap;
135
+ }
136
+
137
+ function renderAuth() {
138
+ if (!authHost || rendering) return;
139
+ rendering = true;
140
+ const pills = keepReleasePills();
141
+ const user = userFromResult(oauthResult);
142
+ authHost.replaceChildren(...pills, user ? makeLoggedInControl(user) : makeLoggedOutControl());
143
+ queueMicrotask(() => { rendering = false; });
144
+ }
145
+
146
+ function cleanCallbackQuery() {
147
+ try {
148
+ const url = new URL(window.location.href);
149
+ let changed = false;
150
+ for (const key of ["code", "state", "scope", "error", "error_description"]) {
151
+ if (url.searchParams.has(key)) {
152
+ url.searchParams.delete(key);
153
+ changed = true;
154
+ }
155
+ }
156
+ if (changed) history.replaceState(null, "", url.toString());
157
+ } catch {
158
+ // Cosmetic cleanup only.
159
+ }
160
+ }
161
+
162
+ async function initialize() {
163
+ renderAuth();
164
+ try {
165
+ const callbackResult = await oauthHandleRedirectIfPresent();
166
+ if (callbackResult) {
167
+ oauthResult = callbackResult;
168
+ writeStoredResult(callbackResult);
169
+ cleanCallbackQuery();
170
+ renderAuth();
171
+ }
172
+ } catch (error) {
173
+ console.warn("Hugging Face Space login callback failed", error);
174
+ }
175
+
176
+ try {
177
+ const scopes = window.huggingface?.variables?.OAUTH_SCOPES;
178
+ loginUrl = await oauthLoginUrl(scopes ? { scopes } : undefined);
179
+ } catch (error) {
180
+ console.warn("Could not prepare Hugging Face Space login", error);
181
+ }
182
+ renderAuth();
183
+ }
184
+
185
+ if (authHost) {
186
+ const observer = new MutationObserver(() => {
187
+ if (!rendering && !authHost.querySelector("[data-space-native-auth]")) renderAuth();
188
+ });
189
+ observer.observe(authHost, { childList: true });
190
+ }
191
+
192
+ window.addEventListener("storage", (event) => {
193
+ if (event.key !== STORAGE_KEY) return;
194
+ oauthResult = readStoredResult();
195
+ renderAuth();
196
+ });
197
+
198
+ initialize();
space-shell.js ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function () {
2
+ "use strict";
3
+
4
+ var CARD_PREFIX = "https://hfviewer.com/models/cards/";
5
+ var API_PREFIX = "https://hfviewer.com/api/graph-preview.svg";
6
+
7
+ function repositoryFromImage(image) {
8
+ var alt = String(image.getAttribute("alt") || "").trim();
9
+ var suffix = " architecture graph";
10
+ if (alt.endsWith(suffix)) return alt.slice(0, -suffix.length).trim();
11
+
12
+ var card = image.closest("[data-model]");
13
+ if (!card) return "";
14
+ try {
15
+ var url = new URL(String(card.dataset.model || ""), window.location.href);
16
+ return url.pathname.replace(/^\/+|\/+$/g, "");
17
+ } catch (error) {
18
+ return "";
19
+ }
20
+ }
21
+
22
+ function restoreCard(image) {
23
+ if (!(image instanceof HTMLImageElement)) return;
24
+ if (image.dataset.spaceCardFallback === "1") return;
25
+ if (!String(image.currentSrc || image.src || "").startsWith(CARD_PREFIX)) return;
26
+ var repository = repositoryFromImage(image);
27
+ if (!repository || repository.split("/").length !== 2) return;
28
+
29
+ image.dataset.spaceCardFallback = "1";
30
+ var query = new URLSearchParams({
31
+ source: repository,
32
+ source_page: "hf-space",
33
+ });
34
+ image.src = API_PREFIX + "?" + query.toString();
35
+ }
36
+
37
+ document.addEventListener("error", function (event) {
38
+ restoreCard(event.target);
39
+ }, true);
40
+
41
+ function repairAlreadyFailedImages(root) {
42
+ var images = (root || document).querySelectorAll("img");
43
+ images.forEach(function (image) {
44
+ if (image.complete && image.naturalWidth === 0) restoreCard(image);
45
+ });
46
+ }
47
+
48
+ repairAlreadyFailedImages(document);
49
+ new MutationObserver(function (records) {
50
+ records.forEach(function (record) {
51
+ record.addedNodes.forEach(function (node) {
52
+ if (!(node instanceof Element)) return;
53
+ if (node instanceof HTMLImageElement) restoreCard(node);
54
+ repairAlreadyFailedImages(node);
55
+ });
56
+ });
57
+ }).observe(document.body, { childList: true, subtree: true });
58
+ })();
style.css CHANGED
@@ -1,28 +1,87 @@
 
 
 
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
 
 
28
  }
 
1
+ /* Space-owned safety net. The full hfviewer shell is vendored alongside this
2
+ file, but these colors also prevent a white flash while the larger styles
3
+ are parsed. */
4
+ :root,
5
+ html,
6
  body {
7
+ color-scheme: dark;
8
+ background: #050914 !important;
9
  }
10
 
11
+ body {
12
+ min-height: 100vh;
13
+ color: #f5f7fb;
14
+ }
15
+
16
+ /* The Space snapshot normally hides hfviewer.com's own cross-origin auth.
17
+ Native Space OAuth is the one exception. */
18
+ body .hfnx-auth > [data-space-native-auth] {
19
+ display: inline-flex !important;
20
+ }
21
+
22
+ .space-native-auth-login {
23
+ align-items: center;
24
+ justify-content: center;
25
+ min-height: 36px;
26
+ padding: 0 14px;
27
+ border: 1px solid rgba(255, 255, 255, 0.16);
28
+ border-radius: 10px;
29
+ background: rgba(255, 255, 255, 0.07);
30
+ color: #f8fafc;
31
+ font: 600 13px/1 Inter, ui-sans-serif, system-ui, sans-serif;
32
+ text-decoration: none;
33
+ white-space: nowrap;
34
+ transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
35
+ }
36
+
37
+ .space-native-auth-login:hover {
38
+ border-color: rgba(159, 255, 102, 0.62);
39
+ background: rgba(159, 255, 102, 0.1);
40
+ transform: translateY(-1px);
41
+ }
42
+
43
+ .space-native-auth-login[aria-disabled="true"] {
44
+ cursor: wait;
45
+ opacity: 0.62;
46
+ }
47
+
48
+ .space-native-auth-wrap {
49
+ position: relative;
50
+ align-items: center;
51
+ }
52
+
53
+ .space-native-auth-wrap .hfnx-auth__chip {
54
+ display: inline-flex !important;
55
+ }
56
+
57
+ body .space-native-auth-menu {
58
+ display: none !important;
59
+ position: absolute;
60
+ top: calc(100% + 8px);
61
+ right: 0;
62
+ z-index: 4200;
63
+ min-width: 168px;
64
+ padding: 6px;
65
+ border: 1px solid rgba(255, 255, 255, 0.12);
66
+ border-radius: 12px;
67
+ background: rgba(13, 17, 29, 0.98);
68
+ box-shadow: 0 18px 48px rgba(0, 0, 0, 0.42);
69
  }
70
 
71
+ body .space-native-auth-menu.is-open {
72
+ display: grid !important;
 
 
 
73
  }
74
 
75
+ .space-native-auth-menu .hfnx-auth__item {
76
+ width: 100%;
77
+ box-sizing: border-box;
78
+ text-align: left;
 
 
79
  }
80
 
81
+ @media (max-width: 640px) {
82
+ .space-native-auth-login {
83
+ min-height: 34px;
84
+ padding: 0 10px;
85
+ font-size: 12px;
86
+ }
87
  }