@hattisar/design-tokens 0.3.19 → 0.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tokens.css +200 -85
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hattisar/design-tokens",
3
- "version": "0.3.19",
3
+ "version": "0.3.21",
4
4
  "description": "Shared design tokens (colors, type, radius, spacing, motion) and base primitives (reset, buttons, inputs, cards, modals, auth shell) for every Hattisar frontend.",
5
5
  "main": "tokens.css",
6
6
  "files": [
package/tokens.css CHANGED
@@ -109,31 +109,19 @@
109
109
  --color-brand-active: color-mix(in srgb, var(--color-brand) 70%, black);
110
110
  --color-brand-text: #ffffff;
111
111
 
112
- /* The main call to action.
113
- Asked for by hex: "main CTA color #4285f4". It is the one place in
114
- this palette with a hue — greys carry structure, colour carries
115
- status, and now one blue carries "this is the button you press".
116
- --color-brand stays charcoal ink: it is the focus ring, the active
117
- tab marker and the checkbox tick, and turning all of those blue is
118
- a bigger change than a call-to-action colour.
119
-
120
- White on #4285f4 measures 3.56:1, below the 4.5:1 this file
121
- promises everywhere else. It is recorded as a deliberate exception
122
- in check-contrast.mjs rather than quietly left out of it — the
123
- nearest shade that passes is #1a73e8 at 4.51:1, visually the same
124
- blue, if the ratio matters more than the exact hex. */
125
- --color-cta: #4285f4;
126
- /* The call-to-action blue as *text* on a surface, which is a
127
- stricter bar than as a fill. #4285f4 carries white at 3.56:1 — the
128
- one documented exception in check-contrast.mjs — and reusing it for
129
- text would spread that exception instead of containing it. Scaled
130
- 13% darker it reaches 4.59:1 on a white card while reading as the
131
- same blue. Dark mode needs no adjustment: #4285f4 already measures
132
- 4.61:1 on #1f1f23, so it keeps the brand hex exactly. */
133
- --color-cta-on-surface: #3973d4;
134
- --color-cta-hover: color-mix(in srgb, var(--color-cta) 88%, black);
135
- --color-cta-active: color-mix(in srgb, var(--color-cta) 76%, black);
136
- --color-cta-text: #ffffff;
112
+ /* The main call to action — charcoal ink, the same as --color-brand,
113
+ not a hue of its own. Used to be a blue chosen by hex; asked for
114
+ directly to remove ("just keep our dark color"). Kept as its own
115
+ token rather than collapsed into --color-brand directly, since the
116
+ handful of places that render it as text on a raised surface
117
+ (sidebar current-row, a link's hover state, an input's focus
118
+ border) still reach for --color-cta-on-surface/--color-cta by
119
+ name, and this way none of them had to change. */
120
+ --color-cta: var(--color-brand);
121
+ --color-cta-on-surface: var(--color-brand);
122
+ --color-cta-hover: var(--color-brand-hover);
123
+ --color-cta-active: var(--color-brand-active);
124
+ --color-cta-text: var(--color-brand-text);
137
125
 
138
126
 
139
127
  /* Secondary button — bordered light-gray fill. Reuses
@@ -144,10 +132,12 @@
144
132
  --color-secondary-border: var(--color-border-strong);
145
133
  --color-secondary-text: var(--color-text-primary);
146
134
  --color-secondary-hover: color-mix(in srgb, var(--color-text-primary) 6%, var(--color-secondary-fill));
135
+ --color-secondary-active: color-mix(in srgb, var(--color-text-primary) 12%, var(--color-secondary-fill));
147
136
 
148
137
  /* Destructive button — irreversible actions only (delete, void). */
149
138
  --color-destructive-fill: #c70a24;
150
139
  --color-destructive-hover: #a30a24;
140
+ --color-destructive-active: color-mix(in srgb, black 15%, var(--color-destructive-hover));
151
141
  --color-destructive-text: #ffffff;
152
142
 
153
143
  /* General-purpose semantic text/icon colors (form errors, savebar
@@ -219,13 +209,58 @@
219
209
  remove-buttons inside chips, the settings toggle switch) — never
220
210
  applied to a badge/tag/chip just for a rounder look; those use
221
211
  --radius-sm like everything else (see .status-badge and friends). */
222
- --radius-xs: 5px;
223
- --radius-sm: 7px;
224
- --radius-md: 10px;
225
- --radius-lg: 13px;
226
- --radius-xl: 16px;
212
+ --radius-xs: 6px;
213
+ --radius-sm: 8px;
214
+ --radius-md: 11px;
215
+ --radius-lg: 14px;
216
+ --radius-xl: 17px;
227
217
  --radius-full: 9999px;
228
218
 
219
+ /* The horizontal tab block (Tabs.tsx) — one frame for every context it
220
+ appears in, whether wrapped in .card (document forms) or
221
+ .form-section-tabs (Customer/Vendor/Item). Transparent on purpose:
222
+ the frame shows the page canvas, so the strip reads as a gray band
223
+ and the active tab's white pill and the white panel below stand out
224
+ against it. A .card frame (white) hid both. */
225
+ --tabs-frame-bg: transparent;
226
+ --tabs-frame-border: 1px solid var(--color-border);
227
+ --tabs-frame-radius: var(--radius-sm);
228
+
229
+ /* Anything that floats over the page: dropdown and action menus, the
230
+ global-search results, combobox lists, the profile/notification
231
+ drawer, tooltips and modal dialogs. Their surface already had a
232
+ border and a shadow but no radius, so every popup was a hard
233
+ rectangle beside the rounded buttons and cards that opened it. */
234
+ --popup-radius: var(--radius-sm);
235
+
236
+ /* The header row shared by every titled card (WidgetCard) and the tab
237
+ strip that stands in for one, and the control that sits inside it (a
238
+ "+" button, a filter select). Two numbers so the strip and the card
239
+ header can't drift apart, and so a control added to a header is sized
240
+ to fit it rather than stretching it. */
241
+ --card-header-height: 36px;
242
+ --card-header-control-height: 24px;
243
+
244
+ /* Colours that must not follow the theme, named instead of repeated as
245
+ hex. White on a saturated fill (an org tile, an integration logo)
246
+ stays white in dark mode; the scrim dims the page behind a modal or
247
+ the mobile nav; a video letterbox is black either way; a printed
248
+ page is always paper and ink. */
249
+ --color-on-accent: #ffffff;
250
+ --color-logo-backdrop: #ffffff;
251
+ --color-scrim: rgba(26, 26, 26, 0.45);
252
+ --color-media-backdrop: #000000;
253
+ --print-paper: #ffffff;
254
+ --print-ink: #0f172a;
255
+
256
+ /* The row a list page's summary tiles and search/filter toolbar share.
257
+ 48px, not the 36px table-header/tab-strip row: those are dense
258
+ header bands; this one holds a text field and a view switcher you
259
+ click into, and at 36px the icon and text sat against the card edge
260
+ and the gray column-header band right below ("search area look very
261
+ tight"). One token so the tiles and the toolbar can't drift apart. */
262
+ --toolbar-row-height: 48px;
263
+
229
264
  /* Depth, deliberately restrained. These were all `none`, which left
230
265
  every surface separated by border alone — correct, legible, and
231
266
  completely flat: a card, a dropdown and a modal all sat on the page
@@ -256,6 +291,19 @@
256
291
  be able to open on top of a dialog it lives inside. */
257
292
  --z-dropdown: 110;
258
293
  --z-modal: 100;
294
+ /* The app shell's own layers, bottom to top. Named with the values
295
+ they always had, so nothing restacks: the docked support panel sits
296
+ under the sidebar rail, both under the banners and the header, and
297
+ the mobile nav (with its backdrop just beneath it) over everything
298
+ but a dropdown or dialog. Component-local stacking (1, 2, 5, 15, 20
299
+ inside a table, a tooltip, a timeline) stays a literal — it only
300
+ orders a component's own children, not the page. */
301
+ --z-support-panel: 40;
302
+ --z-sidebar: 50;
303
+ --z-banner: 59;
304
+ --z-header: 60;
305
+ --z-mobile-backdrop: 150;
306
+ --z-mobile-nav: 200;
259
307
 
260
308
  /* 4px-based spacing scale — new markup (bento tiles, order cards)
261
309
  should reach for these instead of new magic numbers. Existing
@@ -354,7 +402,10 @@
354
402
  --duration-base: 150ms;
355
403
  --duration-slow: 250ms;
356
404
 
357
- --header-height: 52px;
405
+ /* 58px, not 52 — asked for directly, matched against a reference
406
+ layout's own header height so this app's chrome proportions read
407
+ the same. */
408
+ --header-height: 58px;
358
409
 
359
410
  /* Exact Hattisar Design match — aside/header sit at the same white
360
411
  --hd-card-bg as every card (bordered, not tonally separate),
@@ -383,8 +434,11 @@
383
434
  --sidebar-rail-bg: var(--color-background-card);
384
435
 
385
436
  /* Every left-hand nav rail in an app sharing this one width instead
386
- of each picking its own. */
387
- --sidebar-width: 240px;
437
+ of each picking its own. 260px, not 240 — asked for directly,
438
+ matched (to the nearest round number) against a reference
439
+ layout's own sidebar width, the same reason --header-height above
440
+ moved too. */
441
+ --sidebar-width: 260px;
388
442
  --sidebar-width-collapsed: 64px;
389
443
  --sidebar-height: calc(100vh - var(--header-height));
390
444
 
@@ -418,6 +472,20 @@
418
472
  --page-width-medium: var(--page-width-content);
419
473
  --page-width-large: var(--page-width-content);
420
474
 
475
+ /* A second, wider cap for a list/table page (Items, Sales Orders,
476
+ Purchase Orders, ...) — reported directly ("keep wide page width
477
+ for tables... another page width for form which is shorter in
478
+ centered like now"). --page-width-content stays the form width
479
+ (a column you can read across); a table wants more of the room a
480
+ wide monitor actually has, so this is capped further out instead
481
+ of sharing the form's own number. Used by the one rule that caps
482
+ a plain list page's root <div> (.page-content-scroll, further
483
+ down) — forms keep their own narrower cap untouched.
484
+
485
+ 1440 → 1680: asked for directly ("more wide than 1440px") right
486
+ after the first pass shipped. */
487
+ --page-width-wide: 1680px;
488
+
421
489
  color-scheme: light dark;
422
490
  }
