@khipu/design-system 0.2.0-alpha.22 → 0.2.0-alpha.24

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.
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * AUTO-GENERATED FILE - DO NOT EDIT MANUALLY
13
13
  * Source: design-system/src/tokens/tokens.json
14
- * Generated: 2026-05-25T18:59:02.134Z
14
+ * Generated: 2026-05-27T17:53:25.694Z
15
15
  *
16
16
  * To regenerate:
17
17
  * cd design-system && npm run tokens:generate
@@ -1073,63 +1073,90 @@ a.kds-btn.kds-btn-md {
1073
1073
  }
1074
1074
  }
1075
1075
 
1076
- /* Selection card */
1076
+ /* Selection card.
1077
+ IMPORTANTE: este componente se renderiza como `<button>`. BeerCSS aplica al
1078
+ `button` base: `display: inline-flex; align-items: center; justify-content: center;
1079
+ block-size: 2.5rem; padding: 0 1rem; background: var(--primary); color: on-primary`.
1080
+ Todas esas reglas hay que sobreescribirlas para que el card-selector funcione como
1081
+ un contenedor flex column de altura variable y alineado a la izquierda.
1082
+
1083
+ Convención del DS: spacing entre hijos via `gap` del flex padre + padding.
1084
+ Los elementos internos (.kds-card-selector-icon/-title/-description) NO usan margin. */
1077
1085
  .kds-card-selector {
1086
+ /* Reset BeerCSS button */
1087
+ display: flex;
1088
+ flex-direction: column;
1089
+ align-items: stretch;
1090
+ justify-content: flex-start;
1091
+ block-size: auto;
1092
+ inline-size: 100%;
1093
+ text-align: left;
1094
+ line-height: 1.5;
1095
+ color: var(--kds-color-text-primary);
1096
+ /* Estilos propios del card-selector */
1078
1097
  padding: var(--kds-spacing-3);
1098
+ gap: var(--kds-spacing-1-5);
1079
1099
  border-radius: var(--kds-radius-md);
1080
- border: 2px solid var(--kds-border-light);
1100
+ border: var(--kds-border-width-md) solid var(--kds-border-light);
1081
1101
  background: var(--kds-color-background-paper);
1082
1102
  transition: all 0.3s ease;
1083
- text-align: left;
1084
1103
  cursor: pointer;
1085
- display: flex;
1086
- flex-direction: column;
1087
1104
  }
1088
1105
 
