@kashi-ui/css 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kashi contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,27 @@
1
- # Temporary Holding Version
1
+ # @kashi-ui/css
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ استایل همهٔ کامپوننت‌های [کاشی](https://github.com/Sepantapouya/Kashi) با CSS خالص؛ برای React، Vue، Svelte، Angular یا HTML ساده.
4
+
5
+ ```bash
6
+ npm i @kashi-ui/css
7
+ ```
8
+
9
+ ```js
10
+ import "@kashi-ui/css";
11
+ ```
12
+
13
+ یا از CDN:
14
+
15
+ ```html
16
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kashi-ui/css/dist/kashi.css">
17
+
18
+ <html lang="fa" dir="rtl">
19
+ <button class="k-btn k-btn--primary">ثبت‌نام</button>
20
+ ```
21
+
22
+ - راست‌به‌چپ از پایه با Logical Properties
23
+ - تم تیره (پیش‌فرض) و روشن با `data-theme="light"`
24
+ - همهٔ استایل‌ها در Cascade Layer؛ CSS شما همیشه اولویت دارد
25
+ - فونت متغیر وزیرمتن همراه پکیج (لایسنس SIL OFL 1.1، اثر صابر راستی‌کردار)
26
+
27
+ مستندات کامل: [kashi.sepantapouya.com](https://kashi.sepantapouya.com) · کد: [GitHub](https://github.com/Sepantapouya/Kashi) · لایسنس MIT
package/dist/base.css ADDED
@@ -0,0 +1,82 @@
1
+ /* پایه — فقط در ریشه یا داخل .k-root اعمال می‌شود */
2
+ *, *::before, *::after { box-sizing: border-box; }
3
+
4
+ :where(html) {
5
+ -webkit-text-size-adjust: 100%;
6
+ text-size-adjust: 100%;
7
+ }
8
+
9
+ :where(body, .k-root) {
10
+ margin: 0;
11
+ background: var(--k-bg-primary);
12
+ color: var(--k-text-primary);
13
+ font-family: var(--k-font-sans);
14
+ font-size: var(--k-text-md);
15
+ line-height: var(--k-leading-normal);
16
+ -webkit-font-smoothing: antialiased;
17
+ -moz-osx-font-smoothing: grayscale;
18
+ /* کشیده‌نویسی و اتصال درست حروف فارسی */
19
+ font-feature-settings: "kern", "liga", "calt";
20
+ }
21
+
22
+ :where(h1, h2, h3, h4, h5, h6) {
23
+ margin: 0;
24
+ line-height: var(--k-leading-tight);
25
+ font-weight: var(--k-weight-bold);
26
+ }
27
+
28
+ :where(:focus-visible) {
29
+ outline: 2px solid var(--k-border-brand);
30
+ outline-offset: 2px;
31
+ }
32
+
33
+ ::selection {
34
+ background: var(--k-bg-brand-subtle);
35
+ color: var(--k-text-primary);
36
+ }
37
+
38
+ /* فقط برای صفحه‌خوان قابل‌خواندن است */
39
+ .k-sr-only {
40
+ position: absolute;
41
+ inline-size: 1px;
42
+ block-size: 1px;
43
+ padding: 0;
44
+ margin: -1px;
45
+ overflow: hidden;
46
+ clip-path: inset(50%);
47
+ white-space: nowrap;
48
+ border: 0;
49
+ }
50
+
51
+ /* لینک «رفتن به محتوای اصلی» برای کاربران کیبورد */
52
+ .k-skip-link {
53
+ position: absolute;
54
+ inset-inline-start: var(--k-space-4);
55
+ inset-block-start: var(--k-space-4);
56
+ z-index: var(--k-z-toast);
57
+ padding: var(--k-space-2) var(--k-space-4);
58
+ border-radius: var(--k-radius-md);
59
+ background: var(--k-bg-brand);
60
+ color: var(--k-text-on-brand);
61
+ translate: 0 -200%;
62
+ }
63
+ .k-skip-link:focus { translate: 0 0; }
64
+
65
+ /* کاربرانی که کنتراست بیشتر خواسته‌اند */
66
+ @media (prefers-contrast: more) {
67
+ :root {
68
+ --k-text-tertiary: var(--k-text-secondary);
69
+ --k-border-primary: var(--k-text-tertiary);
70
+ --k-border-secondary: var(--k-border-primary);
71
+ }
72
+ }
73
+
74
+ /* ارقام لاتین در کنار متن فارسی: tabular برای جدول‌ها و اعداد */
75
+ .k-tabular { font-variant-numeric: tabular-nums; }
76
+
77
+ @media (prefers-reduced-motion: reduce) {
78
+ *, *::before, *::after {
79
+ animation-duration: 0.01ms !important;
80
+ transition-duration: 0.01ms !important;
81
+ }
82
+ }
@@ -0,0 +1,92 @@
1
+ /* هشدار (Alert) — به سبک Untitled UI: سطح خنثی، رنگ فقط در آیکون شاخص
2
+ * <div class="k-alert k-alert--warning" role="alert"> ← role="status" برای پیام‌های غیرفوری
3
+ * <span class="k-alert__icon" aria-hidden="true"><svg>…</svg></span>
4
+ * <div class="k-alert__content">
5
+ * <p class="k-alert__title">عنوان</p>
6
+ * <p class="k-alert__description">توضیح</p>
7
+ * <div class="k-alert__actions">…</div>
8
+ * </div>
9
+ * <button class="k-btn k-btn--tertiary k-btn--icon k-btn--sm k-alert__close" aria-label="بستن">×</button>
10
+ * </div>
11
+ * رنگ‌ها: neutral | brand | info | success | warning | error
12
+ * k-alert--tinted: پس‌زمینهٔ رنگی کم‌رنگ به‌جای سطح خنثی
13
+ *
14
+ * متغیرها: --k-alert-radius --k-alert-padding --k-alert-bg
15
+ */
16
+ .k-alert {
17
+ --_accent: var(--k-text-tertiary);
18
+ --_bg: var(--k-alert-bg, var(--k-bg-secondary));
19
+
20
+ display: flex;
21
+ align-items: flex-start;
22
+ gap: var(--k-space-4);
23
+ padding: var(--k-alert-padding, calc(1rem * var(--k-density)));
24
+ border: 1px solid var(--k-border-primary);
25
+ border-radius: var(--k-alert-radius, var(--k-radius-xl));
26
+ background: var(--_bg);
27
+ color: var(--k-text-tertiary);
28
+ font-size: var(--k-text-sm);
29
+ box-shadow: var(--k-shadow-xs);
30
+ }
31
+
32
+ .k-alert--brand { --_accent: var(--k-text-brand); }
33
+ .k-alert--info { --_accent: var(--k-text-info); }
34
+ .k-alert--success { --_accent: var(--k-text-success); }
35
+ .k-alert--warning { --_accent: var(--k-text-warning); }
36
+ .k-alert--error { --_accent: var(--k-text-error); }
37
+
38
+ .k-alert--tinted {
39
+ --_bg: var(--k-alert-bg, color-mix(in srgb, var(--_accent) 8%, var(--k-bg-primary)));
40
+ border-color: color-mix(in srgb, var(--_accent) 32%, transparent);
41
+ }
42
+
43
+ /* آیکون شاخص با دو حلقهٔ هم‌مرکز (featured icon) */
44
+ .k-alert__icon {
45
+ position: relative;
46
+ display: grid;
47
+ place-items: center;
48
+ flex-shrink: 0;
49
+ inline-size: 1.25rem;
50
+ block-size: 1.25rem;
51
+ margin: 0.375rem;
52
+ color: var(--_accent);
53
+ }
54
+ .k-alert__icon::before,
55
+ .k-alert__icon::after {
56
+ content: "";
57
+ position: absolute;
58
+ border: 2px solid var(--_accent);
59
+ border-radius: var(--k-radius-full);
60
+ }
61
+ .k-alert__icon::before { inset: -0.3125rem; opacity: 0.3; }
62
+ .k-alert__icon::after { inset: -0.625rem; opacity: 0.1; }
63
+ .k-alert__icon svg { inline-size: 100%; block-size: 100%; }
64
+
65
+ .k-alert__content {
66
+ flex: 1;
67
+ display: grid;
68
+ gap: var(--k-space-1);
69
+ min-inline-size: 0;
70
+ padding-block-start: 0.125rem;
71
+ }
72
+
73
+ .k-alert__title {
74
+ margin: 0;
75
+ color: var(--k-text-secondary);
76
+ font-weight: var(--k-weight-semibold);
77
+ }
78
+
79
+ .k-alert__description { margin: 0; }
80
+
81
+ .k-alert__actions {
82
+ display: flex;
83
+ flex-wrap: wrap;
84
+ gap: var(--k-space-3);
85
+ margin-block-start: var(--k-space-2);
86
+ }
87
+
88
+ .k-alert__close { margin-block: -0.375rem; margin-inline-end: -0.375rem; }
89
+
90
+ @media (forced-colors: active) {
91
+ .k-alert { border-color: CanvasText; }
92
+ }
@@ -0,0 +1,77 @@
1
+ /* آواتار
2
+ * <span class="k-avatar k-avatar--lg">
3
+ * <img class="k-avatar__image" src="…" alt="سارا احمدی"> ← یا حروف اول: <span aria-hidden="true">س‌ا</span> + role="img" aria-label روی والد
4
+ * <span class="k-avatar__status k-avatar__status--online"></span>
5
+ * </span>
6
+ * اندازه‌ها: xs | sm | md | lg | xl | 2xl — شکل: k-avatar--square — رنگ: k-avatar--brand
7
+ * گروه: <div class="k-avatar-group">…</div>
8
+ *
9
+ * متغیرها: --k-avatar-size --k-avatar-radius --k-avatar-bg --k-avatar-fg
10
+ */
11
+ .k-avatar {
12
+ --_s: var(--k-avatar-size, 2.5rem);
13
+
14
+ position: relative;
15
+ display: inline-grid;
16
+ place-items: center;
17
+ flex-shrink: 0;
18
+ inline-size: var(--_s);
19
+ block-size: var(--_s);
20
+ border-radius: var(--k-avatar-radius, var(--k-radius-full));
21
+ background: var(--k-avatar-bg, var(--k-bg-tertiary));
22
+ color: var(--k-avatar-fg, var(--k-text-secondary));
23
+ font-size: calc(var(--_s) * 0.36);
24
+ font-weight: var(--k-weight-semibold);
25
+ line-height: 1;
26
+ user-select: none;
27
+ /* حاشیهٔ داخلی ظریف مثل Untitled UI */
28
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--k-text-primary) 8%, transparent);
29
+ }
30
+
31
+ .k-avatar__image {
32
+ position: absolute;
33
+ inset: 0;
34
+ inline-size: 100%;
35
+ block-size: 100%;
36
+ object-fit: cover;
37
+ border-radius: inherit;
38
+ }
39
+
40
+ .k-avatar--xs { --_s: var(--k-avatar-size, 1.5rem); }
41
+ .k-avatar--sm { --_s: var(--k-avatar-size, 2rem); }
42
+ .k-avatar--lg { --_s: var(--k-avatar-size, 3rem); }
43
+ .k-avatar--xl { --_s: var(--k-avatar-size, 3.5rem); }
44
+ .k-avatar--2xl { --_s: var(--k-avatar-size, 4rem); }
45
+
46
+ .k-avatar--square { border-radius: var(--k-avatar-radius, var(--k-radius-md)); }
47
+ .k-avatar--brand {
48
+ background: var(--k-avatar-bg, var(--k-bg-brand-subtle));
49
+ color: var(--k-avatar-fg, var(--k-text-brand));
50
+ }
51
+
52
+ .k-avatar__status {
53
+ position: absolute;
54
+ inset-block-end: 0;
55
+ inset-inline-end: 0;
56
+ inline-size: max(0.5rem, calc(var(--_s) * 0.28));
57
+ block-size: max(0.5rem, calc(var(--_s) * 0.28));
58
+ border: 2px solid var(--k-bg-primary);
59
+ border-radius: var(--k-radius-full);
60
+ background: var(--k-border-input);
61
+ }
62
+ .k-avatar__status--online { background: var(--k-text-success); }
63
+ .k-avatar__status--busy { background: var(--k-text-error); }
64
+ .k-avatar__status--away { background: var(--k-text-warning); }
65
+
66
+ .k-avatar-group { display: inline-flex; align-items: center; }
67
+ .k-avatar-group > .k-avatar {
68
+ box-shadow: 0 0 0 2px var(--k-bg-primary);
69
+ }
70
+ .k-avatar-group > .k-avatar + .k-avatar {
71
+ margin-inline-start: calc(var(--_s) * -0.28);
72
+ }
73
+
74
+ @media (forced-colors: active) {
75
+ .k-avatar { border: 1px solid CanvasText; }
76
+ .k-avatar__status { background: CanvasText; }
77
+ }
@@ -0,0 +1,48 @@
1
+ /* نشان (Badge)
2
+ * <span class="k-badge k-badge--success"><span class="k-badge__dot" aria-hidden="true"></span>فعال</span>
3
+ * رنگ‌ها: neutral | brand | error | warning | success | info — اندازه‌ها: sm | md | lg
4
+ * شکل: پیش‌فرض گرد (pill)؛ k-badge--square برای گوشهٔ کم
5
+ *
6
+ * متغیرها: --k-badge-radius --k-badge-font-weight
7
+ */
8
+ .k-badge {
9
+ --_bg: var(--k-bg-tertiary);
10
+ --_fg: var(--k-text-secondary);
11
+ --_px: 0.625rem;
12
+
13
+ display: inline-flex;
14
+ align-items: center;
15
+ gap: var(--k-space-1);
16
+ padding-block: 0.125rem;
17
+ padding-inline: var(--_px);
18
+ border: 1px solid color-mix(in srgb, var(--_fg) 24%, transparent);
19
+ border-radius: var(--k-badge-radius, var(--k-radius-full));
20
+ background: var(--_bg);
21
+ color: var(--_fg);
22
+ font-size: var(--k-text-sm);
23
+ font-weight: var(--k-badge-font-weight, var(--k-weight-medium));
24
+ line-height: 1.5;
25
+ white-space: nowrap;
26
+ }
27
+
28
+ .k-badge--brand { --_bg: var(--k-bg-brand-subtle); --_fg: var(--k-text-brand); }
29
+ .k-badge--error { --_bg: var(--k-bg-error-subtle); --_fg: var(--k-text-error); }
30
+ .k-badge--warning { --_bg: var(--k-bg-warning-subtle); --_fg: var(--k-text-warning); }
31
+ .k-badge--success { --_bg: var(--k-bg-success-subtle); --_fg: var(--k-text-success); }
32
+ .k-badge--info { --_bg: var(--k-bg-info-subtle); --_fg: var(--k-text-info); }
33
+
34
+ .k-badge--sm { --_px: 0.5rem; font-size: var(--k-text-xs); }
35
+ .k-badge--lg { --_px: 0.75rem; padding-block: 0.25rem; }
36
+ .k-badge--square { border-radius: var(--k-badge-radius, var(--k-radius-sm)); }
37
+
38
+ .k-badge__dot {
39
+ inline-size: 0.375rem;
40
+ block-size: 0.375rem;
41
+ border-radius: var(--k-radius-full);
42
+ background: currentColor;
43
+ }
44
+ .k-badge svg { inline-size: 0.875em; block-size: 0.875em; }
45
+
46
+ @media (forced-colors: active) {
47
+ .k-badge { border-color: CanvasText; }
48
+ }
@@ -0,0 +1,169 @@
1
+ /* دکمه — به سبک Untitled UI: سایهٔ اسکئومورفیک و حلقهٔ فوکوس نرم
2
+ * <button class="k-btn k-btn--primary k-btn--md">ثبت</button>
3
+ * گونه‌ها: primary | secondary | tertiary | link | danger | danger-secondary
4
+ * اندازه‌ها: sm | md | lg | xl — حالت‌ها: disabled، aria-disabled، aria-busy="true"
5
+ *
6
+ * متغیرهای قابل‌بازنویسی (روی :root یا هر والدی):
7
+ * --k-btn-height-{sm,md,lg,xl} --k-btn-padding-{sm,md,lg,xl}
8
+ * --k-btn-radius --k-btn-font-weight --k-btn-gap
9
+ */
10
+ .k-btn {
11
+ --_h: var(--k-btn-height-md, calc(2.5rem * var(--k-density)));
12
+ --_px: var(--k-btn-padding-md, calc(0.875rem * var(--k-density)));
13
+ --_fs: var(--k-text-sm);
14
+ --_bg: var(--k-bg-primary);
15
+ --_bg-hover: var(--k-bg-hover);
16
+ --_fg: var(--k-text-secondary);
17
+ --_fg-hover: var(--k-text-primary);
18
+ --_border: var(--k-border-primary);
19
+ --_shadow: var(--k-shadow-xs), var(--k-shadow-skeuomorphic);
20
+ --_ring: var(--k-ring-brand);
21
+
22
+ position: relative;
23
+ display: inline-flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ gap: var(--k-btn-gap, var(--k-space-1_5));
27
+ block-size: var(--_h);
28
+ /* حداقل ناحیهٔ لمس WCAG 2.5.8 */
29
+ min-block-size: 24px;
30
+ min-inline-size: 24px;
31
+ padding-inline: var(--_px);
32
+ border: 1px solid var(--_border);
33
+ border-radius: var(--k-btn-radius, var(--k-radius-md));
34
+ background: var(--_bg);
35
+ color: var(--_fg);
36
+ box-shadow: var(--_shadow);
37
+ font: inherit;
38
+ font-size: var(--_fs);
39
+ font-weight: var(--k-btn-font-weight, var(--k-weight-semibold));
40
+ line-height: 1;
41
+ white-space: nowrap;
42
+ text-decoration: none;
43
+ cursor: pointer;
44
+ user-select: none;
45
+ transition:
46
+ background-color var(--k-duration-fast) var(--k-ease-standard),
47
+ color var(--k-duration-fast) var(--k-ease-standard),
48
+ box-shadow var(--k-duration-fast) var(--k-ease-standard);
49
+ }
50
+
51
+ .k-btn:hover { background: var(--_bg-hover); color: var(--_fg-hover); }
52
+
53
+ .k-btn:focus-visible {
54
+ /* outline شفاف در حالت forced-colors ویندوز قابل‌مشاهده می‌شود */
55
+ outline: 2px solid transparent;
56
+ box-shadow: var(--_shadow), var(--_ring);
57
+ }
58
+
59
+ .k-btn:disabled,
60
+ .k-btn[aria-disabled="true"]:not([aria-busy="true"]) {
61
+ --_bg: var(--k-bg-secondary);
62
+ --_fg: var(--k-text-quaternary);
63
+ --_border: var(--k-border-secondary);
64
+ --_shadow: var(--k-shadow-xs);
65
+ cursor: not-allowed;
66
+ }
67
+ .k-btn[aria-disabled="true"]:hover { background: var(--_bg); color: var(--_fg); }
68
+
69
+
70
+ /* گونه‌ها */
71
+ .k-btn--primary {
72
+ --_bg: var(--k-bg-brand);
73
+ --_bg-hover: var(--k-bg-brand-hover);
74
+ --_fg: var(--k-text-on-brand);
75
+ --_fg-hover: var(--k-text-on-brand);
76
+ --_border: transparent;
77
+ --_shadow: var(--k-shadow-xs), var(--k-shadow-skeuomorphic);
78
+ }
79
+ /* حاشیهٔ داخلی سفید که به پایین محو می‌شود (Untitled UI) */
80
+ .k-btn:is(.k-btn--primary, .k-btn--danger)::before {
81
+ content: "";
82
+ position: absolute;
83
+ inset: 1px;
84
+ border: 1px solid rgb(255 255 255 / 0.12);
85
+ border-radius: inherit;
86
+ mask: linear-gradient(to bottom, #000, transparent);
87
+ pointer-events: none;
88
+ }
89
+ .k-btn:is(.k-btn--primary, .k-btn--danger):is(:disabled, [aria-disabled="true"]:not([aria-busy="true"]))::before { display: none; }
90
+ .k-btn--tertiary {
91
+ --_bg: transparent;
92
+ --_border: transparent;
93
+ --_shadow: none;
94
+ }
95
+ .k-btn--link {
96
+ --_bg: transparent;
97
+ --_bg-hover: transparent;
98
+ --_fg: var(--k-text-brand);
99
+ --_fg-hover: var(--k-text-brand);
100
+ --_border: transparent;
101
+ --_shadow: none;
102
+ --_h: auto;
103
+ --_px: 0;
104
+ }
105
+ .k-btn--link:hover { text-decoration: underline; text-underline-offset: 0.3em; }
106
+ .k-btn--danger {
107
+ --_bg: var(--k-bg-error);
108
+ --_bg-hover: var(--k-bg-error-hover);
109
+ --_fg: var(--k-text-on-brand);
110
+ --_fg-hover: var(--k-text-on-brand);
111
+ --_border: transparent;
112
+ --_shadow: var(--k-shadow-xs), var(--k-shadow-skeuomorphic);
113
+ --_ring: var(--k-ring-error);
114
+ }
115
+ .k-btn--danger-secondary {
116
+ --_fg: var(--k-text-error);
117
+ --_fg-hover: var(--k-text-error);
118
+ --_bg-hover: var(--k-bg-error-subtle);
119
+ --_ring: var(--k-ring-error);
120
+ }
121
+
122
+ /* اندازه‌ها */
123
+ .k-btn--sm {
124
+ --_h: var(--k-btn-height-sm, calc(2.25rem * var(--k-density)));
125
+ --_px: var(--k-btn-padding-sm, calc(0.75rem * var(--k-density)));
126
+ }
127
+ .k-btn--lg {
128
+ --_h: var(--k-btn-height-lg, calc(2.75rem * var(--k-density)));
129
+ --_px: var(--k-btn-padding-lg, calc(1.125rem * var(--k-density)));
130
+ --_fs: var(--k-text-md);
131
+ }
132
+ .k-btn--xl {
133
+ --_h: var(--k-btn-height-xl, calc(3rem * var(--k-density)));
134
+ --_px: var(--k-btn-padding-xl, calc(1.25rem * var(--k-density)));
135
+ --_fs: var(--k-text-md);
136
+ }
137
+ .k-btn--icon { padding-inline: 0; inline-size: var(--_h); }
138
+ .k-btn--block { display: flex; inline-size: 100%; }
139
+
140
+ .k-btn svg { inline-size: 1.25em; block-size: 1.25em; flex-shrink: 0; }
141
+
142
+ /* آیکون‌های جهت‌دار (فلش و…) در RTL آینه می‌شوند */
143
+ [dir="rtl"] .k-btn [data-k-mirror] { transform: scaleX(-1); }
144
+
145
+ /* در حال بارگذاری */
146
+ .k-btn[aria-busy="true"] {
147
+ color: transparent;
148
+ cursor: progress;
149
+ }
150
+ .k-btn[aria-busy="true"]::after {
151
+ content: "";
152
+ position: absolute;
153
+ inline-size: 1.1em;
154
+ block-size: 1.1em;
155
+ border: 2px solid var(--_fg);
156
+ border-block-start-color: transparent;
157
+ border-radius: var(--k-radius-full);
158
+ animation: k-spin 0.7s linear infinite;
159
+ }
160
+
161
+ @keyframes k-spin { to { rotate: 360deg; } }
162
+
163
+ /* حالت کنتراست بالای ویندوز */
164
+ @media (forced-colors: active) {
165
+ .k-btn { border-color: ButtonText; }
166
+ .k-btn--primary, .k-btn--danger { border-color: ButtonText; }
167
+ .k-btn:disabled, .k-btn[aria-disabled="true"] { border-color: GrayText; color: GrayText; }
168
+ .k-btn[aria-busy="true"]::after { border-color: ButtonText; border-block-start-color: transparent; }
169
+ }
@@ -0,0 +1,77 @@
1
+ /* کارت
2
+ * <article class="k-card">
3
+ * <header class="k-card__header">
4
+ * <h3 class="k-card__title">عنوان</h3>
5
+ * <p class="k-card__description">توضیح</p>
6
+ * </header>
7
+ * <div class="k-card__body">...</div>
8
+ * <footer class="k-card__footer">...دکمه‌ها</footer>
9
+ * </article>
10
+ * گونه‌ها: k-card--flat (بدون سایه) | k-card--interactive (برای کارت قابل‌کلیک، همراه با <a> یا <button>)
11
+ *
12
+ * متغیرها: --k-card-padding --k-card-radius --k-card-bg --k-card-border --k-card-shadow
13
+ */
14
+ .k-card {
15
+ --_p: var(--k-card-padding, calc(1.5rem * var(--k-density)));
16
+
17
+ display: flex;
18
+ flex-direction: column;
19
+ border: 1px solid var(--k-card-border, var(--k-border-secondary));
20
+ border-radius: var(--k-card-radius, var(--k-radius-xl));
21
+ background: var(--k-card-bg, var(--k-bg-elevated));
22
+ color: var(--k-text-primary);
23
+ box-shadow: var(--k-card-shadow, var(--k-shadow-xs));
24
+ overflow: clip;
25
+ }
26
+
27
+ .k-card__header,
28
+ .k-card__body,
29
+ .k-card__footer { padding: var(--_p); }
30
+
31
+ .k-card__header + .k-card__body { padding-block-start: 0; }
32
+
33
+ .k-card__header { display: grid; gap: var(--k-space-1); }
34
+
35
+ .k-card__title {
36
+ margin: 0;
37
+ font-size: var(--k-text-lg);
38
+ font-weight: var(--k-weight-semibold);
39
+ line-height: var(--k-leading-tight);
40
+ }
41
+
42
+ .k-card__description {
43
+ margin: 0;
44
+ color: var(--k-text-tertiary);
45
+ font-size: var(--k-text-sm);
46
+ }
47
+
48
+ .k-card__footer {
49
+ display: flex;
50
+ flex-wrap: wrap;
51
+ gap: var(--k-space-3);
52
+ justify-content: flex-end;
53
+ padding-block: calc(var(--_p) * 0.66);
54
+ border-block-start: 1px solid var(--k-border-secondary);
55
+ margin-block-start: auto;
56
+ }
57
+
58
+ .k-card__media { display: block; inline-size: 100%; object-fit: cover; }
59
+
60
+ .k-card--flat { box-shadow: none; }
61
+
62
+ .k-card--interactive {
63
+ position: relative;
64
+ transition:
65
+ border-color var(--k-duration-fast) var(--k-ease-standard),
66
+ box-shadow var(--k-duration-normal) var(--k-ease-standard);
67
+ }
68
+ .k-card--interactive:hover { border-color: var(--k-border-primary); box-shadow: var(--k-shadow-md); }
69
+ .k-card--interactive:has(:focus-visible) { box-shadow: var(--k-shadow-md), var(--k-ring-brand); }
70
+ /* لینک اصلی کل کارت را قابل‌کلیک می‌کند ولی فقط یک توقف Tab دارد */
71
+ .k-card--interactive :is(a, button).k-card__link::after { content: ""; position: absolute; inset: 0; }
72
+ .k-card--interactive .k-card__link:focus-visible { outline: none; }
73
+
74
+ @media (forced-colors: active) {
75
+ .k-card { border-color: CanvasText; }
76
+ .k-card--interactive:has(:focus-visible) { outline: 2px solid Highlight; }
77
+ }
@@ -0,0 +1,93 @@
1
+ /* چک‌باکس — روی <input type="checkbox"> بومی، پس کیبورد و صفحه‌خوان خودکار کار می‌کنند
2
+ * <label class="k-check">
3
+ * <input type="checkbox" class="k-checkbox">
4
+ * <span class="k-check__text">
5
+ * <span class="k-check__label">مرا به خاطر بسپار</span>
6
+ * <span class="k-check__description">توضیح اختیاری</span>
7
+ * </span>
8
+ * </label>
9
+ * حالت نیمه: input.indeterminate = true — خطا: aria-invalid="true" — اندازه: k-checkbox--lg
10
+ *
11
+ * متغیرها: --k-checkbox-size --k-checkbox-radius
12
+ */
13
+ .k-checkbox {
14
+ --_s: var(--k-checkbox-size, 1.125rem);
15
+ --_border: var(--k-border-input);
16
+
17
+ appearance: none;
18
+ display: inline-grid;
19
+ place-content: center;
20
+ flex-shrink: 0;
21
+ inline-size: var(--_s);
22
+ block-size: var(--_s);
23
+ margin: 0;
24
+ border: 1px solid var(--_border);
25
+ border-radius: var(--k-checkbox-radius, calc(0.3125rem * var(--k-radius-factor)));
26
+ background: var(--k-bg-primary);
27
+ color: var(--k-text-on-brand);
28
+ cursor: pointer;
29
+ transition:
30
+ background-color var(--k-duration-fast) var(--k-ease-standard),
31
+ border-color var(--k-duration-fast) var(--k-ease-standard),
32
+ box-shadow var(--k-duration-fast) var(--k-ease-standard);
33
+ }
34
+
35
+ .k-checkbox::before {
36
+ content: "";
37
+ inline-size: calc(var(--_s) * 0.7);
38
+ block-size: calc(var(--_s) * 0.7);
39
+ background: currentColor;
40
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11.5 3.5 5.5 10 2.5 7'/%3E%3C/svg%3E") center / contain no-repeat;
41
+ scale: 0;
42
+ transition: scale var(--k-duration-fast) var(--k-ease-emphasized);
43
+ }
44
+ .k-checkbox:indeterminate::before {
45
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3 7h8'/%3E%3C/svg%3E");
46
+ }
47
+
48
+ .k-checkbox:hover { --_border: var(--k-border-brand); }
49
+
50
+ .k-checkbox:is(:checked, :indeterminate) {
51
+ --_border: var(--k-bg-brand);
52
+ background: var(--k-bg-brand);
53
+ }
54
+ .k-checkbox:is(:checked, :indeterminate)::before { scale: 1; }
55
+
56
+ .k-checkbox:focus-visible {
57
+ outline: 2px solid transparent;
58
+ box-shadow: var(--k-ring-brand);
59
+ }
60
+
61
+ .k-checkbox[aria-invalid="true"] { --_border: var(--k-border-error); }
62
+ .k-checkbox[aria-invalid="true"]:focus-visible { box-shadow: var(--k-ring-error); }
63
+
64
+ .k-checkbox:disabled {
65
+ --_border: var(--k-border-secondary);
66
+ background: var(--k-bg-tertiary);
67
+ color: var(--k-text-quaternary);
68
+ cursor: not-allowed;
69
+ }
70
+
71
+ .k-checkbox--lg { --_s: var(--k-checkbox-size, 1.25rem); }
72
+
73
+ /* ردیف برچسب — مشترک بین چک‌باکس و سوییچ */
74
+ .k-check {
75
+ display: inline-flex;
76
+ align-items: flex-start;
77
+ gap: var(--k-space-2);
78
+ cursor: pointer;
79
+ /* ارتفاع خط متن با کنترل هم‌تراز شود */
80
+ line-height: 1.25rem;
81
+ }
82
+ .k-check > :is(.k-checkbox, .k-switch) { margin-block-start: calc((1.25rem - var(--_h, var(--_s))) / 2); }
83
+ .k-check:has(:disabled) { cursor: not-allowed; }
84
+ .k-check__text { display: grid; gap: 0.125rem; }
85
+ .k-check__label { color: var(--k-text-secondary); font-size: var(--k-text-sm); font-weight: var(--k-weight-medium); }
86
+ .k-check__description { color: var(--k-text-tertiary); font-size: var(--k-text-sm); }
87
+ .k-check:has(:disabled) .k-check__label { color: var(--k-text-quaternary); }
88
+
89
+ /* حالت کنتراست بالای ویندوز: برگشت به کنترل بومی سیستم */
90
+ @media (forced-colors: active) {
91
+ .k-checkbox { appearance: auto; }
92
+ .k-checkbox::before { display: none; }
93
+ }