@crvouga/atlas 0.10.2 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +7 -0
  3. package/dist/reports/src/catalog-health.d.ts +142 -0
  4. package/dist/reports/src/catalog-health.js +257 -0
  5. package/dist/reports/src/test-catalog.d.ts +8 -0
  6. package/dist/reports/src/test-catalog.js +5 -1
  7. package/dist/schema/src/api.d.ts +79 -0
  8. package/dist/schema/src/api.js +50 -0
  9. package/dist/server/src/app.js +9 -0
  10. package/dist/server/src/llms.js +1 -0
  11. package/dist/server/src/openapi.js +18 -2
  12. package/dist/server/src/settings-page.d.ts +4 -4
  13. package/dist/server/src/settings-page.js +17 -78
  14. package/docs/reference/http-api.md +34 -0
  15. package/docs/reference/reports.md +224 -0
  16. package/docs/reference/schema.md +10 -0
  17. package/docs/reference/server.md +4 -4
  18. package/docs/server.md +10 -0
  19. package/docs/ui.md +142 -0
  20. package/docs/workspaces.md +130 -0
  21. package/llms-full.txt +322 -0
  22. package/llms.txt +2 -0
  23. package/package.json +17 -10
  24. package/packages/schema/schemas/catalog-health.schema.json +400 -0
  25. package/packages/server/openapi.json +596 -0
  26. package/packages/visualizer/src/admin/SettingsPage.tsx +456 -0
  27. package/packages/visualizer/src/admin/main.tsx +11 -0
  28. package/packages/visualizer/src/app/AppShell.tsx +62 -38
  29. package/packages/visualizer/src/app/gazetteer.tsx +90 -83
  30. package/packages/visualizer/src/app/router.tsx +33 -15
  31. package/packages/visualizer/src/components/ActivityIndicator.tsx +4 -5
  32. package/packages/visualizer/src/components/DataIssues.tsx +36 -54
  33. package/packages/visualizer/src/components/Header.tsx +197 -125
  34. package/packages/visualizer/src/components/Legend.tsx +13 -41
  35. package/packages/visualizer/src/components/ProjectPicker.tsx +61 -26
  36. package/packages/visualizer/src/components/Screen.tsx +80 -71
  37. package/packages/visualizer/src/components/SpecLogo.tsx +15 -0
  38. package/packages/visualizer/src/components/Status.tsx +20 -34
  39. package/packages/visualizer/src/components/labels.tsx +8 -3
  40. package/packages/visualizer/src/components/spec-logos/APACHE-2.0.txt +206 -0
  41. package/packages/visualizer/src/components/spec-logos/CAMUNDA-MIT.txt +21 -0
  42. package/packages/visualizer/src/components/spec-logos/FILE-ICONS-ISC.txt +13 -0
  43. package/packages/visualizer/src/components/spec-logos/README.md +23 -0
  44. package/packages/visualizer/src/components/spec-logos/SIMPLE-ICONS-CC0.txt +30 -0
  45. package/packages/visualizer/src/components/spec-logos/alloy.svg +1 -0
  46. package/packages/visualizer/src/components/spec-logos/dmn.svg +3 -0
  47. package/packages/visualizer/src/components/spec-logos/gherkin.svg +1 -0
  48. package/packages/visualizer/src/components/spec-logos/openslo.svg +63 -0
  49. package/packages/visualizer/src/components/spec-logos/quint.svg +1 -0
  50. package/packages/visualizer/src/evidence/artifacts.tsx +263 -110
  51. package/packages/visualizer/src/evidence/chart-source.tsx +18 -0
  52. package/packages/visualizer/src/evidence/check-detail.tsx +283 -139
  53. package/packages/visualizer/src/evidence/decision-table.tsx +35 -26
  54. package/packages/visualizer/src/evidence/document-page.tsx +51 -29
  55. package/packages/visualizer/src/evidence/feature-page.tsx +121 -53
  56. package/packages/visualizer/src/evidence/marks.tsx +112 -79
  57. package/packages/visualizer/src/evidence/model-page.tsx +77 -46
  58. package/packages/visualizer/src/evidence/model-trace.tsx +55 -35
  59. package/packages/visualizer/src/evidence/overview.tsx +137 -69
  60. package/packages/visualizer/src/evidence/recording-page.tsx +70 -31
  61. package/packages/visualizer/src/evidence/recording.tsx +135 -68
  62. package/packages/visualizer/src/evidence/snapshot.tsx +99 -43
  63. package/packages/visualizer/src/evidence/source-text.tsx +33 -0
  64. package/packages/visualizer/src/evidence/sources-panel.tsx +138 -144
  65. package/packages/visualizer/src/evidence/spec-header.tsx +52 -36
  66. package/packages/visualizer/src/evidence/spec-index.tsx +61 -32
  67. package/packages/visualizer/src/evidence/spec-page.tsx +56 -25
  68. package/packages/visualizer/src/evidence/test-filter.tsx +38 -14
  69. package/packages/visualizer/src/explorer/Explorer.tsx +688 -261
  70. package/packages/visualizer/src/explorer/ExplorerIndex.tsx +136 -68
  71. package/packages/visualizer/src/explorer/RunsView.tsx +307 -94
  72. package/packages/visualizer/src/explorer/TestDetail.tsx +393 -118
  73. package/packages/visualizer/src/explorer/parts.tsx +35 -13
  74. package/packages/visualizer/src/find/Finder.tsx +106 -90
  75. package/packages/visualizer/src/find/open.ts +17 -20
  76. package/packages/visualizer/src/live/test-progress.tsx +60 -22
  77. package/packages/visualizer/src/looks/Stage.tsx +223 -110
  78. package/packages/visualizer/src/main.tsx +9 -11
  79. package/packages/visualizer/src/map/ChartMap.tsx +125 -69
  80. package/packages/visualizer/src/map/EventEdge.tsx +59 -37
  81. package/packages/visualizer/src/map/map.module.css +12 -546
  82. package/packages/visualizer/src/map/nodes.tsx +124 -70
  83. package/packages/visualizer/src/reachable.test.ts +3 -2
  84. package/packages/visualizer/src/spec-kind.ts +2 -2
  85. package/packages/visualizer/src/ui/grammars/ALLOY-MIT.txt +21 -0
  86. package/packages/visualizer/src/ui/grammars/QUINT-APACHE-2.0.txt +206 -0
  87. package/packages/visualizer/src/ui/grammars/README.md +14 -0
  88. package/packages/visualizer/src/ui/grammars/alloy.json +71 -0
  89. package/packages/visualizer/src/ui/grammars/quint.json +152 -0
  90. package/packages/visualizer/src/ui/highlight.ts +50 -0
  91. package/packages/visualizer/src/ui/theme.tsx +109 -0
  92. package/packages/visualizer/src/views/ChartPage.tsx +46 -26
  93. package/packages/visualizer/src/views/ChartTests.tsx +59 -22
  94. package/packages/visualizer/src/views/ProductPage.tsx +16 -15
  95. package/packages/visualizer/src/views/SidePanel.tsx +241 -131
  96. package/packages/visualizer/src/app/gazetteer.module.css +0 -107
  97. package/packages/visualizer/src/components/ActivityIndicator.module.css +0 -4
  98. package/packages/visualizer/src/components/DataIssues.module.css +0 -136
  99. package/packages/visualizer/src/components/Header.module.css +0 -114
  100. package/packages/visualizer/src/components/Legend.module.css +0 -84
  101. package/packages/visualizer/src/components/Screen.module.css +0 -312
  102. package/packages/visualizer/src/components/Status.module.css +0 -116
  103. package/packages/visualizer/src/components/icons.tsx +0 -156
  104. package/packages/visualizer/src/evidence/artifacts.module.css +0 -213
  105. package/packages/visualizer/src/evidence/evidence.module.css +0 -907
  106. package/packages/visualizer/src/evidence/recording.module.css +0 -460
  107. package/packages/visualizer/src/evidence/sources.module.css +0 -168
  108. package/packages/visualizer/src/evidence/spec-snapshot.tsx +0 -26
  109. package/packages/visualizer/src/explorer/explorer.module.css +0 -1238
  110. package/packages/visualizer/src/find/Finder.module.css +0 -168
  111. package/packages/visualizer/src/looks/stage.module.css +0 -300
  112. package/packages/visualizer/src/styles/global.css +0 -105
  113. package/packages/visualizer/src/styles/tokens.css +0 -80
  114. package/packages/visualizer/src/views/views.module.css +0 -546