1089
- .kds-card-selector:hover {
1090
- border-color: #D1D5DB; /* gray-300 */
1106
+ .kds-card-selector:hover:not(.selected) {
1107
+ border-color: var(--kds-color-primary-light);
1108
+ background: var(--kds-color-primary-hover);
1109
+ }
1110
+
1111
+ /* Override del ripple/overlay default de BeerCSS:
1112
+ `:is(.wave,.chip,.button,button,nav.tabbed>a,...):not([class*=ripple])::after`
1113
+ tiene specificity (0,2,4) según DevTools (Chrome cuenta cada selector dentro
1114
+ de :is() individualmente para algunos motores). Usamos !important — consistente
1115
+ con cómo se overridean otros estilos de BeerCSS en este archivo (67 usos previos).
1116
+ Antes pintaba negro porque `currentColor` resolvía a text-primary del card. */
1117
+ .kds-card-selector::after {
1118
+ background-image: radial-gradient(circle, var(--kds-color-primary-main) 1%, transparent 1%) !important;
1091
1119
  }
1092
1120
 
1093
1121
  .kds-card-selector.selected {
1094
- border-color: #3B82F6; /* blue-600 */
1095
- background: #EFF6FF; /* blue-50 */
1122
+ border-color: var(--kds-color-primary-main);
1123
+ background: var(--kds-color-primary-faint);
1096
1124
  box-shadow: var(--kds-shadow-md);
1097
1125
  }
1098
1126
 
1099
- /* Icon container */
1127
+ /* Icon container — spacing manejado por gap del padre, no margin */
1100
1128
  .kds-card-selector-icon {
1101
- width: 48px;
1102
- height: 48px;
1103
- background: #DBEAFE; /* blue-100 */
1104
- border-radius: 8px;
1129
+ width: var(--kds-spacing-6);
1130
+ height: var(--kds-spacing-6);
1131
+ background: var(--kds-color-primary-focus);
1132
+ border-radius: var(--kds-radius-sm);
1105
1133
  display: flex;
1106
1134
  align-items: center;
1107
1135
  justify-content: center;
1108
- margin-bottom: 16px;
1109
1136
  }
1110
1137
 
1111
1138
  .kds-card-selector-icon i,
1112
1139
  .kds-card-selector-icon svg {
1113
- width: 24px;
1114
- height: 24px;
1115
- min-width: 24px;
1116
- min-height: 24px;
1117
- color: #3B82F6; /* blue-600 */
1140
+ width: var(--kds-spacing-3);
1141
+ height: var(--kds-spacing-3);
1142
+ min-width: var(--kds-spacing-3);
1143
+ min-height: var(--kds-spacing-3);
1144
+ font-size: var(--kds-spacing-3);
1145
+ color: var(--kds-color-primary-main);
1118
1146
  }
1119
1147
 
1120
- /* Title */
1148
+ /* Title — spacing manejado por gap del padre, no margin */
1121
1149
  .kds-card-selector-title {
1122
- font-weight: 600;
1150
+ font-weight: var(--kds-font-weight-semibold);
1123
1151
  color: var(--kds-color-text-primary);
1124
- margin-bottom: 8px;
1125
- font-size: 16px;
1152
+ font-size: var(--kds-font-size-lg);
1126
1153
  }
1127
1154
 
1128
1155
  /* Description */
1129
1156
  .kds-card-selector-description {
1130
- font-size: 14px;
1131
- color: #4B5563; /* gray-600 */
1132
- line-height: 1.5;
1157
+ font-size: var(--kds-font-size-sm);
1158
+ color: var(--kds-color-text-secondary);
1159
+ line-height: var(--kds-line-height-normal);
1133
1160
  }
1134
1161
 
1135
1162
  /* Selected state - visual feedback via border only */
@@ -1141,14 +1168,22 @@ a.kds-btn.kds-btn-md {
1141
1168
  display: flex;
1142
1169
  flex-direction: column;
1143
1170
  gap: var(--kds-spacing-2);
1144
- padding: var(--kds-spacing-4);
1171
+ padding: var(--kds-spacing-2);
1145
1172
  border-radius: var(--kds-radius-lg);
1146
1173
  border: 2px solid var(--kds-border-medium);
1147
- max-width: 400px; /* Increased from 365px for better text spacing */
1174
+ /* Ancho mínimo aplicado a TODOS los planes así un plan sin badge en una
1175
+ grilla con un plan recomendado mantiene la misma anchura, y el badge nunca
1176
+ se superpone al título por estrechez del card. */
1177
+ min-width: 260px;
1178
+ max-width: 400px;
1148
1179
  background: var(--kds-surface-base);
1149
1180
  transition: all 0.3s ease;
1150
1181
  cursor: pointer;
1151
- height: 100%; /* Ensure cards fill grid height */
1182
+ /* Alto fijo: el card se estira al alto de su row del grid (align-items stretch
1183
+ es el default) — todas las cards de la misma fila quedan a la misma altura
1184
+ sin importar el contenido. `align-self: stretch` lo hace explícito. */
1185
+ height: 100%;
1186
+ align-self: stretch;
1152
1187
  }
1153
1188
 
1154
1189
  .kds-card-plan:hover {
@@ -1168,18 +1203,19 @@ a.kds-btn.kds-btn-md {
1168
1203
  box-shadow: var(--kds-shadow-elevation-4);
1169
1204
  }
1170
1205
 
1171
- /* Recommended Badge */
1206
+ /* Recommended Badge — inline dentro del card (no flotante).
1207
+ Es el primer hijo del .kds-card-plan, así que aparece arriba de todo
1208
+ el contenido, alineado a la izquierda. */
1172
1209
  .kds-card-plan-badge {
1173
- position: absolute;
1174
- top: -12px;
1175
- right: var(--kds-spacing-6);
1176
- padding: var(--kds-spacing-1) var(--kds-spacing-4);
1210
+ align-self: flex-start;
1211
+ padding: var(--kds-spacing-0-5) var(--kds-spacing-1-5);
1177
1212
  background: var(--primary);
1178
1213
  color: white;
1179
- font-size: var(--kds-font-size-sm);
1214
+ font-size: var(--kds-font-size-xs);
1180
1215
  font-weight: var(--kds-font-weight-semibold);
1216
+ line-height: 1;
1181
1217
  border-radius: var(--kds-radius-full);
1182
- box-shadow: var(--kds-shadow-elevation-1);
1218
+ white-space: nowrap;
1183
1219
  }
1184
1220
 
1185
1221
  /* Plan Header */
@@ -1207,13 +1243,11 @@ a.kds-btn.kds-btn-md {
1207
1243
  display: flex;
1208
1244
  align-items: baseline;
1209
1245
  gap: var(--kds-spacing-2);
1210
- padding: var(--kds-spacing-4) 0;
1211
1246
  border-bottom: 1px solid var(--kds-border-light);
1212
- min-height: 88px; /* Standardize price area height */
1213
1247
  }
1214
1248
 
1215
1249
  .kds-price {
1216
- font-size: 42px;
1250
+ font-size: var(--kds-font-size-4xl);
1217
1251
  font-weight: var(--kds-font-weight-bold);
1218
1252
  color: var(--primary);
1219
1253
  line-height: 1.1;
@@ -2400,6 +2434,71 @@ body.dark {
2400
2434
  display: inline-flex;
2401
2435
  }
2402
2436
 
2437
+ /* ========================================
2438
+ Radix Tooltip (.kds-tooltip)
2439
+ Espejo de `.tooltip` pero para popovers de Radix:
2440
+ bg oscuro, texto blanco, sombra + animación fade/slide direccional.
2441
+ ======================================== */
2442
+
2443
+ .kds-tooltip {
2444
+ background-color: var(--kds-color-text-primary);
2445
+ color: var(--kds-color-background-paper);
2446
+ font-family: var(--kds-font-family-primary);
2447
+ font-size: var(--kds-font-size-xs);
2448
+ font-weight: var(--kds-font-weight-medium);
2449
+ line-height: var(--kds-line-height-normal);
2450
+ border-radius: var(--kds-radius-sm);
2451
+ padding: var(--kds-spacing-0-75) var(--kds-spacing-1-5);
2452
+ box-shadow: var(--kds-shadow-4);
2453
+ max-width: 280px;
2454
+ z-index: var(--kds-z-index-tooltip, 1500);
2455
+ user-select: none;
2456
+ /* Animación direccional según Radix data-side — coordinada con copy-row
2457
+ (cubic-bezier 0.2, 0.8, 0.2, 1) para un feel consistente del DS. */
2458
+ animation-duration: 240ms;
2459
+ animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
2460
+ will-change: transform, opacity;
2461
+ }
2462
+
2463
+ .kds-tooltip[data-state='closed'] {
2464
+ animation-duration: 140ms;
2465
+ animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
2466
+ }
2467
+
2468
+ /* Direccional según data-side (Radix añade el attr en runtime).
2469
+ Cada lado entra desde su dirección con ~8px de offset (más visible que 4px). */
2470
+ .kds-tooltip[data-side='top'][data-state='delayed-open'],
2471
+ .kds-tooltip[data-side='top'][data-state='instant-open'] { animation-name: kds-tooltip-in-top; }
2472
+ .kds-tooltip[data-side='bottom'][data-state='delayed-open'],
2473
+ .kds-tooltip[data-side='bottom'][data-state='instant-open'] { animation-name: kds-tooltip-in-bottom; }
2474
+ .kds-tooltip[data-side='left'][data-state='delayed-open'],
2475
+ .kds-tooltip[data-side='left'][data-state='instant-open'] { animation-name: kds-tooltip-in-left; }
2476
+ .kds-tooltip[data-side='right'][data-state='delayed-open'],
2477
+ .kds-tooltip[data-side='right'][data-state='instant-open'] { animation-name: kds-tooltip-in-right; }
2478
+
2479
+ /* Fallback cuando no hay data-side resuelto aún */
2480
+ .kds-tooltip[data-state='delayed-open']:not([data-side]),
2481
+ .kds-tooltip[data-state='instant-open']:not([data-side]) {
2482
+ animation-name: kds-tooltip-in-top;
2483
+ }
2484
+
2485
+ .kds-tooltip[data-state='closed'] { animation-name: kds-tooltip-out; }
2486
+
2487
+ @keyframes kds-tooltip-in-top { from { opacity: 0; transform: translateY(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2488
+ @keyframes kds-tooltip-in-bottom { from { opacity: 0; transform: translateY(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2489
+ @keyframes kds-tooltip-in-left { from { opacity: 0; transform: translateX(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2490
+ @keyframes kds-tooltip-in-right { from { opacity: 0; transform: translateX(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2491
+
2492
+ @keyframes kds-tooltip-out {
2493
+ from { opacity: 1; transform: none; }
2494
+ to { opacity: 0; transform: scale(0.96); }
2495
+ }
2496
+
2497
+ /* Arrow (SVG path generado por Radix) */
2498
+ .kds-tooltip-arrow {
2499
+ fill: var(--kds-color-text-primary);
2500
+ }
2501
+
2403
2502
  /* ========================================
2404
2503
  Material Symbols Icon Sizing
2405
2504
  ======================================== */
@@ -3116,6 +3215,32 @@ footer > .kds-container-center {
3116
3215
  color: var(--kds-color-error-dark);
3117
3216
  }
3118
3217
 
3218
+ /* Close button — icon-only, discreto, no usa kds-btn para no romper el flex layout del alert */
3219
+ .kds-alert-close {
3220
+ flex-shrink: 0;
3221
+ display: inline-flex;
3222
+ align-items: center;
3223
+ justify-content: center;
3224
+ width: 28px;
3225
+ height: 28px;
3226
+ padding: 0;
3227
+ background: transparent;
3228
+ border: 0;
3229
+ border-radius: 50%;
3230
+ color: inherit;
3231
+ cursor: pointer;
3232
+ transition: background-color 0.15s ease;
3233
+ }
3234
+
3235
+ .kds-alert-close:hover {
3236
+ background: rgba(0, 0, 0, 0.06);
3237
+ }
3238
+
3239
+ .kds-alert-close i {
3240
+ font-size: 18px;
3241
+ line-height: 1;
3242
+ }
3243
+
3119
3244
  /* Lists inside alerts */
3120
3245
  .kds-alert ul {
3121
3246
  padding-left: var(--kds-spacing-2);
@@ -4338,7 +4463,9 @@ dialog#surveyModal button.circle {
4338
4463
  ======================================== */
4339
4464
 
4340
4465
  .kds-badge {
4341
- display: inline-block;
4466
+ display: inline-flex;
4467
+ align-items: center;
4468
+ gap: 4px;
4342
4469
  padding: 2px 8px;
4343
4470
  border-radius: var(--kds-radius-sm);
4344
4471
  font-size: var(--kds-font-size-xs);
@@ -4346,6 +4473,40 @@ dialog#surveyModal button.circle {
4346
4473
  line-height: 1.5;
4347
4474
  }
4348
4475
 
4476
+ /* Icon prefix inside chip — small inline icon */
4477
+ .kds-badge > i.material-symbols-outlined {
4478
+ font-size: 14px;
4479
+ line-height: 1;
4480
+ }
4481
+
4482
+ /* Deletable chip close button — discreto, sin kds-btn (eso lo agrandaba ridículo) */
4483
+ .kds-badge-close {
4484
+ display: inline-flex;
4485
+ align-items: center;
4486
+ justify-content: center;
4487
+ width: 16px;
4488
+ height: 16px;
4489
+ margin-right: -2px;
4490
+ padding: 0;
4491
+ background: transparent;
4492
+ border: 0;
4493
+ border-radius: 50%;
4494
+ color: inherit;
4495
+ cursor: pointer;
4496
+ opacity: 0.7;
4497
+ transition: opacity 0.15s, background-color 0.15s;
4498
+ }
4499
+
4500
+ .kds-badge-close:hover {
4501
+ opacity: 1;
4502
+ background: rgba(0, 0, 0, 0.1);
4503
+ }
4504
+
4505
+ .kds-badge-close i {
4506
+ font-size: 14px;
4507
+ line-height: 1;
4508
+ }
4509
+
4349
4510
  .kds-badge.success {
4350
4511
  background-color: var(--kds-color-success-container);
4351
4512
  color: var(--kds-color-success-dark);
@@ -5239,11 +5400,11 @@ dialog#surveyModal button.circle {
5239
5400
  color: var(--kds-color-success-main);
5240
5401
  }
5241
5402
 
5242
- /* Variant: pending (animated spinner) */
5403
+ /* Variant: pending (animated blue spinner, sin icono interno) */
5243
5404
  .kds-status-block[data-status="pending"] .kds-status-block-icon {
5244
5405
  background: transparent;
5245
5406
  border: 3px solid var(--kds-color-divider);
5246
- border-top-color: var(--kds-color-primary-main);
5407
+ border-top-color: var(--kds-color-info-main);
5247
5408
  animation: kds-spin 1s linear infinite;
5248
5409
  }
5249
5410
 
@@ -5261,7 +5422,9 @@ dialog#surveyModal button.circle {
5261
5422
  color: var(--kds-color-error-main);
5262
5423
  }
5263
5424
 
5264
- /* Variant: info */
5425
+ /* Variant: info — usar SIEMPRE con icon "info_i" (i minúscula sin glyph circular)
5426
+ para que solo se vea nuestro círculo decorativo. Iconos como "info" tienen
5427
+ su propio círculo built-in → causarían doble círculo. */
5265
5428
  .kds-status-block[data-status="info"] .kds-status-block-icon {
5266
5429
  background: var(--kds-color-info-soft);
5267
5430
  border: var(--kds-border-width-md) solid var(--kds-color-info-main);
@@ -5335,6 +5498,40 @@ dialog#surveyModal button.circle {
5335
5498
  background: var(--kds-color-divider);
5336
5499
  }
5337
5500
 
5501
+ /* Close button — top-right discreto, NO usa kds-btn (rompía el flex layout) */
5502
+ .kds-bottom-sheet-close {
5503
+ position: absolute;
5504
+ top: var(--kds-spacing-1);
5505
+ right: var(--kds-spacing-1);
5506
+ width: 32px;
5507
+ height: 32px;
5508
+ display: inline-flex;
5509
+ align-items: center;
5510
+ justify-content: center;
5511
+ padding: 0;
5512
+ background: transparent;
5513
+ border: 0;
5514
+ border-radius: 50%;
5515
+ color: var(--kds-color-text-secondary);
5516
+ cursor: pointer;
5517
+ transition: background-color 0.15s ease;
5518
+ }
5519
+
5520
+ .kds-bottom-sheet-close:hover {
5521
+ background: rgba(0, 0, 0, 0.06);
5522
+ }
5523
+
5524
+ .kds-bottom-sheet-close i {
5525
+ font-size: 20px;
5526
+ line-height: 1;
5527
+ }
5528
+
5529
+ /* Body container — separa el content del title/actions */
5530
+ .kds-bottom-sheet-body {
5531
+ text-align: left;
5532
+ margin-top: var(--kds-spacing-1);
5533
+ }
5534
+
5338
5535
  .kds-bottom-sheet-icon {
5339
5536
  font-size: var(--kds-font-size-4xl);
5340
5537
  }
@@ -6283,10 +6480,17 @@ button.kds-btn-success::after {
6283
6480
  padding-bottom: var(--kds-spacing-2);
6284
6481
  }
6285
6482
 
6286
- /* Invoice sticky card: progressive padding-top (expanded 20px → collapsed 8px).
6287
- Overrides base rule at same specificity; source order wins here. */
6483
+ /* Invoice sticky card padding (mobile).
6484
+ Top: estático 12px. Bottom: progresivo 20px (expandido) 8px (colapsado).
6485
+ El padding-bottom animado da breathing room natural cuando expandido y se
6486
+ reduce convencionalmente al colapsar — sin depender de que el clip-path
6487
+ corte el padding abruptamente. */
6288
6488
  .kds-payment-flow .kds-card-elevated.kds-invoice-sticky {
6289
6489
  padding-top: var(--kds-spacing-1-5);
6490
+ padding-bottom: calc(
6491
+ var(--kds-spacing-2-5)
6492
+ - var(--kds-spacing-1-5) * var(--collapse-progress, 0)
6493
+ );
6290
6494
  }
6291
6495
 
6292
6496
 
@@ -6732,6 +6936,11 @@ button.kds-btn-success::after {
6732
6936
  font-family: var(--kds-font-family-primary);
6733
6937
  font-size: var(--kds-font-size-caption);
6734
6938
  color: var(--kds-color-text-secondary);
6939
+ /* Trunca con ellipsis en lugar de wrap a 2 líneas — evita apretar el row
6940
+ cuando el contenedor es angosto (mobile o decorator constrained). */
6941
+ overflow: hidden;
6942
+ text-overflow: ellipsis;
6943
+ white-space: nowrap;
6735
6944
  }
6736
6945
 
6737
6946
  /* QR Badge - "Rápido" indicator */
@@ -6754,46 +6963,26 @@ button.kds-btn-success::after {
6754
6963
  font-size: 20px;
6755
6964
  }
6756
6965
 
6757
- /* Mobile responsive: Ajustes para pantallas pequeñas */
6966
+ /* Mobile responsive (≤480px): respira más mantenemos padding/gap/avatar igual
6967
+ que desktop y solo agregamos truncation al subtitle y `flex-shrink: 0` en los
6968
+ ítems que deben mantener su tamaño (avatar, badge, chevron). */
6758
6969
  @media (max-width: 480px) {
6759
- .kds-qr-row {
6760
- gap: var(--kds-spacing-1-5);
6761
- padding: var(--kds-spacing-1-5);
6762
- }
6763
-
6764
6970
  .kds-qr-avatar {
6765
- width: var(--kds-spacing-4-5);
6766
- height: var(--kds-spacing-4-5);
6767
6971
  flex-shrink: 0;
6768
6972
  }
6769
6973
 
6770
- .kds-qr-avatar .material-symbols-outlined,
6771
- .kds-qr-avatar .material-icons-round {
6772
- font-size: var(--kds-font-size-lg);
6773
- }
6774
-
6775
- .kds-qr-text .title {
6776
- font-size: var(--kds-font-size-xs);
6777
- line-height: var(--kds-line-height-tight);
6778
- }
6779
-
6780
6974
  .kds-qr-text .sub {
6781
- font-size: var(--kds-font-size-caption);
6782
- line-height: var(--kds-line-height-tight);
6783
6975
  overflow: hidden;
6784
6976
  text-overflow: ellipsis;
6785
6977
  white-space: nowrap;
6786
6978
  }
6787
6979
 
6788
6980
  .kds-qr-badge {
6789
- font-size: var(--kds-font-size-caption);
6790
- padding: var(--kds-spacing-0-25) var(--kds-spacing-0-75);
6791
6981
  flex-shrink: 0;
6792
6982
  }
6793
6983
 
6794
6984
  .kds-qr-row .material-symbols-outlined:last-child,
6795
6985
  .kds-qr-row .material-icons-round:last-child {
6796
- font-size: var(--kds-font-size-base);
6797
6986
  flex-shrink: 0;
6798
6987
  }
6799
6988
  }
@@ -6822,7 +7011,11 @@ button.kds-btn-success::after {
6822
7011
  border-radius: var(--kds-spacing-0-75);
6823
7012
  font-size: var(--kds-font-size-sm);
6824
7013
  cursor: pointer;
6825
- transition: background 0.12s ease;
7014
+ /* Transición más amplia y suave: bg + color + border ease-out */
7015
+ transition:
7016
+ background-color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
7017
+ color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
7018
+ border-top-color 280ms ease-out;
6826
7019
  position: relative;
6827
7020
  user-select: none;
6828
7021
  }
@@ -6831,15 +7024,17 @@ button.kds-btn-success::after {
6831
7024
  border-top: 0;
6832
7025
  }
6833
7026
 
6834
- .kds-copyable-table-row:hover {
7027
+ /* Hover NO aplica mientras la row esté en `.copied` o `.settling`
7028
+ (evita el flicker del hover state al desaparecer el verde de "copiado") */
7029
+ .kds-copyable-table-row:not(.copied):not(.settling):hover {
6835
7030
  background: var(--kds-color-primary-faint);
6836
7031
  }
6837
7032
 
6838
- .kds-copyable-table-row:hover + .kds-copyable-table-row {
7033
+ .kds-copyable-table-row:not(.copied):not(.settling):hover + .kds-copyable-table-row {
6839
7034
  border-top-color: transparent;
6840
7035
  }
6841
7036
 
6842
- .kds-copyable-table-row:active {
7037
+ .kds-copyable-table-row:not(.copied):not(.settling):active {
6843
7038
  background: var(--kds-color-primary-selected);
6844
7039
  }
6845
7040
 
@@ -6874,11 +7069,12 @@ button.kds-btn-success::after {
6874
7069
  font-size: var(--kds-font-size-sm);
6875
7070
  color: var(--kds-color-primary-main);
6876
7071
  opacity: 0;
6877
- transition: opacity 0.12s ease;
7072
+ /* Transición coordinada con la row */
7073
+ transition: opacity 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
6878
7074
  flex: 0 0 auto;
6879
7075
  }
6880
7076
 
6881
- .kds-copyable-table-row:hover .v::after {
7077
+ .kds-copyable-table-row:not(.copied):not(.settling):hover .v::after {
6882
7078
  opacity: 0.7;
6883
7079
  }
6884
7080
 
@@ -6897,6 +7093,14 @@ button.kds-btn-success::after {
6897
7093
  opacity: 1;
6898
7094
  }
6899
7095
 
7096
+ /* `.settling`: estado de "recién copiado" — la row vuelve al normal sin
7097
+ activar hover. Dura lo mismo que la transición (~300ms) y se aplica
7098
+ desde React tras quitar `.copied`. */
7099
+ .kds-copyable-table-row.settling .v::after {
7100
+ /* Mantén el check con opacity 0 mientras settling, fade out suave */
7101
+ opacity: 0;
7102
+ }
7103
+
6900
7104
  /* Disable BeerCSS ripple on copyable table rows */
6901
7105
  .kds-copyable-table-row::after {
6902
7106
  display: none;