423
491
 
@@ -477,13 +545,13 @@
477
545
  --color-brand-hover: color-mix(in srgb, var(--color-brand) 90%, black);
478
546
  --color-brand-active: color-mix(in srgb, var(--color-brand) 75%, black);
479
547
  --color-brand-text: #09090b;
480
- --color-cta: #4285f4;
481
- /* Light mode darkens this for contrast; on a dark surface the brand
482
- blue already clears AA, so it stands unmodified. */
483
- --color-cta-on-surface: #4285f4;
484
- --color-cta-hover: color-mix(in srgb, var(--color-cta) 88%, black);
485
- --color-cta-active: color-mix(in srgb, var(--color-cta) 76%, black);
486
- --color-cta-text: #ffffff;
548
+ /* See :root's own --color-cta for why this is brand ink and not a
549
+ hue of its own. */
550
+ --color-cta: var(--color-brand);
551
+ --color-cta-on-surface: var(--color-brand);
552
+ --color-cta-hover: var(--color-brand-hover);
553
+ --color-cta-active: var(--color-brand-active);
554
+ --color-cta-text: var(--color-brand-text);
487
555
 
488
556
  --shadow-btn-primary: 0 1px 2px rgba(9, 9, 11, 0.12);
489
557
  --shadow-btn-secondary: 0 1px 2px rgba(9, 9, 11, 0.05);
