glasscn-core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,220 @@
1
+ /* ============================================================================
2
+ * glasscn-core — 降级与无障碍 (Fallback & A11y)
3
+ * ----------------------------------------------------------------------------
4
+ * 玻璃拟态的失败模式很危险:backdrop-filter 一旦不生效,
5
+ * rgba(255,255,255,0.08) 的面板就变成"几乎看不见的框",
6
+ * 文字直接压在动画光斑上——不可读。
7
+ * 所以降级不是锦上添花,是这套库能不能上生产的分界线。
8
+ *
9
+ * 降级方向和亮色主题相反:这里要退到**接近不透明的暗色**,
10
+ * 不是白色。白色 0.94 压在近黑底上会变成一块刺眼的白板。
11
+ *
12
+ * 关于这一整层的 !important —— 不是偷懒,是必须的:
13
+ * 调色用 :root[data-glass-palette="x"](0,2,0)声明变量,
14
+ * 会稳压这里的 :root(0,1,0)。不加的话用户一旦切换调色,
15
+ * 整层无障碍降级就被静默压掉——自动化测不出来,只有真实用户会踩到。
16
+ * ==========================================================================*/
17
+
18
+ /* 降级用的实底。跟着调色走,浅色调色里会被覆写成浅底。 */
19
+ :root {
20
+ --glass-solid: 20 16 12;
21
+ }
22
+
23
+ :root[data-glass-palette="ocean-frost"] { --glass-solid: 6 16 30; }
24
+ :root[data-glass-palette="soft-bloom"] { --glass-solid: 28 16 32; }
25
+ :root[data-glass-palette="warm-sunset"] { --glass-solid: 30 14 12; }
26
+ :root[data-glass-palette="emerald-mist"] { --glass-solid: 8 28 16; }
27
+ :root[data-glass-palette="liquid-light"] { --glass-solid: 244 240 233; }
28
+
29
+ /* --- 1. 浏览器不支持 backdrop-filter ------------------------------------- */
30
+
31
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
32
+ .glass-surface,
33
+ .glass-nav,
34
+ .glass-menu,
35
+ [data-slot] {
36
+ background-color: rgb(var(--glass-solid) / 0.9) !important;
37
+ }
38
+ }
39
+
40
+ /* --- 2. 用户要求减少透明度 ------------------------------------------------- */
41
+ /* macOS「减弱透明度」/ Windows 关闭「透明效果」时命中。
42
+ 这是明确的用户意图,优先级高于设计意图。 */
43
+
44
+ @media (prefers-reduced-transparency: reduce) {
45
+ :root {
46
+ --glass-blur-base: 0px !important;
47
+ --glass-saturate: 100% !important;
48
+ --glass-shimmer-alpha: 0 !important;
49
+ }
50
+
51
+ .glass-surface,
52
+ .glass-nav,
53
+ .glass-menu,
54
+ [data-slot] {
55
+ background-color: rgb(var(--glass-solid) / 0.94) !important;
56
+ -webkit-backdrop-filter: none !important;
57
+ backdrop-filter: none !important;
58
+ }
59
+
60
+ /* 光斑保留但压暗:完全去掉会让界面变成一块死板,
61
+ 用户要的是"别透",不是"别有颜色"。 */
62
+ .glass-backdrop::before,
63
+ .glass-backdrop::after,
64
+ .glass-blob-accent::before {
65
+ opacity: 0.22 !important;
66
+ }
67
+ }
68
+
69
+ /* --- 3. 增强对比度 --------------------------------------------------------- */
70
+
71
+ @media (prefers-contrast: more) {
72
+ :root {
73
+ --glass-border-alpha: 0.55 !important;
74
+ --glass-border-alpha-hover: 0.85 !important;
75
+ --glass-border-width: 1.5px !important;
76
+ --glass-shimmer-alpha: 0 !important;
77
+ --glass-text-secondary: rgb(var(--glass-text-rgb) / 0.92) !important;
78
+ --glass-text-muted: rgb(var(--glass-text-rgb) / 0.72) !important;
79
+ }
80
+
81
+ .glass-surface,
82
+ .glass-nav,
83
+ .glass-menu,
84
+ [data-slot] {
85
+ background-color: rgb(var(--glass-solid) / 0.96) !important;
86
+ }
87
+ }
88
+
89
+ /* --- 4. 减少动效 ----------------------------------------------------------- */
90
+ /* 技能要求的兜底:所有动画与过渡压到近零,揭示元素立即可见。
91
+ 浮层物化的位移/缩放在此一并归零 -- 减少动效不是没有反馈,
92
+ 面板仍然淡入淡出(opacity 是前庭安全的),只是不再移动。 */
93
+
94
+ @media (prefers-reduced-motion: reduce) {
95
+ /* 注意只能对锚定浮层整体归零。居中 modal 的 translate(-50%,-50%)
96
+ 同时承担着定位(shadcn 的 Dialog 靠它居中),整条 transform: none
97
+ 会让面板跳去左上角。对它们只关位移和缩放,保留居中。 */
98
+ [data-slot="popover-content"],
99
+ [data-slot="hover-card-content"],
100
+ [data-slot="dropdown-menu-content"],
101
+ [data-slot="dropdown-menu-sub-content"],
102
+ [data-slot="context-menu-content"],
103
+ [data-slot="menubar-content"],
104
+ [data-slot="select-content"],
105
+ [data-slot="tooltip-content"],
106
+ [data-slot="sheet-content"],
107
+ [data-slot="drawer-content"] {
108
+ transform: none !important;
109
+ }
110
+
111
+ [data-slot="dialog-content"],
112
+ [data-slot="command"] {
113
+ transform: translate(-50%, -50%) !important;
114
+ }
115
+
116
+ :root {
117
+ --glass-duration-fast: 0.01ms !important;
118
+ --glass-duration: 0.01ms !important;
119
+ --glass-duration-slow: 0.01ms !important;
120
+ --glass-duration-color: 0.01ms !important;
121
+ --glass-duration-enter: 0.01ms !important;
122
+ --glass-duration-exit: 0.01ms !important;
123
+ --glass-shimmer-duration: 0.01ms !important;
124
+ --glass-lift: 0px !important;
125
+ --glass-press: 0px !important;
126
+ --glass-press-scale: 1 !important;
127
+ }
128
+
129
+ *,
130
+ *::before,
131
+ *::after {
132
+ animation-duration: 0.01ms !important;
133
+ animation-iteration-count: 1 !important;
134
+ transition-duration: 0.01ms !important;
135
+ }
136
+
137
+ .glass-reveal,
138
+ .glass-reveal:not(.is-revealed) {
139
+ opacity: 1 !important;
140
+ transform: none !important;
141
+ filter: none !important;
142
+ animation: none !important;
143
+ }
144
+ }
145
+
146
+ /* --- 5. 打印 --------------------------------------------------------------- */
147
+
148
+ @media print {
149
+ :root {
150
+ --glass-blur-base: 0px !important;
151
+ --glass-text-rgb: 20 16 12 !important;
152
+ }
153
+
154
+ /* 滚动揭示在打印时必须强制可见。
155
+ 打印不产生滚动,scroll-driven 动画的时间轴永远停在起点,
156
+ 整页内容会以 opacity: 0 印出来 —— 一张白纸。
157
+ 同样的坑:打印预览、无头截图服务、部分爬虫。 */
158
+ .glass-reveal,
159
+ .glass-reveal:not(.is-revealed) {
160
+ opacity: 1 !important;
161
+ transform: none !important;
162
+ filter: none !important;
163
+ animation: none !important;
164
+ }
165
+
166
+ .glass-backdrop::before,
167
+ .glass-backdrop::after,
168
+ .glass-blob-accent::before {
169
+ display: none !important;
170
+ }
171
+
172
+ .glass-surface,
173
+ .glass-nav,
174
+ .glass-menu,
175
+ [data-slot] {
176
+ background: #fff !important;
177
+ border-color: #999 !important;
178
+ box-shadow: none !important;
179
+ -webkit-backdrop-filter: none !important;
180
+ backdrop-filter: none !important;
181
+ }
182
+ }
183
+
184
+ /* --- 6. 性能逃生阀 --------------------------------------------------------- */
185
+ /* backdrop-filter 是逐帧重绘的合成层。长列表 / 低端安卓 / 虚拟滚动里
186
+ 很容易掉帧。任意祖先挂 data-glass-perf="lite"(可由 useGlassPerf 自动挂),
187
+ 整棵子树退回纯色,布局完全不变。 */
188
+
189
+ [data-glass-perf="lite"] {
190
+ --glass-blur-base: 0px;
191
+ --glass-saturate: 100%;
192
+
193
+ & .glass-surface,
194
+ & .glass-nav,
195
+ & .glass-menu,
196
+ & [data-slot] {
197
+ background-color: rgb(var(--glass-solid) / 0.92) !important;
198
+ -webkit-backdrop-filter: none !important;
199
+ backdrop-filter: none !important;
200
+ }
201
+
202
+ /* 光斑的 blur(90px) 同样昂贵,一并降级 */
203
+ & .glass-backdrop::before,
204
+ & .glass-backdrop::after,
205
+ & .glass-blob-accent::before {
206
+ animation: none !important;
207
+ filter: blur(40px) !important;
208
+ }
209
+ }
210
+
211
+ /* --- 7. 文字可读性护栏 ------------------------------------------------------ */
212
+ /* 光斑最亮处压着的正文会被洗掉。极轻的文字阴影成本远低于再加一层遮罩。 */
213
+
214
+ @utility glass-legible {
215
+ text-shadow: 0 1px 3px rgb(0 0 0 / 0.45);
216
+
217
+ @media (prefers-contrast: more) {
218
+ text-shadow: none;
219
+ }
220
+ }
@@ -0,0 +1,159 @@
1
+ /* ============================================================================
2
+ * glasscn-core — 交互原语 (Interaction Primitives)
3
+ * ----------------------------------------------------------------------------
4
+ * 规范定的手感:
5
+ * hover translateY(-4px) + 投影变深 + 微光斜扫过表面
6
+ * active translateY(1px) scale(0.97),80ms 内完成 —— 要"啪"地一下
7
+ * focus 描边提亮到 0.30 + 外发光环 + 高光
8
+ *
9
+ * 只动 transform 和 opacity。绝不动 backdrop-filter、尺寸或布局属性 ——
10
+ * 那些每帧都要重新光栅化,一动就掉帧。
11
+ *
12
+ * 缓动纪律(对齐 Apple「流体界面」的阻尼比 + 响应):
13
+ * 位移 / 投影 阻尼 1.0,240ms -- 悬停不是被甩出去的,不过冲
14
+ * 颜色反馈 150ms,快一拍 -- 状态确认不需要仪式感
15
+ * 按压 80ms -- 要"啪"地一下
16
+ * 过冲曲线(--glass-ease-spring)只保留给带动量的交互:开关拨杆、倾斜回弹。
17
+ * ==========================================================================*/
18
+
19
+ @utility glass-interactive {
20
+ transition-property: transform, box-shadow, background-color, border-color;
21
+ transition-duration:
22
+ var(--glass-duration),
23
+ var(--glass-duration),
24
+ var(--glass-duration-color),
25
+ var(--glass-duration-color);
26
+ transition-timing-function:
27
+ var(--glass-ease),
28
+ var(--glass-ease),
29
+ var(--glass-ease-out),
30
+ var(--glass-ease-out);
31
+ will-change: transform;
32
+
33
+ &:hover:not(:disabled, [data-disabled], [aria-disabled="true"]) {
34
+ transform: translateY(calc(var(--glass-lift) * -1));
35
+ background-color: rgb(var(--glass-white) / var(--glass-fill-hover));
36
+ border-color: var(--glass-border-hover);
37
+ box-shadow:
38
+ var(--glass-specular-size) var(--glass-specular-color) inset,
39
+ var(--glass-shadow-hover);
40
+ }
41
+
42
+ &:active:not(:disabled, [data-disabled], [aria-disabled="true"]) {
43
+ transform: translateY(var(--glass-press)) scale(var(--glass-press-scale));
44
+ transition-duration: var(--glass-duration-fast);
45
+ }
46
+
47
+ &:disabled,
48
+ &[data-disabled],
49
+ &[aria-disabled="true"] {
50
+ opacity: 0.45;
51
+ cursor: not-allowed;
52
+ box-shadow: var(--glass-specular-size) var(--glass-specular-color) inset;
53
+ }
54
+ }
55
+
56
+ /* --- 微光扫过 (shimmer sweep) --------------------------------------------- */
57
+ /* hover 时一道斜向白光扫过表面。这是"玻璃在光下被转动"的感觉,
58
+ 也是这套设计里最有辨识度的一处动效。
59
+ 用 ::after + overflow 裁切,不占 ::before(那个留给 premium 渐变边)。 */
60
+
61
+ @keyframes glass-shimmer-sweep {
62
+ from {
63
+ transform: translateX(-130%) skewX(var(--glass-shimmer-angle));
64
+ }
65
+ to {
66
+ transform: translateX(230%) skewX(var(--glass-shimmer-angle));
67
+ }
68
+ }
69
+
70
+ @utility glass-shimmer {
71
+ position: relative;
72
+ overflow: hidden;
73
+
74
+ &::after {
75
+ content: "";
76
+ position: absolute;
77
+ top: 0;
78
+ bottom: 0;
79
+ left: 0;
80
+ width: 45%;
81
+ z-index: 2;
82
+ pointer-events: none;
83
+ opacity: 0;
84
+ background: linear-gradient(
85
+ 90deg,
86
+ transparent 0%,
87
+ rgb(var(--glass-white) / var(--glass-shimmer-alpha)) 50%,
88
+ transparent 100%
89
+ );
90
+ transform: translateX(-130%) skewX(var(--glass-shimmer-angle));
91
+ }
92
+
93
+ &:hover::after {
94
+ opacity: 1;
95
+ animation: glass-shimmer-sweep var(--glass-shimmer-duration)
96
+ var(--glass-ease-out);
97
+ }
98
+ }
99
+
100
+ /* --- 聚焦环 --------------------------------------------------------------- */
101
+ /* 背景是不可预测的光斑,单层 outline 经常和背景撞色。
102
+ 三层:贴合棱边的亮线 + 强调色细环 + 扩散辉光。 */
103
+
104
+ @utility glass-ring {
105
+ &:focus-visible {
106
+ outline: none;
107
+ border-color: rgb(var(--glass-white) / 0.3);
108
+ box-shadow:
109
+ var(--glass-specular-size) var(--glass-specular-color) inset,
110
+ 0 0 0 1px rgb(var(--glass-white) / 0.3),
111
+ 0 0 0 4px color-mix(in oklab, var(--glass-accent) 35%, transparent),
112
+ var(--glass-shadow);
113
+ }
114
+ }
115
+
116
+ /* --- 列表项高亮 ------------------------------------------------------------ */
117
+ /* 菜单项、选项、命令项。不做位移也不做模糊 —— 一个列表里几十项,
118
+ 每项都起合成层会直接掉帧。只换填充。 */
119
+
120
+ @utility glass-highlight {
121
+ transition: background-color var(--glass-duration-fast) var(--glass-ease-out),
122
+ color var(--glass-duration-fast) var(--glass-ease-out);
123
+
124
+ &[data-highlighted],
125
+ &[data-state="checked"],
126
+ &:hover:not([data-disabled]) {
127
+ background-color: rgb(var(--glass-white) / 0.1);
128
+ }
129
+ }
130
+
131
+ /* --- 实心 CTA -------------------------------------------------------------- */
132
+ /* 规范明确:主操作是实心强调色,不是玻璃。
133
+ 主按钮做成玻璃会丢失可供性 —— 一屏全是半透明面板时,用户找不到"该点哪个"。 */
134
+
135
+ @utility glass-cta {
136
+ background-color: var(--glass-accent);
137
+ color: var(--glass-accent-fg);
138
+ border: var(--glass-border-width) solid transparent;
139
+ border-radius: var(--glass-radius-pill);
140
+ box-shadow:
141
+ 0 1px 0 0 rgb(var(--glass-white) / 0.25) inset,
142
+ 0 8px 24px -8px color-mix(in oklab, var(--glass-accent) 60%, transparent);
143
+ transition-property: transform, filter, box-shadow;
144
+ transition-duration: var(--glass-duration), var(--glass-duration-color), var(--glass-duration);
145
+ transition-timing-function: var(--glass-ease), var(--glass-ease-out), var(--glass-ease);
146
+
147
+ &:hover:not(:disabled, [aria-disabled="true"]) {
148
+ transform: translateY(-2px);
149
+ filter: brightness(1.1);
150
+ box-shadow:
151
+ 0 1px 0 0 rgb(var(--glass-white) / 0.3) inset,
152
+ 0 14px 32px -10px color-mix(in oklab, var(--glass-accent) 70%, transparent);
153
+ }
154
+
155
+ &:active:not(:disabled, [aria-disabled="true"]) {
156
+ transform: translateY(1px) scale(var(--glass-press-scale));
157
+ transition-duration: var(--glass-duration-fast);
158
+ }
159
+ }
@@ -0,0 +1,168 @@
1
+ /* ============================================================================
2
+ * glasscn-core — 揭示与加载态 (Reveal & Loading)
3
+ * ----------------------------------------------------------------------------
4
+ * 滚动揭示:卡片从下方 24px 处带着 8px 模糊浮入。
5
+ * 模糊一起动是关键 —— 单纯的位移淡入看着像贴纸滑进来,
6
+ * 带模糊才像"一块玻璃从景深里推到眼前"。
7
+ *
8
+ * 两种驱动方式:
9
+ * 1. 纯 CSS —— animation-timeline: view(),新浏览器原生支持,零 JS
10
+ * 2. JS —— IntersectionObserver 加 .is-revealed 类,
11
+ * 走 registry 的 use-glass-reveal hook,兼容老浏览器
12
+ * 两者共用同一套视觉,先声明纯 CSS,JS 那条作为渐进增强。
13
+ * ==========================================================================*/
14
+
15
+ @utility glass-reveal {
16
+ opacity: 0;
17
+ transform: translateY(24px);
18
+ filter: blur(8px);
19
+ transition:
20
+ opacity var(--glass-duration-slow) var(--glass-ease),
21
+ transform var(--glass-duration-slow) var(--glass-ease),
22
+ filter calc(var(--glass-duration-slow) * 0.85) var(--glass-ease-out);
23
+
24
+ /* JS 驱动 */
25
+ &.is-revealed {
26
+ opacity: 1;
27
+ transform: none;
28
+ filter: none;
29
+ }
30
+ }
31
+
32
+ /* 纯 CSS 驱动:支持滚动驱动动画的浏览器直接接管,不需要 JS。
33
+ 放在 @supports 里,不支持的浏览器落到上面的 JS 路径。 */
34
+ @supports (animation-timeline: view()) {
35
+ @keyframes glass-reveal-in {
36
+ from {
37
+ opacity: 0;
38
+ transform: translateY(24px);
39
+ filter: blur(8px);
40
+ }
41
+ to {
42
+ opacity: 1;
43
+ transform: none;
44
+ filter: none;
45
+ }
46
+ }
47
+
48
+ .glass-reveal:not(.is-revealed) {
49
+ opacity: 1;
50
+ transform: none;
51
+ filter: none;
52
+ animation: glass-reveal-in linear both;
53
+ animation-timeline: view();
54
+ animation-range: entry 5% cover 22%;
55
+ }
56
+ }
57
+
58
+ /* 同级错峰:一排卡片依次浮入,而不是齐刷刷一起动 */
59
+ @utility glass-reveal-stagger {
60
+ & > * {
61
+ transition-delay: 0ms;
62
+ }
63
+ & > *:nth-child(2) { transition-delay: 80ms; }
64
+ & > *:nth-child(3) { transition-delay: 160ms; }
65
+ & > *:nth-child(4) { transition-delay: 240ms; }
66
+ & > *:nth-child(5) { transition-delay: 320ms; }
67
+ & > *:nth-child(n + 6) { transition-delay: 400ms; }
68
+ }
69
+
70
+ /* --- 浮层物化 keyframes ---------------------------------------------------- */
71
+ /* 给 bridge/auto.css 用。设计原则见 auto.css 里的注释块;
72
+ 定义放这里是因为 registry 的 css 字段按文件收集 @keyframes,
73
+ 集中放一处,生成器不会漏。 */
74
+
75
+ /* 遮罩:纯淡入淡出 -- 它是氛围不是面板 */
76
+ @keyframes glass-fade-in {
77
+ from { opacity: 0; }
78
+ }
79
+ @keyframes glass-fade-out {
80
+ to { opacity: 0; }
81
+ }
82
+
83
+ /* 居中 modal:scale 0.96->1,位移只动 2%(y 轴微抬)。
84
+ 基准 translate(-50%,-50%) 是 shadcn Dialog 的居中手段,必须带上。 */
85
+ @keyframes glass-modal-in {
86
+ from { opacity: 0; transform: translate(-50%, -52%) scale(0.96); }
87
+ }
88
+ @keyframes glass-modal-out {
89
+ to { opacity: 0; transform: translate(-50%, -52%) scale(0.96); }
90
+ }
91
+
92
+ /* 锚定浮层:从触发方向 4px + scale 0.98 物化。
93
+ transform-origin 由 Radix 的 --radix-*-transform-origin 给出,
94
+ 面板从触发按钮那一侧长出来。 */
95
+ @keyframes glass-pop-in {
96
+ from { opacity: 0; transform: translateY(4px) scale(0.98); }
97
+ }
98
+ @keyframes glass-pop-out {
99
+ to { opacity: 0; transform: translateY(4px) scale(0.98); }
100
+ }
101
+
102
+ /* tooltip:更快更轻 */
103
+ @keyframes glass-tip-in {
104
+ from { opacity: 0; transform: translateY(2px) scale(0.97); }
105
+ }
106
+ @keyframes glass-tip-out {
107
+ to { opacity: 0; transform: translateY(2px) scale(0.97); }
108
+ }
109
+
110
+ /* Sheet / Drawer:沿各自方向滑入,对称滑出(从哪来回哪去)。
111
+ 16px 起步 -- 比 modal 的 scale 更"整块",抽屉是刚性平移不是膨胀。 */
112
+ @keyframes glass-sheet-in-bottom {
113
+ from { opacity: 0; transform: translateY(16px); }
114
+ }
115
+ @keyframes glass-sheet-out-bottom {
116
+ to { opacity: 0; transform: translateY(16px); }
117
+ }
118
+ @keyframes glass-sheet-in-top {
119
+ from { opacity: 0; transform: translateY(-16px); }
120
+ }
121
+ @keyframes glass-sheet-out-top {
122
+ to { opacity: 0; transform: translateY(-16px); }
123
+ }
124
+ @keyframes glass-sheet-in-left {
125
+ from { opacity: 0; transform: translateX(-16px); }
126
+ }
127
+ @keyframes glass-sheet-out-left {
128
+ to { opacity: 0; transform: translateX(-16px); }
129
+ }
130
+ @keyframes glass-sheet-in-right {
131
+ from { opacity: 0; transform: translateX(16px); }
132
+ }
133
+ @keyframes glass-sheet-out-right {
134
+ to { opacity: 0; transform: translateX(16px); }
135
+ }
136
+
137
+ /* 手风琴:高度沿 grid-template-rows 0fr->1fr 展开。
138
+ 不支持 grid rows 插值的浏览器退成两帧 -- 仍然可见,无断裂。 */
139
+ @keyframes glass-accordion-in {
140
+ from { grid-template-rows: 0fr; opacity: 0.4; }
141
+ }
142
+ @keyframes glass-accordion-out {
143
+ to { grid-template-rows: 0fr; opacity: 0.4; }
144
+ }
145
+
146
+ /* --- 骨架屏 --------------------------------------------------------------- */
147
+ /* 异步加载期间保持玻璃质感。用 background-position 扫而不是 transform,
148
+ 这样不需要额外的裁切容器,也不会和 glass-shimmer 的 ::after 打架。 */
149
+
150
+ @keyframes glass-skeleton-sweep {
151
+ from { background-position: 200% 0; }
152
+ to { background-position: -200% 0; }
153
+ }
154
+
155
+ @utility glass-skeleton {
156
+ position: relative;
157
+ overflow: hidden;
158
+ border-radius: var(--glass-radius-md);
159
+ background-color: rgb(var(--glass-white) / var(--glass-fill-flat));
160
+ background-image: linear-gradient(
161
+ 100deg,
162
+ transparent 20%,
163
+ rgb(var(--glass-white) / 0.08) 50%,
164
+ transparent 80%
165
+ );
166
+ background-size: 200% 100%;
167
+ animation: glass-skeleton-sweep 1.8s linear infinite;
168
+ }