kmaterialize 2.3.3-1.0.20 → 2.3.3-1.0.22

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,217 @@
1
+ .kanban-board {
2
+ --kanban-column-width: 20rem;
3
+ --kanban-gap: 1rem;
4
+ display: flex;
5
+ align-items: flex-start;
6
+ gap: var(--kanban-gap);
7
+ width: 100%;
8
+ padding: 0.25rem;
9
+ overflow-x: auto;
10
+ box-sizing: border-box;
11
+ overscroll-behavior-x: contain;
12
+
13
+ &.kanban-wrap {
14
+ flex-wrap: wrap;
15
+ overflow-x: visible;
16
+ }
17
+ }
18
+
19
+ .kanban-column {
20
+ display: flex;
21
+ flex: 0 0 var(--kanban-column-width);
22
+ flex-direction: column;
23
+ min-height: 15rem;
24
+ padding: 0.75rem;
25
+ border: 1px solid var(--md-sys-color-outline-variant);
26
+ border-radius: 0.875rem;
27
+ background: var(--md-sys-color-surface-variant);
28
+ box-sizing: border-box;
29
+ transition: border-color 160ms ease, background-color 160ms ease;
30
+
31
+ &.is-drag-over {
32
+ border-color: var(--md-sys-color-primary);
33
+ background: color-mix(in srgb, var(--md-sys-color-primary-container) 55%, var(--md-sys-color-surface-variant));
34
+ }
35
+ }
36
+
37
+ .kanban-column-header {
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: space-between;
41
+ gap: 0.5rem;
42
+ padding: 0.25rem 0.25rem 0.75rem;
43
+ color: var(--md-sys-color-on-surface-variant);
44
+ }
45
+
46
+ .kanban-column-title {
47
+ margin: 0;
48
+ font-size: 1rem;
49
+ font-weight: 600;
50
+ }
51
+
52
+ .kanban-column-count {
53
+ display: inline-flex;
54
+ min-width: 1.5rem;
55
+ min-height: 1.5rem;
56
+ align-items: center;
57
+ justify-content: center;
58
+ padding: 0 0.375rem;
59
+ border-radius: 999px;
60
+ background: var(--md-sys-color-surface);
61
+ color: var(--md-sys-color-on-surface);
62
+ font-size: 0.75rem;
63
+ }
64
+
65
+ .kanban-column-body {
66
+ display: flex;
67
+ flex: 1 1 auto;
68
+ flex-direction: column;
69
+ gap: 0.75rem;
70
+ min-height: 8rem;
71
+ }
72
+
73
+ .kanban-card {
74
+ --kanban-card-accent: var(--md-sys-color-primary);
75
+ position: relative;
76
+ display: flex;
77
+ flex-direction: column;
78
+ gap: 0.625rem;
79
+ padding: 1rem;
80
+ border: 1px solid var(--md-sys-color-outline-variant);
81
+ border-radius: 0.75rem;
82
+ background: var(--md-sys-color-surface);
83
+ color: var(--md-sys-color-on-surface);
84
+ box-shadow: var(--md-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, 0.14));
85
+ cursor: grab;
86
+ user-select: none;
87
+ overflow: hidden;
88
+ transition: transform 160ms ease, opacity 160ms ease, box-shadow 160ms ease;
89
+
90
+ &:active,
91
+ &.is-dragging {
92
+ cursor: grabbing;
93
+ }
94
+
95
+ &.is-dragging {
96
+ opacity: 0.45;
97
+ box-shadow: var(--md-sys-elevation-level3, 0 8px 18px rgba(0, 0, 0, 0.2));
98
+ }
99
+
100
+ &:focus-visible {
101
+ outline: 2px solid var(--md-sys-color-primary);
102
+ outline-offset: 2px;
103
+ }
104
+
105
+ &.kanban-card-accent {
106
+ &::after {
107
+ position: absolute;
108
+ right: 0;
109
+ bottom: 0;
110
+ left: 0;
111
+ height: 0.25rem;
112
+ background: var(--kanban-card-accent);
113
+ content: '';
114
+ pointer-events: none;
115
+ }
116
+ }
117
+
118
+ &.kanban-card-accent-top::after {
119
+ top: 0;
120
+ bottom: auto;
121
+ left: 0;
122
+ width: 100%;
123
+ height: 0.25rem;
124
+ }
125
+
126
+ &.kanban-card-accent-right::after {
127
+ top: 0;
128
+ right: 0;
129
+ bottom: 0;
130
+ left: auto;
131
+ width: 0.25rem;
132
+ height: 100%;
133
+ }
134
+
135
+ &.kanban-card-accent-left::after {
136
+ top: 0;
137
+ right: auto;
138
+ bottom: 0;
139
+ left: 0;
140
+ width: 0.25rem;
141
+ height: 100%;
142
+ }
143
+
144
+ &.is-disabled,
145
+ &[aria-disabled='true'] {
146
+ cursor: not-allowed;
147
+ opacity: 0.55;
148
+ filter: saturate(0.55);
149
+ }
150
+ }
151
+
152
+ .kanban-drag-image {
153
+ position: fixed !important;
154
+ top: -10000px !important;
155
+ left: -10000px !important;
156
+ z-index: -1;
157
+ pointer-events: none;
158
+ transform: rotate(2deg) scale(1.015);
159
+ transform-origin: center;
160
+ }
161
+
162
+ .kanban-drop-preview {
163
+ min-height: 4rem;
164
+ box-sizing: border-box;
165
+ border: 2px dashed var(--md-sys-color-primary);
166
+ border-radius: 0.75rem;
167
+ background: color-mix(in srgb, var(--md-sys-color-primary-container) 45%, transparent);
168
+ pointer-events: none;
169
+ }
170
+
171
+ .kanban-card-title {
172
+ margin: 0;
173
+ font-size: 1rem;
174
+ font-weight: 600;
175
+ }
176
+
177
+ .kanban-card-description {
178
+ margin: 0;
179
+ color: var(--md-sys-color-on-surface-variant);
180
+ font-size: 0.875rem;
181
+ }
182
+
183
+ .kanban-card-meta {
184
+ display: flex;
185
+ align-items: center;
186
+ justify-content: space-between;
187
+ gap: 0.5rem;
188
+ color: var(--md-sys-color-on-surface-variant);
189
+ font-size: 0.75rem;
190
+ }
191
+
192
+ .kanban-card-label {
193
+ display: inline-flex;
194
+ align-items: center;
195
+ align-self: flex-start;
196
+ padding: 0.1875rem 0.5rem;
197
+ border-radius: 999px;
198
+ background: var(--md-sys-color-secondary-container);
199
+ color: var(--md-sys-color-on-secondary-container);
200
+ font-size: 0.75rem;
201
+ }
202
+
203
+ .kanban-empty {
204
+ display: grid;
205
+ min-height: 5rem;
206
+ place-items: center;
207
+ border: 1px dashed var(--md-sys-color-outline);
208
+ border-radius: 0.625rem;
209
+ color: var(--md-sys-color-on-surface-variant);
210
+ font-size: 0.875rem;
211
+ }
212
+
213
+ @media (max-width: 600px) {
214
+ .kanban-board {
215
+ --kanban-column-width: min(20rem, calc(100vw - 3rem));
216
+ }
217
+ }
@@ -0,0 +1,182 @@
1
+ import { BaseOptions, Component, InitElements, MElement } from '../../src/component';
2
+
3
+ export interface KanbanMoveDetail {
4
+ card: HTMLElement;
5
+ from: HTMLElement;
6
+ to: HTMLElement;
7
+ }
8
+
9
+ export interface KanbanOptions extends BaseOptions {
10
+ /** Enable native drag-and-drop interactions. */
11
+ draggable: boolean;
12
+ /** Called after a card changes column or order. */
13
+ onMove?: (detail: KanbanMoveDetail) => void;
14
+ }
15
+
16
+ const _defaults: KanbanOptions = {
17
+ draggable: true
18
+ };
19
+
20
+ /** A lightweight, dependency-free board for columns of draggable cards. */
21
+ export class Kanban extends Component<KanbanOptions> {
22
+ private _draggedCard: HTMLElement | null = null;
23
+ private _dragSourceColumn: HTMLElement | null = null;
24
+ private _dropPreview: HTMLElement | null = null;
25
+ private _dragImage: HTMLElement | null = null;
26
+ private _previewHeight = 64;
27
+
28
+ private _onDragStart = (event: DragEvent) => {
29
+ const card = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-card');
30
+ if (!card || !this.options.draggable || card.classList.contains('is-disabled') || card.getAttribute('aria-disabled') === 'true') return;
31
+ this._draggedCard = card;
32
+ this._dragSourceColumn = card.closest<HTMLElement>('.kanban-column');
33
+ this._previewHeight = Math.max(64, Math.round(card.getBoundingClientRect().height));
34
+ card.classList.add('is-dragging');
35
+ this._dragImage = card.cloneNode(true) as HTMLElement;
36
+ this._dragImage.classList.remove('is-dragging');
37
+ this._dragImage.classList.add('kanban-drag-image');
38
+ this._dragImage.setAttribute('aria-hidden', 'true');
39
+ this._dragImage.style.width = `${card.getBoundingClientRect().width}px`;
40
+ document.body.appendChild(this._dragImage);
41
+ event.dataTransfer?.setDragImage(this._dragImage, card.offsetWidth / 2, card.offsetHeight / 2);
42
+ event.dataTransfer?.setData('text/plain', card.dataset.kanbanCard || '');
43
+ if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move';
44
+ };
45
+
46
+ private _onDragOver = (event: DragEvent) => {
47
+ if (!this._draggedCard) return;
48
+ const column = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-column');
49
+ if (!column || !this.el.contains(column)) return;
50
+ event.preventDefault();
51
+ if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';
52
+ this.el.querySelectorAll('.kanban-column.is-drag-over').forEach((item) => item.classList.remove('is-drag-over'));
53
+ column.classList.add('is-drag-over');
54
+ this._updateDropPreview(column, event);
55
+ };
56
+
57
+ private _onDrop = (event: DragEvent) => {
58
+ if (!this._draggedCard) return;
59
+ const column = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-column');
60
+ if (!column || !this.el.contains(column)) return;
61
+ event.preventDefault();
62
+ const body = column.querySelector<HTMLElement>('.kanban-column-body') || column;
63
+ const targetCard = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-card');
64
+ const source = this._dragSourceColumn;
65
+ const movedCard = this._draggedCard;
66
+ if (this._dropPreview?.parentElement === body) {
67
+ body.insertBefore(movedCard, this._dropPreview);
68
+ this._dropPreview.remove();
69
+ } else if (targetCard && targetCard !== movedCard && targetCard.parentElement === body) {
70
+ body.insertBefore(movedCard, targetCard);
71
+ } else {
72
+ body.appendChild(movedCard);
73
+ }
74
+ this._clearDragState();
75
+ this._updateCounts();
76
+ if (source && source !== column) this.options.onMove?.({ card: movedCard, from: source, to: column });
77
+ };
78
+
79
+ private _onDragEnd = () => this._clearDragState();
80
+
81
+ constructor(el: HTMLElement, options: Partial<KanbanOptions>) {
82
+ super(el, options, Kanban);
83
+ this.options = { ...Kanban.defaults, ...options };
84
+ this.el['M_Kanban'] = this;
85
+ this._prepareMarkup();
86
+ if (this.options.draggable) this._bindEvents();
87
+ }
88
+
89
+ static get defaults(): KanbanOptions {
90
+ return _defaults;
91
+ }
92
+
93
+ static init(el: HTMLElement, options?: Partial<KanbanOptions>): Kanban;
94
+ static init(els: InitElements<MElement>, options?: Partial<KanbanOptions>): Kanban[];
95
+ static init(els: HTMLElement | InitElements<MElement>, options: Partial<KanbanOptions> = {}): Kanban | Kanban[] {
96
+ return super.init(els, options, Kanban);
97
+ }
98
+
99
+ static getInstance(el: HTMLElement): Kanban {
100
+ return el['M_Kanban'];
101
+ }
102
+
103
+ private _prepareMarkup() {
104
+ this.el.setAttribute('role', 'region');
105
+ this.el.querySelectorAll<HTMLElement>('.kanban-column').forEach((column) => {
106
+ column.setAttribute('role', 'group');
107
+ const body = column.querySelector<HTMLElement>('.kanban-column-body');
108
+ if (body) body.setAttribute('role', 'list');
109
+ column.querySelectorAll<HTMLElement>('.kanban-card').forEach((card) => {
110
+ card.setAttribute('role', 'listitem');
111
+ const disabled = card.classList.contains('is-disabled') || card.getAttribute('aria-disabled') === 'true';
112
+ card.setAttribute('tabindex', disabled ? '-1' : '0');
113
+ if (disabled) {
114
+ card.setAttribute('aria-disabled', 'true');
115
+ card.draggable = false;
116
+ } else if (this.options.draggable) {
117
+ card.draggable = true;
118
+ }
119
+ });
120
+ });
121
+ this._updateCounts();
122
+ }
123
+
124
+ private _bindEvents() {
125
+ this.el.addEventListener('dragstart', this._onDragStart);
126
+ this.el.addEventListener('dragover', this._onDragOver);
127
+ this.el.addEventListener('drop', this._onDrop);
128
+ this.el.addEventListener('dragend', this._onDragEnd);
129
+ }
130
+
131
+ private _clearDragState() {
132
+ this._dragImage?.remove();
133
+ this._dragImage = null;
134
+ this._dropPreview?.remove();
135
+ this._dropPreview = null;
136
+ this._draggedCard?.classList.remove('is-dragging');
137
+ this.el.querySelectorAll('.kanban-column.is-drag-over').forEach((item) => item.classList.remove('is-drag-over'));
138
+ this._draggedCard = null;
139
+ this._dragSourceColumn = null;
140
+ this._previewHeight = 64;
141
+ }
142
+
143
+ private _updateCounts() {
144
+ this.el.querySelectorAll<HTMLElement>('.kanban-column').forEach((column) => {
145
+ const count = column.querySelector<HTMLElement>('.kanban-column-count');
146
+ const body = column.querySelector<HTMLElement>('.kanban-column-body');
147
+ if (count && body) count.textContent = String(body.querySelectorAll(':scope > .kanban-card').length);
148
+ const empty = body?.querySelector<HTMLElement>('.kanban-empty');
149
+ if (empty && body) empty.hidden = body.querySelectorAll(':scope > .kanban-card').length > 0;
150
+ });
151
+ }
152
+
153
+ private _updateDropPreview(column: HTMLElement, event: DragEvent) {
154
+ const body = column.querySelector<HTMLElement>('.kanban-column-body') || column;
155
+ const targetCard = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-card');
156
+ if (targetCard === this._draggedCard) return;
157
+ if (!this._dropPreview) {
158
+ this._dropPreview = document.createElement('div');
159
+ this._dropPreview.className = 'kanban-drop-preview';
160
+ this._dropPreview.setAttribute('aria-hidden', 'true');
161
+ }
162
+ // Keep the preview tied to the dragged card's original height. Using the
163
+ // hovered card's height makes the placeholder jump as the pointer crosses
164
+ // cards with different content lengths.
165
+ this._dropPreview.style.height = `${this._previewHeight}px`;
166
+ if (targetCard && targetCard.parentElement === body) {
167
+ const box = targetCard.getBoundingClientRect();
168
+ body.insertBefore(this._dropPreview, event.clientY < box.top + box.height / 2 ? targetCard : targetCard.nextSibling);
169
+ } else if (this._dropPreview.parentElement !== body) {
170
+ body.appendChild(this._dropPreview);
171
+ }
172
+ }
173
+
174
+ destroy() {
175
+ this._clearDragState();
176
+ this.el.removeEventListener('dragstart', this._onDragStart);
177
+ this.el.removeEventListener('dragover', this._onDragOver);
178
+ this.el.removeEventListener('drop', this._onDrop);
179
+ this.el.removeEventListener('dragend', this._onDragEnd);
180
+ delete this.el['M_Kanban'];
181
+ }
182
+ }
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Materialize v2.3.3-1.0.20 (https://materializeweb.com)
2
+ * Materialize v2.3.3-1.0.22 (https://materializeweb.com)
3
3
  * Copyright 2014-2026 Materialize
4
4
  * MIT License (https://raw.githubusercontent.com/materializecss/materialize/master/LICENSE)
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Materialize v2.3.3-1.0.20 (https://materializeweb.com)
2
+ * Materialize v2.3.3-1.0.22 (https://materializeweb.com)
3
3
  * Copyright 2014-2026 Materialize
4
4
  * MIT License (https://raw.githubusercontent.com/materializecss/materialize/master/LICENSE)
5
5
  */
@@ -13863,6 +13863,296 @@ button.btn-floating {
13863
13863
  transform: translateY(-0.25rem);
13864
13864
  }
13865
13865
  }
13866
+ .kanban-board {
13867
+ --kanban-column-width: 20rem;
13868
+ --kanban-gap: 1rem;
13869
+ display: -webkit-box;
13870
+ display: -webkit-flex;
13871
+ display: -ms-flexbox;
13872
+ display: flex;
13873
+ -webkit-box-align: start;
13874
+ -webkit-align-items: flex-start;
13875
+ -ms-flex-align: start;
13876
+ align-items: flex-start;
13877
+ gap: var(--kanban-gap);
13878
+ width: 100%;
13879
+ padding: 0.25rem;
13880
+ overflow-x: auto;
13881
+ -webkit-box-sizing: border-box;
13882
+ box-sizing: border-box;
13883
+ overscroll-behavior-x: contain;
13884
+ }
13885
+ .kanban-board.kanban-wrap {
13886
+ -webkit-flex-wrap: wrap;
13887
+ -ms-flex-wrap: wrap;
13888
+ flex-wrap: wrap;
13889
+ overflow-x: visible;
13890
+ }
13891
+
13892
+ .kanban-column {
13893
+ display: -webkit-box;
13894
+ display: -webkit-flex;
13895
+ display: -ms-flexbox;
13896
+ display: flex;
13897
+ -webkit-box-flex: 0;
13898
+ -webkit-flex: 0 0 var(--kanban-column-width);
13899
+ -ms-flex: 0 0 var(--kanban-column-width);
13900
+ flex: 0 0 var(--kanban-column-width);
13901
+ -webkit-box-orient: vertical;
13902
+ -webkit-box-direction: normal;
13903
+ -webkit-flex-direction: column;
13904
+ -ms-flex-direction: column;
13905
+ flex-direction: column;
13906
+ min-height: 15rem;
13907
+ padding: 0.75rem;
13908
+ border: 1px solid var(--md-sys-color-outline-variant);
13909
+ border-radius: 0.875rem;
13910
+ background: var(--md-sys-color-surface-variant);
13911
+ -webkit-box-sizing: border-box;
13912
+ box-sizing: border-box;
13913
+ -webkit-transition: border-color 160ms ease, background-color 160ms ease;
13914
+ transition: border-color 160ms ease, background-color 160ms ease;
13915
+ }
13916
+ .kanban-column.is-drag-over {
13917
+ border-color: var(--md-sys-color-primary);
13918
+ background: color-mix(in srgb, var(--md-sys-color-primary-container) 55%, var(--md-sys-color-surface-variant));
13919
+ }
13920
+
13921
+ .kanban-column-header {
13922
+ display: -webkit-box;
13923
+ display: -webkit-flex;
13924
+ display: -ms-flexbox;
13925
+ display: flex;
13926
+ -webkit-box-align: center;
13927
+ -webkit-align-items: center;
13928
+ -ms-flex-align: center;
13929
+ align-items: center;
13930
+ -webkit-box-pack: justify;
13931
+ -webkit-justify-content: space-between;
13932
+ -ms-flex-pack: justify;
13933
+ justify-content: space-between;
13934
+ gap: 0.5rem;
13935
+ padding: 0.25rem 0.25rem 0.75rem;
13936
+ color: var(--md-sys-color-on-surface-variant);
13937
+ }
13938
+
13939
+ .kanban-column-title {
13940
+ margin: 0;
13941
+ font-size: 1rem;
13942
+ font-weight: 600;
13943
+ }
13944
+
13945
+ .kanban-column-count {
13946
+ display: -webkit-inline-box;
13947
+ display: -webkit-inline-flex;
13948
+ display: -ms-inline-flexbox;
13949
+ display: inline-flex;
13950
+ min-width: 1.5rem;
13951
+ min-height: 1.5rem;
13952
+ -webkit-box-align: center;
13953
+ -webkit-align-items: center;
13954
+ -ms-flex-align: center;
13955
+ align-items: center;
13956
+ -webkit-box-pack: center;
13957
+ -webkit-justify-content: center;
13958
+ -ms-flex-pack: center;
13959
+ justify-content: center;
13960
+ padding: 0 0.375rem;
13961
+ border-radius: 999px;
13962
+ background: var(--md-sys-color-surface);
13963
+ color: var(--md-sys-color-on-surface);
13964
+ font-size: 0.75rem;
13965
+ }
13966
+
13967
+ .kanban-column-body {
13968
+ display: -webkit-box;
13969
+ display: -webkit-flex;
13970
+ display: -ms-flexbox;
13971
+ display: flex;
13972
+ -webkit-box-flex: 1;
13973
+ -webkit-flex: 1 1 auto;
13974
+ -ms-flex: 1 1 auto;
13975
+ flex: 1 1 auto;
13976
+ -webkit-box-orient: vertical;
13977
+ -webkit-box-direction: normal;
13978
+ -webkit-flex-direction: column;
13979
+ -ms-flex-direction: column;
13980
+ flex-direction: column;
13981
+ gap: 0.75rem;
13982
+ min-height: 8rem;
13983
+ }
13984
+
13985
+ .kanban-card {
13986
+ --kanban-card-accent: var(--md-sys-color-primary);
13987
+ position: relative;
13988
+ display: -webkit-box;
13989
+ display: -webkit-flex;
13990
+ display: -ms-flexbox;
13991
+ display: flex;
13992
+ -webkit-box-orient: vertical;
13993
+ -webkit-box-direction: normal;
13994
+ -webkit-flex-direction: column;
13995
+ -ms-flex-direction: column;
13996
+ flex-direction: column;
13997
+ gap: 0.625rem;
13998
+ padding: 1rem;
13999
+ border: 1px solid var(--md-sys-color-outline-variant);
14000
+ border-radius: 0.75rem;
14001
+ background: var(--md-sys-color-surface);
14002
+ color: var(--md-sys-color-on-surface);
14003
+ -webkit-box-shadow: var(--md-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, 0.14));
14004
+ box-shadow: var(--md-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, 0.14));
14005
+ cursor: -webkit-grab;
14006
+ cursor: grab;
14007
+ -webkit-user-select: none;
14008
+ -moz-user-select: none;
14009
+ -ms-user-select: none;
14010
+ user-select: none;
14011
+ overflow: hidden;
14012
+ -webkit-transition: opacity 160ms ease, -webkit-transform 160ms ease, -webkit-box-shadow 160ms ease;
14013
+ transition: opacity 160ms ease, -webkit-transform 160ms ease, -webkit-box-shadow 160ms ease;
14014
+ transition: transform 160ms ease, opacity 160ms ease, box-shadow 160ms ease;
14015
+ transition: transform 160ms ease, opacity 160ms ease, box-shadow 160ms ease, -webkit-transform 160ms ease, -webkit-box-shadow 160ms ease;
14016
+ }
14017
+ .kanban-card:active, .kanban-card.is-dragging {
14018
+ cursor: -webkit-grabbing;
14019
+ cursor: grabbing;
14020
+ }
14021
+ .kanban-card.is-dragging {
14022
+ opacity: 0.45;
14023
+ -webkit-box-shadow: var(--md-sys-elevation-level3, 0 8px 18px rgba(0, 0, 0, 0.2));
14024
+ box-shadow: var(--md-sys-elevation-level3, 0 8px 18px rgba(0, 0, 0, 0.2));
14025
+ }
14026
+ .kanban-card:focus-visible {
14027
+ outline: 2px solid var(--md-sys-color-primary);
14028
+ outline-offset: 2px;
14029
+ }
14030
+ .kanban-card.kanban-card-accent::after {
14031
+ position: absolute;
14032
+ right: 0;
14033
+ bottom: 0;
14034
+ left: 0;
14035
+ height: 0.25rem;
14036
+ background: var(--kanban-card-accent);
14037
+ content: "";
14038
+ pointer-events: none;
14039
+ }
14040
+ .kanban-card.kanban-card-accent-top::after {
14041
+ top: 0;
14042
+ bottom: auto;
14043
+ left: 0;
14044
+ width: 100%;
14045
+ height: 0.25rem;
14046
+ }
14047
+ .kanban-card.kanban-card-accent-right::after {
14048
+ top: 0;
14049
+ right: 0;
14050
+ bottom: 0;
14051
+ left: auto;
14052
+ width: 0.25rem;
14053
+ height: 100%;
14054
+ }
14055
+ .kanban-card.kanban-card-accent-left::after {
14056
+ top: 0;
14057
+ right: auto;
14058
+ bottom: 0;
14059
+ left: 0;
14060
+ width: 0.25rem;
14061
+ height: 100%;
14062
+ }
14063
+ .kanban-card.is-disabled, .kanban-card[aria-disabled=true] {
14064
+ cursor: not-allowed;
14065
+ opacity: 0.55;
14066
+ -webkit-filter: saturate(0.55);
14067
+ filter: saturate(0.55);
14068
+ }
14069
+
14070
+ .kanban-drag-image {
14071
+ position: fixed !important;
14072
+ top: -10000px !important;
14073
+ left: -10000px !important;
14074
+ z-index: -1;
14075
+ pointer-events: none;
14076
+ -webkit-transform: rotate(2deg) scale(1.015);
14077
+ transform: rotate(2deg) scale(1.015);
14078
+ -webkit-transform-origin: center;
14079
+ transform-origin: center;
14080
+ }
14081
+
14082
+ .kanban-drop-preview {
14083
+ min-height: 4rem;
14084
+ -webkit-box-sizing: border-box;
14085
+ box-sizing: border-box;
14086
+ border: 2px dashed var(--md-sys-color-primary);
14087
+ border-radius: 0.75rem;
14088
+ background: color-mix(in srgb, var(--md-sys-color-primary-container) 45%, transparent);
14089
+ pointer-events: none;
14090
+ }
14091
+
14092
+ .kanban-card-title {
14093
+ margin: 0;
14094
+ font-size: 1rem;
14095
+ font-weight: 600;
14096
+ }
14097
+
14098
+ .kanban-card-description {
14099
+ margin: 0;
14100
+ color: var(--md-sys-color-on-surface-variant);
14101
+ font-size: 0.875rem;
14102
+ }
14103
+
14104
+ .kanban-card-meta {
14105
+ display: -webkit-box;
14106
+ display: -webkit-flex;
14107
+ display: -ms-flexbox;
14108
+ display: flex;
14109
+ -webkit-box-align: center;
14110
+ -webkit-align-items: center;
14111
+ -ms-flex-align: center;
14112
+ align-items: center;
14113
+ -webkit-box-pack: justify;
14114
+ -webkit-justify-content: space-between;
14115
+ -ms-flex-pack: justify;
14116
+ justify-content: space-between;
14117
+ gap: 0.5rem;
14118
+ color: var(--md-sys-color-on-surface-variant);
14119
+ font-size: 0.75rem;
14120
+ }
14121
+
14122
+ .kanban-card-label {
14123
+ display: -webkit-inline-box;
14124
+ display: -webkit-inline-flex;
14125
+ display: -ms-inline-flexbox;
14126
+ display: inline-flex;
14127
+ -webkit-box-align: center;
14128
+ -webkit-align-items: center;
14129
+ -ms-flex-align: center;
14130
+ align-items: center;
14131
+ -webkit-align-self: flex-start;
14132
+ -ms-flex-item-align: start;
14133
+ align-self: flex-start;
14134
+ padding: 0.1875rem 0.5rem;
14135
+ border-radius: 999px;
14136
+ background: var(--md-sys-color-secondary-container);
14137
+ color: var(--md-sys-color-on-secondary-container);
14138
+ font-size: 0.75rem;
14139
+ }
14140
+
14141
+ .kanban-empty {
14142
+ display: grid;
14143
+ min-height: 5rem;
14144
+ place-items: center;
14145
+ border: 1px dashed var(--md-sys-color-outline);
14146
+ border-radius: 0.625rem;
14147
+ color: var(--md-sys-color-on-surface-variant);
14148
+ font-size: 0.875rem;
14149
+ }
14150
+
14151
+ @media (max-width: 600px) {
14152
+ .kanban-board {
14153
+ --kanban-column-width: min(20rem, calc(100vw - 3rem));
14154
+ }
14155
+ }
13866
14156
  .collapsible {
13867
14157
  padding-left: 0;
13868
14158
  list-style-type: none;