@@ -492,9 +560,11 @@
492
560
  --color-secondary-border: var(--color-border-strong);
493
561
  --color-secondary-text: var(--color-text-primary);
494
562
  --color-secondary-hover: color-mix(in srgb, white 6%, var(--color-secondary-fill));
563
+ --color-secondary-active: color-mix(in srgb, white 12%, var(--color-secondary-fill));
495
564
 
496
565
  --color-destructive-fill: #a30a24;
497
566
  --color-destructive-hover: #c70a24;
567
+ --color-destructive-active: color-mix(in srgb, white 15%, var(--color-destructive-hover));
498
568
  --color-destructive-text: #ffffff;
499
569
 
500
570
  --color-warning: var(--accent-amber);
@@ -553,9 +623,9 @@
553
623
  --sidebar-text-muted: var(--color-text-muted);
554
624
  --sidebar-active-text: var(--color-text-primary);
555
625
  --sidebar-hover-bg: rgba(255, 255, 255, 0.06);
556
- /* --color-cta unmodified here: on #18181b it measures 4.97:1, where
557
- the on-surface variant light theme uses is tuned for a white
558
- ground. See the light block above for what this token is. */
626
+ /* --color-cta is brand ink now (see :root's own --color-cta) — this
627
+ "current row" marker used to lean on the accent blue clearing AA
628
+ on #18181b without the on-surface variant's extra darkening. */
559
629
  --sidebar-active-ink: var(--color-cta);