@@ -1,136 +0,0 @@
1
- .trigger {
2
- display: inline-flex;
3
- align-items: center;
4
- gap: 0.35rem;
5
- font-size: 0.78rem;
6
- color: var(--muted);
7
- background: transparent;
8
- border: 1px solid var(--line);
9
- border-radius: var(--pill);
10
- padding: 0.3rem 0.7rem;
11
- cursor: pointer;
12
- white-space: nowrap;
13
- }
14
-
15
- .trigger:hover {
16
- border-color: var(--line-2);
17
- color: var(--ink-2);
18
- }
19
-
20
- .trigger[data-has-problems='true'] {
21
- color: var(--system-ink);
22
- }
23
-
24
- .overlay {
25
- position: fixed;
26
- inset: 0;
27
- background: rgba(15, 23, 42, 0.18);
28
- z-index: 60;
29
- }
30
-
31
- .sheet {
32
- position: fixed;
33
- top: 0;
34
- right: 0;
35
- bottom: 0;
36
- width: min(34rem, 100vw);
37
- background: var(--card);
38
- border-left: 1px solid var(--line);
39
- box-shadow: var(--shadow-pop);
40
- z-index: 61;
41
- display: flex;
42
- flex-direction: column;
43
- padding: 1.25rem 1.25rem 0;
44
- }
45
-
46
- .head {
47
- display: flex;
48
- justify-content: space-between;
49
- align-items: center;
50
- }
51
-
52
- .title {
53
- margin: 0;
54
- font-size: 1.15rem;
55
- }
56
-
57
- .close {
58
- border: 0;
59
- background: transparent;
60
- color: var(--muted);
61
- cursor: pointer;
62
- width: 2rem;
63
- height: 2rem;
64
- display: grid;
65
- place-items: center;
66
- border-radius: var(--pill);
67
- }
68
-
69
- .close:hover {
70
- background: var(--bg-2);
71
- }
72
-
73
- .lead {
74
- margin: 0.4rem 0 1rem;
75
- color: var(--ink-3);
76
- font-size: 0.9rem;
77
- }
78
-
79
- .list {
80
- overflow-y: auto;
81
- padding-bottom: 2rem;
82
- display: flex;
83
- flex-direction: column;
84
- gap: 1rem;
85
- }
86
-
87
- .fileName {
88
- margin: 0 0 0.4rem;
89
- font-family: var(--mono);
90
- font-size: 0.78rem;
91
- font-weight: 600;
92
- color: var(--ink-2);
93
- word-break: break-all;
94
- }
95
-
96
- .items {
97
- list-style: none;
98
- margin: 0;
99
- padding: 0;
100
- display: flex;
101
- flex-direction: column;
102
- gap: 0.35rem;
103
- }
104
-
105
- .item {
106
- display: grid;
107
- grid-template-columns: 4.6rem 1fr;
108
- gap: 0.6rem;
109
- font-size: 0.85rem;
110
- color: var(--ink-2);
111
- background: var(--bg);
112
- border-radius: var(--radius-sm);
113
- padding: 0.5rem 0.65rem;
114
- }
115
-
116
- .severity {
117
- font-size: 0.7rem;
118
- font-weight: 700;
119
- text-transform: uppercase;
120
- letter-spacing: 0.04em;
121
- color: var(--muted);
122
- padding-top: 0.1rem;
123
- }
124
-
125
- .item[data-severity='error'] .severity {
126
- color: var(--failed-ink);
127
- }
128
-
129
- .item[data-severity='warning'] .severity {
130
- color: var(--system-ink);
131
- }
132
-
133
- .path {
134
- font-weight: 600;
135
- color: var(--ink);
136
- }
@@ -1,114 +0,0 @@
1
- .header {
2
- position: relative;
3
- z-index: 20;
4
- display: grid;
5
- grid-template-columns: auto minmax(0, 1fr) auto;
6
- align-items: center;
7
- gap: 16px;
8
- min-height: 54px;
9
- padding: 8px 16px;
10
- border-bottom: 1px solid var(--line);
11
- background: var(--bg);
12
- }
13
- .home {
14
- color: var(--ink);
15
- font-size: 15px;
16
- font-weight: 700;
17
- text-decoration: none;
18
- }
19
- .breadcrumbs, .tools { display: flex; align-items: center; min-width: 0; gap: 6px; }
20
- .breadcrumbs { color: var(--faint); }
21
- .tools { justify-content: flex-end; }
22
- .picker { position: relative; display: inline-flex; min-width: 0; max-width: 100%; }
23
- .picker::after {
24
- position: absolute;
25
- right: 10px;
26
- top: 12px;
27
- width: 5px;
28
- height: 5px;
29
- border-right: 1.5px solid var(--ink-3);
30
- border-bottom: 1.5px solid var(--ink-3);
31
- transform: rotate(45deg);
32
- pointer-events: none;
33
- content: '';
34
- }
35
- .select, .search, .menu > summary, .sources {
36
- box-sizing: border-box;
37
- height: 32px;
38
- border: 1px solid transparent;
39
- border-radius: 6px;
40
- background: transparent;
41
- color: var(--ink);
42
- font: 500 13px var(--font);
43
- cursor: pointer;
44
- }
45
- .select {
46
- appearance: none;
47
- min-width: 0;
48
- max-width: min(24rem, 30vw);
49
- padding: 0 28px 0 10px;
50
- overflow: hidden;
51
- text-overflow: ellipsis;
52
- }
53
- .picker[data-project] .select { max-width: 200px; border-color: var(--line); }
54
- .select:disabled { color: var(--ink-3); cursor: default; }
55
- .select:hover:not(:disabled), .search:hover, .menu > summary:hover, .sources:hover { background: var(--bg-2); }
56
- .select:focus-visible, .search:focus-visible, .menu > summary:focus-visible, .sources:focus-visible, .tabs a:focus-visible {
57
- outline: 2px solid var(--place);
58
- outline-offset: 2px;
59
- }
60
- .search { display: inline-flex; align-items: center; justify-content: center; width: 32px; padding: 0; color: var(--ink-3); }
61
- .menu { position: relative; min-width: 0; }
62
- .menu > summary { display: flex; align-items: center; gap: 8px; padding: 0 10px; list-style: none; white-space: nowrap; }
63
- .menu > summary::-webkit-details-marker { display: none; }
64
- .menu[data-tools] > summary { width: 32px; justify-content: center; padding: 0; font-size: 16px; letter-spacing: 1px; }
65
- .menu[open] > summary { background: var(--bg-2); }
66
- .dropdown {
67
- position: absolute;
68
- z-index: 100;
69
- top: calc(100% + 8px);
70
- left: 0;
71
- min-width: 200px;
72
- max-width: min(320px, calc(100vw - 32px));
73
- padding: 6px;
74
- border: 1px solid var(--line);
75
- border-radius: 8px;
76
- background: var(--bg);
77
- box-shadow: 0 8px 24px #00000014;
78
- }
79
- .menu:not([open]) > .dropdown { display: none; }
80
- .menu[data-tools] .dropdown { left: auto; right: 0; width: 260px; }
81
- .tabs { display: flex; flex-direction: column; }
82
- .tabs a { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 10px; border-radius: 4px; color: var(--ink-3); font-size: 13px; text-decoration: none; }
83
- .tabs a:hover { background: var(--bg-2); color: var(--ink); }
84
- .tabs a[aria-current='page'] { background: var(--place-soft); color: var(--ink); font-weight: 600; }
85
- .failing { color: var(--failed-ink); font-size: 12px; }
86
- .options { display: flex; flex-direction: column; gap: 4px; }
87
- .optionGroup { display: flex; flex-direction: column; gap: 4px; padding: 6px 4px 10px; border-bottom: 1px solid var(--line); }
88
- .optionLabel { padding: 0 6px; color: var(--ink-3); font-size: 11px; }
89
- .optionGroup .picker, .optionGroup .select { width: 100%; max-width: 100%; }
90
- .optionGroup .select { border-color: var(--line); }
91
- .sources { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; padding: 0 10px; text-decoration: none; text-align: left; }
92
- .sources span { color: var(--ink-3); font-weight: 400; }
93
- .sources[data-filtered], .sources[data-filtered] span { color: var(--place); }
94
- .connection { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 32px; flex: none; }
95
- .connectionDot, .liveDot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--ink-3); flex: none; }
96
- .connection[data-status='live'] .connectionDot { background: var(--passed); }
97
- .connection[data-status='reconnecting'] .connectionDot { background: var(--failed-ink); }
98
- .live { display: flex; align-items: center; gap: 6px; padding: 6px 10px; color: var(--ink-3); font-size: 12px; }
99
- .liveDot { background: var(--place); }
100
- .notice { margin-top: 4px; padding: 8px 4px 0; border-top: 1px solid var(--line); color: var(--ink-3); font-size: 12px; line-height: 1.5; }
101
- .notice p { margin: 0 6px 6px; }
102
- @media (max-width: 700px) {
103
- .header { gap: 4px 10px; padding: 6px 12px; }
104
- .home { grid-column: 1; grid-row: 1; }
105
- .tools { grid-column: 2 / -1; grid-row: 1; }
106
- .breadcrumbs { grid-column: 1 / -1; grid-row: 2; }
107
- .breadcrumbs .picker { flex: 1; }
108
- .breadcrumbs .select { width: 100%; max-width: 100%; }
109
- .picker[data-project] .select { max-width: min(180px, 43vw); }
110
- .menu[data-tools] .dropdown { position: fixed; top: 44px; left: 12px; right: 12px; width: auto; max-width: none; }
111
- }
112
-
113
- .picker[data-running] .select { padding-left: 28px; }
114
- .pickerActivity { position: absolute; left: 9px; top: 10px; display: flex; pointer-events: none; }
@@ -1,84 +0,0 @@
1
- .legend {
2
- display: flex;
3
- gap: 0.75rem;
4
- flex-wrap: wrap;
5
- align-items: center;
6
- background: rgba(255, 255, 255, 0.94);
7
- padding: 0.5rem 0.8rem;
8
- border-radius: var(--radius);
9
- border: 1px solid var(--line);
10
- font-size: 0.78rem;
11
- color: var(--ink-2);
12
- box-shadow: var(--shadow-card);
13
- }
14
-
15
- .item {
16
- display: inline-flex;
17
- align-items: center;
18
- gap: 0.35rem;
19
- white-space: nowrap;
20
- }
21
-
22
- .sep {
23
- width: 1px;
24
- height: 1rem;
25
- background: var(--line);
26
- }
27
-
28
- .chip {
29
- display: inline-grid;
30
- place-items: center;
31
- width: 1.6rem;
32
- height: 1.1rem;
33
- border-radius: var(--pill);
34
- border: 1.5px solid;
35
- }
36
-
37
- .chip[data-kind='user'] {
38
- background: var(--user-soft);
39
- color: var(--user);
40
- border-color: var(--user-line);
41
- }
42
-
43
- .chip[data-kind='system'] {
44
- background: var(--system-soft);
45
- color: var(--system);
46
- border-color: var(--system-line);
47
- }
48
-
49
- .chip[data-kind='time'] {
50
- background: var(--time-soft);
51
- color: var(--time);
52
- border-color: var(--time-line);
53
- }
54
-
55
- .chip[data-kind='none'] {
56
- background: var(--bg);
57
- border-color: var(--line-2);
58
- border-style: dashed;
59
- }
60
-
61
- .frame {
62
- width: 0.8rem;
63
- height: 1.1rem;
64
- border-radius: 0.2rem;
65
- border: 2px solid var(--line);
66
- background: var(--card);
67
- }
68
-
69
- .frame[data-status='passed'] {
70
- border-color: var(--passed-line);
71
- }
72
-
73
- .frame[data-status='flaky'] {
74
- border-color: var(--flaky);
75
- }
76
-
77
- .frame[data-status='failed'] {
78
- border-color: var(--failed);
79
- }
80
-
81
- .frame[data-status='none'] {
82
- border-style: dashed;
83
- border-color: var(--faint);
84
- }
@@ -1,312 +0,0 @@
1
- .phone {
2
- position: relative;
3
- width: 100%;
4
- aspect-ratio: 390 / 844;
5
- border-radius: 0.65rem;
6
- overflow: hidden;
7
- background: var(--bg-2);
8
- display: block;
9
- }
10
-
11
- .phone[data-size='full'] {
12
- border-radius: 1.4rem;
13
- border: 1px solid var(--line);
14
- box-shadow: var(--shadow-raised);
15
- }
16
-
17
- .phone[data-variant='sketch'] {
18
- background:
19
- radial-gradient(circle at 1px 1px, rgba(28, 36, 48, 0.08) 1px, transparent 0) 0 0 / 10px 10px,
20
- linear-gradient(180deg, #f7fafb 0%, var(--bg) 100%);
21
- border: 1px dashed var(--line-2);
22
- }
23
-
24
- .phone[data-size='full'][data-variant='sketch'] {
25
- border-width: 1px;
26
- }
27
-
28
- .notch {
29
- position: absolute;
30
- top: 5px;
31
- left: 50%;
32
- width: 34%;
33
- height: 7px;
34
- transform: translateX(-50%);
35
- border-radius: var(--pill);
36
- background: rgba(28, 36, 48, 0.1);
37
- }
38
-
39
- .phone[data-size='full'] .notch {
40
- top: 12px;
41
- height: 16px;
42
- width: 30%;
43
- }
44
-
45
- .sketch {
46
- position: absolute;
47
- inset: 18px 8px 10px;
48
- display: flex;
49
- flex-direction: column;
50
- gap: 5px;
51
- text-align: left;
52
- overflow: hidden;
53
- }
54
-
55
- .phone[data-size='full'] .sketch {
56
- inset: 44px 22px 22px;
57
- gap: 12px;
58
- }
59
-
60
- .reason {
61
- align-self: flex-start;
62
- font-size: 7.5px;
63
- font-weight: 400;
64
- padding: 2px 6px;
65
- border-radius: var(--pill);
66
- background: var(--bg);
67
- color: var(--ink-3);
68
- border: 1px solid var(--line);
69
- }
70
-
71
- .reason[data-reason='not-reached'] {
72
- color: var(--muted);
73
- border-style: dashed;
74
- border-color: var(--line-2);
75
- }
76
-
77
- .reason[data-reason='processing'] {
78
- color: var(--time-ink);
79
- border-color: var(--time-line);
80
- }
81
-
82
- .phone[data-size='full'] .reason {
83
- font-size: 0.7rem;
84
- padding: 0.2rem 0.6rem;
85
- }
86
-
87
- .title {
88
- font-size: 11px;
89
- font-weight: 700;
90
- line-height: 1.2;
91
- color: var(--ink);
92
- }
93
-
94
- .phone[data-size='full'] .title {
95
- font-size: 1.15rem;
96
- }
97
-
98
- .missing {
99
- font-size: 8px;
100
- color: var(--ink-3);
101
- }
102
-
103
- .phone[data-size='full'] .missing {
104
- font-size: 0.85rem;
105
- }
106
-
107
- .description {
108
- font-size: 8px;
109
- line-height: 1.35;
110
- color: var(--ink-3);
111
- display: -webkit-box;
112
- -webkit-line-clamp: 6;
113
- -webkit-box-orient: vertical;
114
- overflow: hidden;
115
- }
116
-
117
- .phone[data-size='full'] .description {
118
- font-size: 0.85rem;
119
- -webkit-line-clamp: 8;
120
- }
121
-
122
- .lines {
123
- display: flex;
124
- flex-direction: column;
125
- gap: 4px;
126
- margin-top: 2px;
127
- }
128
-
129
- .line {
130
- display: grid;
131
- grid-template-columns: 8px 1fr;
132
- gap: 4px;
133
- align-items: start;
134
- font-size: 7px;
135
- line-height: 1.3;
136
- color: var(--muted);
137
- background: rgba(255, 255, 255, 0.75);
138
- border-radius: 4px;
139
- padding: 3px 4px;
140
- }
141
-
142
- .line > span:last-child {
143
- display: -webkit-box;
144
- -webkit-line-clamp: 2;
145
- -webkit-box-orient: vertical;
146
- overflow: hidden;
147
- }
148
-
149
- .phone[data-size='full'] .line {
150
- font-size: 0.75rem;
151
- grid-template-columns: 0.75rem 1fr;
152
- padding: 0.4rem 0.55rem;
153
- gap: 0.45rem;
154
- }
155
-
156
- .tick {
157
- margin-top: 2px;
158
- width: 6px;
159
- height: 6px;
160
- border-radius: 2px;
161
- border: 1.2px solid var(--user-line);
162
- }
163
-
164
- .phone[data-size='full'] .tick {
165
- width: 0.7rem;
166
- height: 0.7rem;
167
- }
168
-
169
- .bars {
170
- margin-top: auto;
171
- display: flex;
172
- flex-direction: column;
173
- gap: 4px;
174
- }
175
-
176
- .barWide,
177
- .barNarrow,
178
- .button {
179
- display: block;
180
- height: 5px;
181
- border-radius: var(--pill);
182
- background: rgba(28, 36, 48, 0.08);
183
- }
184
-
185
- .barNarrow {
186
- width: 62%;
187
- }
188
-
189
- .card {
190
- display: block;
191
- height: 46px;
192
- border-radius: 6px;
193
- margin-bottom: 4px;
194
- background: rgba(255, 255, 255, 0.8);
195
- border: 1px solid var(--line);
196
- }
197
-
198
- .phone[data-size='full'] .card {
199
- height: 7rem;
200
- border-radius: 0.8rem;
201
- }
202
-
203
- .button {
204
- height: 12px;
205
- margin-top: 4px;
206
- background: rgba(28, 36, 48, 0.12);
207
- }
208
-
209
- .phone[data-size='full'] .barWide,
210
- .phone[data-size='full'] .barNarrow {
211
- height: 10px;
212
- }
213
-
214
- .phone[data-size='full'] .button {
215
- height: 2.4rem;
216
- }
217
-
218
- .design {
219
- width: 100%;
220
- height: 100%;
221
- object-fit: cover;
222
- display: block;
223
- }
224
-
225
- .designTag {
226
- position: absolute;
227
- left: 6px;
228
- right: 6px;
229
- bottom: 6px;
230
- text-align: center;
231
- font-size: 8px;
232
- font-weight: 400;
233
- padding: 3px 4px;
234
- border-radius: var(--pill);
235
- color: var(--ink-2);
236
- background: rgba(255, 255, 255, 0.94);
237
- border: 1px solid var(--line);
238
- }
239
-
240
- .phone[data-size='full'] .designTag {
241
- font-size: 0.75rem;
242
- bottom: 14px;
243
- left: 14px;
244
- right: 14px;
245
- }
246
-
247
- .underlay {
248
- position: absolute;
249
- inset: 0;
250
- }
251
-
252
- .underlay > .phone {
253
- height: 100%;
254
- }
255
-
256
- .skeleton {
257
- position: absolute;
258
- inset: 0;
259
- background: linear-gradient(100deg, var(--bg-2) 30%, #e9eef5 50%, var(--bg-2) 70%) 0 0 / 300% 100%;
260
- animation: shimmer 1.4s linear infinite;
261
- }
262
-
263
- @keyframes shimmer {
264
- to {
265
- background-position: -150% 0;
266
- }
267
- }
268
-
269
- .img {
270
- position: absolute;
271
- inset: 0;
272
- width: 100%;
273
- height: 100%;
274
- object-fit: cover;
275
- object-position: top;
276
- display: block;
277
- opacity: 0;
278
- transition: opacity var(--fade) var(--ease);
279
- }
280
-
281
- .phone[data-state='loaded'] .img {
282
- opacity: 1;
283
- }
284
-
285
- .failed {
286
- position: absolute;
287
- inset: 0;
288
- display: flex;
289
- flex-direction: column;
290
- align-items: center;
291
- justify-content: center;
292
- gap: 6px;
293
- padding: 8px;
294
- text-align: center;
295
- font-size: 8.5px;
296
- color: var(--muted);
297
- background: var(--bg);
298
- }
299
-
300
- .phone[data-size='full'] .failed {
301
- font-size: 0.85rem;
302
- }
303
-
304
- .retry {
305
- font-size: inherit;
306
- border: 1px solid var(--line);
307
- background: var(--card);
308
- color: var(--user);
309
- border-radius: var(--pill);
310
- padding: 2px 8px;
311
- cursor: pointer;
312
- }