560
630
  --sidebar-rail-bg: #18181b;
561
631
 
@@ -586,18 +656,13 @@
586
656
  --color-brand-hover: color-mix(in srgb, var(--color-brand) 85%, black);
587
657
  --color-brand-active: color-mix(in srgb, var(--color-brand) 70%, black);
588
658
  --color-brand-text: #ffffff;
589
- --color-cta: #4285f4;
590
- /* The call-to-action blue as *text* on a surface, which is a
591
- stricter bar than as a fill. #4285f4 carries white at 3.56:1 — the
592
- one documented exception in check-contrast.mjs — and reusing it for
593
- text would spread that exception instead of containing it. Scaled
594
- 13% darker it reaches 4.59:1 on a white card while reading as the
595
- same blue. Dark mode needs no adjustment: #4285f4 already measures
596
- 4.61:1 on #1f1f23, so it keeps the brand hex exactly. */
597
- --color-cta-on-surface: #3973d4;
598
- --color-cta-hover: color-mix(in srgb, var(--color-cta) 88%, black);
599
- --color-cta-active: color-mix(in srgb, var(--color-cta) 76%, black);
600
- --color-cta-text: #ffffff;
659
+ /* See :root's own --color-cta for why this is brand ink and not a
660
+ hue of its own. */
661
+ --color-cta: var(--color-brand);
662
+ --color-cta-on-surface: var(--color-brand);
663
+ --color-cta-hover: var(--color-brand-hover);
664
+ --color-cta-active: var(--color-brand-active);
665
+ --color-cta-text: var(--color-brand-text);
601
666
 
602
667
  --shadow-btn-primary: 0 1px 2px rgba(0, 0, 0, 0.4);
603
668
  --shadow-btn-secondary: 0 1px 2px rgba(0, 0, 0, 0.3);
@@ -606,9 +671,11 @@
606
671
  --color-secondary-border: var(--color-border-strong);
607
672
  --color-secondary-text: var(--color-text-primary);
608
673
  --color-secondary-hover: color-mix(in srgb, var(--color-text-primary) 6%, var(--color-secondary-fill));
674
+ --color-secondary-active: color-mix(in srgb, var(--color-text-primary) 12%, var(--color-secondary-fill));
609
675
 
610
676
  --color-destructive-fill: #c70a24;
611
677
  --color-destructive-hover: #a30a24;
678
+ --color-destructive-active: color-mix(in srgb, black 15%, var(--color-destructive-hover));
612
679
  --color-destructive-text: #ffffff;
613
680
 
614
681
  --color-warning: #8a6600;
@@ -692,7 +759,6 @@
692
759
 
693
760
  *::-webkit-scrollbar-thumb {
694
761
  background: var(--color-border-strong);
695
- border-radius: var(--radius-full);
696
762
  border: 2px solid transparent;
697
763
  background-clip: padding-box;
698
764
  }
@@ -761,11 +827,19 @@ a {
761
827
  text-decoration: none;
762
828
  }
763
829
 
764
- /* The app's one accent blue — same token as the sidebar's current-row
765
- ink and the active document tab. Not .card: a card-styled link is a
766
- clickable surface, not inline text, and turning its whole contents
767
- blue on hover would tint every stat number/label inside a dashboard
768
- tile along with it (see a.card below, which keeps its own hover
830
+ /* Color shift only, no underline. Nav rows, table rows, menu items and
831
+ every other structural link declare their own higher-specificity
832
+ :hover with a background fill, so this rule never actually paints on
833
+ them — an underline here used to show through anyway, stacked on
834
+ top of that fill, which read as two hover cues on one row instead of
835
+ one. What's left is what a bare inline-text link (no background
836
+ treatment of its own) gets, and a color change is enough there.
837
+
838
+ Not .card: a card-styled link is a clickable surface, not inline
839
+ text, and most of what's inside one already carries its own explicit
840
+ color — but any incidental text that doesn't would pick up this
841
+ tint on hover, which reads as random flicker rather than a link
842
+ changing color (see a.card below, which keeps its own hover
769
843
  treatment instead). */
770
844
  a:hover:not(.card) {
771
845
  color: var(--color-cta-on-surface);
@@ -774,7 +848,6 @@ a:hover:not(.card) {
774
848
  a:focus-visible {
775
849
  outline: 1.5px dashed var(--color-brand);
776
850
  outline-offset: 4px;
777
- border-radius: var(--radius-full);
778
851
  }
779
852
 
780
853
  /* A label should recede so the value it names is what gets scanned.
@@ -797,16 +870,16 @@ label[data-required]::after {
797
870
  font-weight: var(--font-weight-regular);
798
871
  }
799
872
 
800
- /* Primary action — the call-to-action fill. Charcoal until it was
801
- given a colour of its own; --color-brand still carries structure
802
- (focus ring, active tab, checkbox tick) and is deliberately not
803
- this. */
873
+ /* Primary action — the call-to-action fill. Charcoal, the same ink as
874
+ --color-brand (see --color-cta above): had a hue of its own for a
875
+ while, removed to keep color reserved for status/data, same as
876
+ everywhere else in this palette. */
804
877
  button {
805
878
  font: inherit;
806
879
  cursor: pointer;
807
880
  border: none;
808
- border-radius: var(--radius-sm);
809
- padding: 5px 10px;
881
+ border-radius: var(--radius-xs);
882
+ padding: 4px 10px;
810
883
  font-size: var(--text-base);
811
884
  font-weight: 400;
812
885
  background: var(--color-cta);
@@ -867,8 +940,8 @@ button:focus-visible {
867
940
  font: inherit;
868
941
  cursor: pointer;
869
942
  border: none;
870
- border-radius: var(--radius-sm);
871
- padding: 5px 10px;
943
+ border-radius: var(--radius-xs);
944
+ padding: 4px 10px;
872
945
  font-size: var(--text-base);
873
946
  font-weight: 400;
874
947
  background: var(--color-secondary-fill);
@@ -882,6 +955,16 @@ button:focus-visible {
882
955
  opacity: 1;
883
956
  }
884
957
 
958
+ /* Needed despite the bare button:active rule above already setting a
959
+ background on press — button:active's specificity (an element plus
960
+ a pseudo-class) beats .btn-secondary's own single class regardless
961
+ of source order, so without this, pressing a secondary button
962
+ flashed the *primary* button's dark --color-cta-active fill instead
963
+ of staying in its own secondary color family. */
964
+ .btn-secondary:active {
965
+ background: var(--color-secondary-active);
966
+ }
967
+
885
968
  /* Destructive action — irreversible operations only (delete, void,
886
969
  permanently remove). Not the default for every "Delete" button in
887
970
  an app; opt in per call site where the action truly can't be
@@ -893,8 +976,8 @@ button:focus-visible {
893
976
  font: inherit;
894
977
  cursor: pointer;
895
978
  border: none;
896
- border-radius: var(--radius-sm);
897
- padding: 5px 10px;
979
+ border-radius: var(--radius-xs);
980
+ padding: 4px 10px;
898
981
  font-size: var(--text-base);
899
982
  font-weight: 400;
900
983
  background: var(--color-destructive-fill);
@@ -911,6 +994,14 @@ button:focus-visible {
911
994
  background: var(--color-destructive-hover);
912
995
  }
913
996
 
997
+ /* Same reason .btn-secondary:active exists above — button:active's
998
+ own specificity would otherwise win with the primary button's
999
+ --color-cta-active fill instead of a darker/lighter shade of this
1000
+ button's own red. */
1001
+ .btn-danger:active {
1002
+ background: var(--color-destructive-active);
1003
+ }
1004
+
914
1005
  /* font-family is inherited; size, weight and colour are stated.
915
1006
  `font: inherit` alone meant a field took its type from whatever
916
1007
  wrapped it — and most fields in this app are wrapped in their own
@@ -1152,11 +1243,9 @@ label:has(:required) .combobox-input {
1152
1243
  color: var(--color-text-primary);
1153
1244
  }
1154
1245
 
1155
- /* The app's one accent blue, not --color-brand — asked for directly.
1156
- --color-brand still does the same job for the controls that used to
1157
- share this border with it (checkbox tick, a:focus-visible's outline),
1158
- so it stays defined as-is; this just stops reading its (near-black)
1159
- value for the field border specifically.
1246
+ /* --color-cta-on-surface is brand ink now (see :root's own --color-cta)
1247
+ — this used to read a separate accent blue here, kept as its own
1248
+ token in case the two ever need to diverge again.
1160
1249
 
1161
1250
  No box-shadow ring — asked for directly ("we do not need out shadow
1162
1251
  on input area when typing"). :focus and :focus-visible used to carry
@@ -1222,18 +1311,44 @@ input[type="radio"] {
1222
1311
  accent-color: var(--color-brand);
1223
1312
  }
1224
1313
 
1225
- /* Shadow-based elevation, plus a hairline border — the card surface
1226
- and page canvas are close enough in lightness that shadow alone
1227
- doesn't read as a distinct edge, so the border carries definition
1228
- while the shadow carries depth. */
1314
+ /* Shadow-based elevation, plus a real border — the card surface and
1315
+ page canvas are close enough in lightness that shadow alone doesn't
1316
+ read as a distinct edge, so the border carries definition while the
1317
+ shadow carries depth. 1px border-strong, not the old 0.5px border —
1318
+ unified with .widget-card (tokens.css), which had already moved to
1319
+ the crisper weight and color and left plain .card as the one place
1320
+ still drawing a thinner, lighter line for what is the same "a card"
1321
+ job. */
1229
1322
  .card {
1230
1323
  background: var(--color-background-card);
1231
- border: 0.5px solid var(--color-border);
1232
- border-radius: var(--radius-lg);
1324
+ border: 1px solid var(--color-border-strong);
1325
+ border-radius: var(--radius-sm);
1233
1326
  box-shadow: var(--shadow-sm);
1234
1327
  padding: 16px;
1235
1328
  }
1236
1329
 
1330
+ /* The standard gap between two vertically stacked cards — asked for
1331
+ directly, "organize" the pages that each hand-rolled their own
1332
+ marginBottom for this (16px and 20px both showed up for the same
1333
+ "space before the next card" job, no rule for which).
1334
+
1335
+ Opt-in via .card-stack on the shared parent, not a blanket
1336
+ `.card + .card` — a margin-top here would land on the cross axis,
1337
+ not stack spacing, wherever two cards sit in a flex row/wrap
1338
+ instead of a vertical flow (confirmed at least one such case:
1339
+ BillingPage's plan-comparison grid), silently misaligning them.
1340
+ .card-stack marks "these siblings really are a vertical stack" so
1341
+ the rule only ever fires where that is true. Un-opted-in card
1342
+ sequences keep whatever spacing they already declare.
1343
+
1344
+ .widget-card counts as a card here. It didn't, and once the
1345
+ integration pages' Connection card became a WidgetCard the Orders
1346
+ card sat flush against it ("add some space on top of order card") —
1347
+ the rule only knew .card + .card. */
1348
+ .card-stack > :is(.card, .widget-card) + :is(.card, .widget-card) {
1349
+ margin-top: 16px;
1350
+ }
1351
+
1237
1352
  /* A card whose entire content is a table — no inset padding, so the
1238
1353
  table's own row/column lines run edge-to-edge to the card's outer
1239
1354
  border instead of floating inside a padded frame. overflow: hidden
@@ -1460,7 +1575,7 @@ a.card:hover {
1460
1575
  .modal-overlay {
1461
1576
  position: fixed;
1462
1577
  inset: 0;
1463
- background: rgba(26, 26, 26, 0.45);
1578
+ background: var(--color-scrim);
1464
1579
  display: flex;
1465
1580
  align-items: flex-start;
1466
1581
  justify-content: center;
@@ -1471,7 +1586,6 @@ a.card:hover {
1471
1586
  .modal-panel {
1472
1587
  background: var(--color-surface-raised);
1473
1588
  border: 1px solid var(--color-border-raised);
1474
- border-radius: var(--radius-lg);
1475
1589
  box-shadow: var(--shadow-popover);
1476
1590
  width: 100%;
1477
1591
  max-width: 640px;
@@ -1479,6 +1593,7 @@ a.card:hover {
1479
1593
  display: flex;
1480
1594
  flex-direction: column;
1481
1595
  overflow: hidden;
1596
+ border-radius: var(--popup-radius);
1482
1597
  }
1483
1598
 
1484
1599
  .modal-panel-header {