@khipu/design-system 0.1.0-alpha.56 → 0.2.0-alpha.100

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-04T19:11:26.827Z
14
+ * Generated: 2026-07-07T13:01:50.848Z
15
15
  *
16
16
  * To regenerate:
17
17
  * cd design-system && npm run tokens:generate
@@ -48,15 +48,21 @@
48
48
  --kds-color-success-main: #2E7D32;
49
49
  --kds-color-success-light: #4CAF50;
50
50
  --kds-color-success-dark: #1B5E20;
51
+ --kds-color-success-contrast: #FFFFFF;
51
52
  --kds-color-warning-main: #EF6C00;
52
53
  --kds-color-warning-light: #FF9800;
53
54
  --kds-color-warning-dark: #E65100;
55
+ --kds-color-warning-contrast: #FFFFFF;
56
+ --kds-color-warning-warm: #8A6D1A;
54
57
  --kds-color-error-main: #D32F2F;
55
58
  --kds-color-error-light: #EF5350;
56
59
  --kds-color-error-dark: #C62828;
60
+ --kds-color-error-contrast: #FFFFFF;
57
61
  --kds-color-info-main: #0288D1;
58
62
  --kds-color-info-light: #03A9F4;
59
63
  --kds-color-info-dark: #01579B;
64
+ --kds-color-info-contrast: #FFFFFF;
65
+ --kds-color-info-blue: #5A5FE0;
60
66
 
61
67
  /* Text colors */
62
68
  --kds-color-text-primary: #333333;
@@ -133,15 +139,8 @@
133
139
  --kds-font-weight-semibold: 600;
134
140
  --kds-font-weight-bold: 700;
135
141
 
136
- /* Font sizes */
137
- --kds-font-size-xs: 0.75rem;
138
- --kds-font-size-sm: 0.875rem;
139
- --kds-font-size-base: 1rem;
140
- --kds-font-size-lg: 1.125rem;
141
- --kds-font-size-xl: 1.25rem;
142
- --kds-font-size-2xl: 1.5rem;
143
- --kds-font-size-3xl: 1.875rem;
144
- --kds-font-size-4xl: 2.25rem;
142
+ /* Font sizes (base scale xs–4xl: see responsive section below) */
143
+ --kds-font-size-decimal-sup: 0.5em;
145
144
 
146
145
  /* Line heights */
147
146
  --kds-line-height-tight: 1.2;
@@ -156,9 +155,9 @@
156
155
  --kds-letter-spacing-widest: 1px;
157
156
 
158
157
  /* Button typography */
159
- --kds-typography-button-font-size: 0.9375rem;
158
+ --kds-typography-button-font-size: 0.875rem;
160
159
  --kds-typography-button-font-weight: 500;
161
- --kds-typography-button-line-height: 26px;
160
+ --kds-typography-button-line-height: 1.5;
162
161
  --kds-typography-button-letter-spacing: 0.46px;
163
162
 
164
163
  /* Typography margins */
@@ -208,10 +207,10 @@
208
207
  --kds-spacing-input-padding-y: 16px;
209
208
  --kds-spacing-input-padding-x: 12px;
210
209
  --kds-spacing-input-padding: 16px 12px;
211
- --kds-spacing-button-padding-y: 8px;
212
- --kds-spacing-button-padding-x: 22px;
213
- --kds-spacing-button-padding: 8px 22px;
214
- --kds-spacing-button-min-height: 50px;
210
+ --kds-spacing-button-padding-y: 0;
211
+ --kds-spacing-button-padding-x: 16px;
212
+ --kds-spacing-button-padding: 0 16px;
213
+ --kds-spacing-button-min-height: 44px;
215
214
  --kds-spacing-button-icon-size: 20px;
216
215
  --kds-spacing-sidebar-width: 280px;
217
216
  --kds-spacing-sidebar-width-collapsed: 72px;
@@ -250,7 +249,7 @@
250
249
  --kds-radius-full: 9999px;
251
250
 
252
251
  /* Component-specific radii */
253
- --kds-radius-button: 4px;
252
+ --kds-radius-button: 10px;
254
253
  --kds-radius-input: 4px;
255
254
  --kds-radius-card: 14px;
256
255
  --kds-radius-modal: 20px;
@@ -364,6 +363,17 @@
364
363
  RESPONSIVE TYPOGRAPHY (MOBILE BASE)
365
364
  ========================================================================== */
366
365
 
366
+ --kds-font-size-2xs: 0.5625rem;
367
+
368
+ /* Base font-size scale */
369
+ --kds-font-size-xs: 0.6875rem;
370
+ --kds-font-size-sm: 0.8125rem;
371
+ --kds-font-size-base: 0.875rem;
372
+ --kds-font-size-lg: 1rem;
373
+ --kds-font-size-xl: 1.125rem;
374
+ --kds-font-size-2xl: 1.25rem;
375
+ --kds-font-size-3xl: 1.5rem;
376
+ --kds-font-size-4xl: 1.875rem;
367
377
 
368
378
  /* Headings */
369
379
  --kds-font-size-h1: 1.75rem;
@@ -401,6 +411,17 @@
401
411
  /* Tablet (600px+) - Typography */
402
412
  @media (min-width: 600px) {
403
413
  :root {
414
+ --kds-font-size-2xs: 0.625rem;
415
+
416
+ /* Base font-size scale */
417
+ --kds-font-size-xs: 0.75rem;
418
+ --kds-font-size-sm: 0.875rem;
419
+ --kds-font-size-base: 1rem;
420
+ --kds-font-size-lg: 1.125rem;
421
+ --kds-font-size-xl: 1.25rem;
422
+ --kds-font-size-2xl: 1.5rem;
423
+ --kds-font-size-3xl: 1.875rem;
424
+ --kds-font-size-4xl: 2.25rem;
404
425
  --kds-font-size-h1: 2rem;
405
426
  --kds-font-size-h2: 1.75rem;
406
427
  --kds-font-size-h3: 1.5rem;
@@ -428,6 +449,17 @@
428
449
  /* Desktop (840px+) - Typography */
429
450
  @media (min-width: 840px) {
430
451
  :root {
452
+ --kds-font-size-2xs: 0.625rem;
453
+
454
+ /* Base font-size scale */
455
+ --kds-font-size-xs: 0.75rem;
456
+ --kds-font-size-sm: 0.875rem;
457
+ --kds-font-size-base: 1rem;
458
+ --kds-font-size-lg: 1.125rem;
459
+ --kds-font-size-xl: 1.25rem;
460
+ --kds-font-size-2xl: 1.5rem;
461
+ --kds-font-size-3xl: 1.875rem;
462
+ --kds-font-size-4xl: 2.25rem;
431
463
  --kds-font-size-h1: 2.5rem;
432
464
  --kds-font-size-h2: 2rem;
433
465
  --kds-font-size-h3: 1.75rem;
@@ -622,6 +654,7 @@ body.dark {
622
654
  /* Scroll Container Utilities */
623
655
  --kds-scroll-sm-height: 280px;
624
656
  --kds-scroll-md-height: 420px;
657
+
625
658
  --kds-scroll-lg-height: 600px;
626
659
 
627
660
  /* Stage Layout */
@@ -734,7 +767,7 @@ footer {
734
767
  ======================================== */
735
768
  :root {
736
769
  /* Scroll-linked collapse range (mobile sticky invoice) */
737
- --kds-scroll-collapse-end: 150px;
770
+ --kds-scroll-collapse-end: 60px;
738
771
 
739
772
  /* Merchant tile: normal and collapsed sizes (from source prototype) */
740
773
  --kds-merchant-size: 64px;
@@ -756,6 +789,10 @@ footer {
756
789
  * Source: design.khipu.com and Material Design 3 specifications
757
790
  */
758
791
 
792
+ * {
793
+ border-radius: 0;
794
+ }
795
+
759
796
 
760
797
  :has(>main) {
761
798
  background-color: transparent !important;
@@ -799,34 +836,45 @@ a.kds-btn {
799
836
  align-items: center;
800
837
  justify-content: center;
801
838
  gap: 8px;
839
+ text-align: center;
840
+ width: 100%;
802
841
 
803
842
  /* Typography - Using design tokens */
804
843
  font-family: var(--kds-font-family-secondary);
805
- font-weight: var(--kds-font-weight-medium); /* 500, no 600 */
806
- font-size: var(--kds-typography-button-font-size); /* 0.9375rem = 15px */
807
- line-height: var(--kds-typography-button-line-height); /* 26px, no 1 */
844
+ font-weight: var(--kds-font-weight-medium); /* 500 */
845
+ font-size: var(--kds-typography-button-font-size); /* 0.875rem = 14px */
846
+ line-height: var(--kds-typography-button-line-height); /* 1.5 */
808
847
  letter-spacing: var(--kds-typography-button-letter-spacing); /* 0.46px */
809
848
  text-transform: uppercase;
810
849
 
811
850
  /* Spacing - Using design tokens */
812
- padding: var(--kds-spacing-button-padding); /* 8px 22px */
813
- min-height: var(--kds-spacing-button-min-height); /* 50px */
814
- height: auto; /* Remove fixed height, let content + padding define it */
851
+ padding: var(--kds-spacing-button-padding); /* 0 16px */
852
+ height: var(--kds-spacing-button-min-height); /* 44px */
853
+ /* min-height además de height: en contenedores flex-column (p.ej. pantallas de
854
+ resultado/timeout) el botón es flex-item y, con solo `height`, flex-shrink lo
855
+ colapsaba a la altura del texto (~21px). min-height impide que se encoja. */
856
+ min-height: var(--kds-spacing-button-min-height); /* 44px */
815
857
 
816
858
  /* Border - Using design token */
817
- border-radius: var(--kds-radius-button); /* 4px */
859
+ border-radius: var(--kds-radius-button); /* 10px */
818
860
  border: none;
819
861
 
820
862
  /* Interaction */
821
863
  cursor: pointer;
822
- transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1),
823
- box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1),
824
- border-color 250ms cubic-bezier(0.4, 0, 0.2, 1),
825
- color 250ms cubic-bezier(0.4, 0, 0.2, 1);
864
+ transition: background-color var(--kds-transition-shorter) var(--kds-easing-standard),
865
+ color var(--kds-transition-shorter) var(--kds-easing-standard),
866
+ box-shadow var(--kds-transition-shorter) var(--kds-easing-standard),
867
+ transform var(--kds-transition-shortest) var(--kds-easing-standard);
826
868
  box-sizing: border-box;
827
869
  vertical-align: middle;
828
870
  }
829
871
 
872
+ /* Active state - add subtle press effect */
873
+ button.kds-btn:active:not(:disabled),
874
+ a.kds-btn:active:not(:disabled) {
875
+ transform: translateY(1px);
876
+ }
877
+
830
878
  /* Disabled state - colores específicos en lugar de opacity */
831
879
  button.kds-btn:disabled,
832
880
  a.kds-btn:disabled {
@@ -844,18 +892,13 @@ a.kds-btn-primary {
844
892
  background: var(--kds-color-primary-main); /* #8347AD */
845
893
  color: white;
846
894
  border: none;
847
- box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2),
848
- 0px 2px 2px 0px rgba(0, 0, 0, 0.14),
849
- 0px 1px 5px 0px rgba(0, 0, 0, 0.12); /* elevation/2 */
895
+ box-shadow: 0 1px 2px rgba(131, 71, 173, .25);
850
896
  }
851
897
 
852
- /* Hover State - background más oscuro + elevation/4 */
898
+ /* Hover State - background más oscuro */
853
899
  button.kds-btn-primary:hover:not(:disabled),
854
900
  a.kds-btn-primary:hover:not(:disabled) {
855
- background: var(--kds-color-primary-dark); /* #6A3A8C */
856
- box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2),
857
- 0px 4px 5px 0px rgba(0, 0, 0, 0.14),
858
- 0px 1px 10px 0px rgba(0, 0, 0, 0.12); /* elevation/4 */
901
+ background: var(--kds-color-primary-dark); /* #5B3179 */
859
902
  }
860
903
 
861
904
  /* Active/Focus State */
@@ -953,7 +996,7 @@ a.kds-btn-text {
953
996
 
954
997
  button.kds-btn-text:hover:not(:disabled),
955
998
  a.kds-btn-text:hover:not(:disabled) {
956
- background: var(--kds-color-primary-hover); /* rgba(131, 71, 173, 0.04) */
999
+ color: var(--kds-color-primary-dark);
957
1000
  }
958
1001
 
959
1002
  button.kds-btn-text:disabled,
@@ -963,6 +1006,30 @@ a.kds-btn-text:disabled {
963
1006
  box-shadow: none;
964
1007
  }
965
1008
 
1009
+ /* Error text (destructive, ghost) — red text, no fill/border. Para acciones
1010
+ destructivas secundarias que no deben competir con el CTA primario. */
1011
+ button.kds-btn-error-text,
1012
+ a.kds-btn-error-text {
1013
+ background: transparent;
1014
+ color: var(--kds-color-error-main);
1015
+ border: none;
1016
+ padding: 6px var(--kds-spacing-2);
1017
+ min-height: 32px;
1018
+ box-shadow: none;
1019
+ }
1020
+
1021
+ button.kds-btn-error-text:hover:not(:disabled),
1022
+ a.kds-btn-error-text:hover:not(:disabled) {
1023
+ color: var(--kds-color-error-dark);
1024
+ }
1025
+
1026
+ button.kds-btn-error-text:disabled,
1027
+ a.kds-btn-error-text:disabled {
1028
+ background: transparent;
1029
+ color: var(--kds-color-action-disabled);
1030
+ box-shadow: none;
1031
+ }
1032
+
966
1033
  /* Icon wrapper - control size via span container */
967
1034
  button.kds-btn > .kds-icon,
968
1035
  a.kds-btn > .kds-icon {
@@ -984,7 +1051,12 @@ a.kds-btn > .kds-icon > i {
984
1051
  min-width: var(--kds-spacing-button-icon-size);
985
1052
  min-height: var(--kds-spacing-button-icon-size);
986
1053
  line-height: 1;
987
- top: 1px;
1054
+ }
1055
+
1056
+ /* Full-width button */
1057
+ button.kds-btn.kds-btn-block,
1058
+ a.kds-btn.kds-btn-block {
1059
+ width: 100%;
988
1060
  }
989
1061
 
990
1062
  /* ========================================
@@ -1008,12 +1080,6 @@ a.kds-btn.kds-btn-md {
1008
1080
 
1009
1081
  /* Default .kds-btn uses --kds-spacing-button-min-height (50px) from base styles */
1010
1082
 
1011
- /* Full-width button */
1012
- button.kds-btn.kds-btn-block,
1013
- a.kds-btn.kds-btn-block {
1014
- width: 100%;
1015
- }
1016
-
1017
1083
  /* ========================================
1018
1084
  Card Components (Material Design 3)
1019
1085
  ======================================== */
@@ -1026,6 +1092,7 @@ a.kds-btn.kds-btn-block {
1026
1092
  padding: var(--kds-spacing-2);
1027
1093
  box-shadow: var(--kds-shadow-card);
1028
1094
  transition: box-shadow 0.3s ease;
1095
+ margin-block-start: 0 !important;
1029
1096
  }
1030
1097
 
1031
1098
  .kds-card-elevated:hover,
@@ -1048,63 +1115,90 @@ a.kds-btn.kds-btn-block {
1048
1115
  }
1049
1116
  }
1050
1117
 
1051
- /* Selection card */
1118
+ /* Selection card.
1119
+ IMPORTANTE: este componente se renderiza como `<button>`. BeerCSS aplica al
1120
+ `button` base: `display: inline-flex; align-items: center; justify-content: center;
1121
+ block-size: 2.5rem; padding: 0 1rem; background: var(--primary); color: on-primary`.
1122
+ Todas esas reglas hay que sobreescribirlas para que el card-selector funcione como
1123
+ un contenedor flex column de altura variable y alineado a la izquierda.
1124
+
1125
+ Convención del DS: spacing entre hijos via `gap` del flex padre + padding.
1126
+ Los elementos internos (.kds-card-selector-icon/-title/-description) NO usan margin. */
1052
1127
  .kds-card-selector {
1128
+ /* Reset BeerCSS button */
1129
+ display: flex;
1130
+ flex-direction: column;
1131
+ align-items: stretch;
1132
+ justify-content: flex-start;
1133
+ block-size: auto;
1134
+ inline-size: 100%;
1135
+ text-align: left;
1136
+ line-height: 1.5;
1137
+ color: var(--kds-color-text-primary);
1138
+ /* Estilos propios del card-selector */
1053
1139
  padding: var(--kds-spacing-3);
1140
+ gap: var(--kds-spacing-1-5);
1054
1141
  border-radius: var(--kds-radius-md);
1055
- border: 2px solid var(--kds-border-light);
1142
+ border: var(--kds-border-width-md) solid var(--kds-border-light);
1056
1143
  background: var(--kds-color-background-paper);
1057
1144
  transition: all 0.3s ease;
1058
- text-align: left;
1059
1145
  cursor: pointer;
1060
- display: flex;
1061
- flex-direction: column;
1062
1146
  }
1063
1147
 
1064
- .kds-card-selector:hover {
1065
- border-color: #D1D5DB; /* gray-300 */
1148
+ .kds-card-selector:hover:not(.selected) {
1149
+ border-color: var(--kds-color-primary-light);
1150
+ background: var(--kds-color-primary-hover);
1151
+ }
1152
+
1153
+ /* Override del ripple/overlay default de BeerCSS:
1154
+ `:is(.wave,.chip,.button,button,nav.tabbed>a,...):not([class*=ripple])::after`
1155
+ tiene specificity (0,2,4) según DevTools (Chrome cuenta cada selector dentro
1156
+ de :is() individualmente para algunos motores). Usamos !important — consistente
1157
+ con cómo se overridean otros estilos de BeerCSS en este archivo (67 usos previos).
1158
+ Antes pintaba negro porque `currentColor` resolvía a text-primary del card. */
1159
+ .kds-card-selector::after {
1160
+ background-image: radial-gradient(circle, var(--kds-color-primary-main) 1%, transparent 1%) !important;
1066
1161
  }
1067
1162
 
1068
1163
  .kds-card-selector.selected {
1069
- border-color: #3B82F6; /* blue-600 */
1070
- background: #EFF6FF; /* blue-50 */
1164
+ border-color: var(--kds-color-primary-main);
1165
+ background: var(--kds-color-primary-faint);
1071
1166
  box-shadow: var(--kds-shadow-md);
1072
1167
  }
1073
1168
 
1074
- /* Icon container */
1169
+ /* Icon container — spacing manejado por gap del padre, no margin */
1075
1170
  .kds-card-selector-icon {
1076
- width: 48px;
1077
- height: 48px;
1078
- background: #DBEAFE; /* blue-100 */
1079
- border-radius: 8px;
1171
+ width: var(--kds-spacing-6);
1172
+ height: var(--kds-spacing-6);
1173
+ background: var(--kds-color-primary-focus);
1174
+ border-radius: var(--kds-radius-sm);
1080
1175
  display: flex;
1081
1176
  align-items: center;
1082
1177
  justify-content: center;
1083
- margin-bottom: 16px;
1084
1178
  }
1085
1179
 
1086
1180
  .kds-card-selector-icon i,
1087
1181
  .kds-card-selector-icon svg {
1088
- width: 24px;
1089
- height: 24px;
1090
- min-width: 24px;
1091
- min-height: 24px;
1092
- color: #3B82F6; /* blue-600 */
1182
+ width: var(--kds-spacing-3);
1183
+ height: var(--kds-spacing-3);
1184
+ min-width: var(--kds-spacing-3);
1185
+ min-height: var(--kds-spacing-3);
1186
+ font-size: var(--kds-spacing-3);
1187
+ color: var(--kds-color-primary-main);
1093
1188
  }
1094
1189
 
1095
- /* Title */
1190
+ /* Title — spacing manejado por gap del padre, no margin */
1096
1191
  .kds-card-selector-title {
1097
- font-weight: 600;
1192
+ font-weight: var(--kds-font-weight-semibold);
1098
1193
  color: var(--kds-color-text-primary);
1099
- margin-bottom: 8px;
1100
- font-size: 16px;
1194
+ font-size: var(--kds-font-size-lg);
1101
1195
  }
1102
1196
 
1103
1197
  /* Description */
1104
1198
  .kds-card-selector-description {
1105
- font-size: 14px;
1106
- color: #4B5563; /* gray-600 */
1107
- line-height: 1.5;
1199
+ font-size: var(--kds-font-size-sm);
1200
+ color: var(--kds-color-text-secondary);
1201
+ line-height: var(--kds-line-height-normal);
1108
1202
  }
1109
1203
 
1110
1204
  /* Selected state - visual feedback via border only */
@@ -1116,14 +1210,22 @@ a.kds-btn.kds-btn-block {
1116
1210
  display: flex;
1117
1211
  flex-direction: column;
1118
1212
  gap: var(--kds-spacing-2);
1119
- padding: var(--kds-spacing-4);
1213
+ padding: var(--kds-spacing-2);
1120
1214
  border-radius: var(--kds-radius-lg);
1121
1215
  border: 2px solid var(--kds-border-medium);
1122
- max-width: 400px; /* Increased from 365px for better text spacing */
1216
+ /* Ancho mínimo aplicado a TODOS los planes así un plan sin badge en una
1217
+ grilla con un plan recomendado mantiene la misma anchura, y el badge nunca
1218
+ se superpone al título por estrechez del card. */
1219
+ min-width: 260px;
1220
+ max-width: 400px;
1123
1221
  background: var(--kds-surface-base);
1124
1222
  transition: all 0.3s ease;
1125
1223
  cursor: pointer;
1126
- height: 100%; /* Ensure cards fill grid height */
1224
+ /* Alto fijo: el card se estira al alto de su row del grid (align-items stretch
1225
+ es el default) — todas las cards de la misma fila quedan a la misma altura
1226
+ sin importar el contenido. `align-self: stretch` lo hace explícito. */
1227
+ height: 100%;
1228
+ align-self: stretch;
1127
1229
  }
1128
1230
 
1129
1231
  .kds-card-plan:hover {
@@ -1143,18 +1245,19 @@ a.kds-btn.kds-btn-block {
1143
1245
  box-shadow: var(--kds-shadow-elevation-4);
1144
1246
  }
1145
1247
 
1146
- /* Recommended Badge */
1248
+ /* Recommended Badge — inline dentro del card (no flotante).
1249
+ Es el primer hijo del .kds-card-plan, así que aparece arriba de todo
1250
+ el contenido, alineado a la izquierda. */
1147
1251
  .kds-card-plan-badge {
1148
- position: absolute;
1149
- top: -12px;
1150
- right: var(--kds-spacing-6);
1151
- padding: var(--kds-spacing-1) var(--kds-spacing-4);
1252
+ align-self: flex-start;
1253
+ padding: var(--kds-spacing-0-5) var(--kds-spacing-1-5);
1152
1254
  background: var(--primary);
1153
1255
  color: white;
1154
- font-size: var(--kds-font-size-sm);
1256
+ font-size: var(--kds-font-size-xs);
1155
1257
  font-weight: var(--kds-font-weight-semibold);
1258
+ line-height: 1;
1156
1259
  border-radius: var(--kds-radius-full);
1157
- box-shadow: var(--kds-shadow-elevation-1);
1260
+ white-space: nowrap;
1158
1261
  }
1159
1262
 
1160
1263
  /* Plan Header */
@@ -1182,13 +1285,11 @@ a.kds-btn.kds-btn-block {
1182
1285
  display: flex;
1183
1286
  align-items: baseline;
1184
1287
  gap: var(--kds-spacing-2);
1185
- padding: var(--kds-spacing-4) 0;
1186
1288
  border-bottom: 1px solid var(--kds-border-light);
1187
- min-height: 88px; /* Standardize price area height */
1188
1289
  }
1189
1290
 
1190
1291
  .kds-price {
1191
- font-size: 42px;
1292
+ font-size: var(--kds-font-size-4xl);
1192
1293
  font-weight: var(--kds-font-weight-bold);
1193
1294
  color: var(--primary);
1194
1295
  line-height: 1.1;
@@ -1443,6 +1544,10 @@ a.kds-btn.kds-btn-block {
1443
1544
  align-items: flex-end;
1444
1545
  }
1445
1546
 
1547
+ .kds-self-center {
1548
+ align-self: center;
1549
+ }
1550
+
1446
1551
  /* Gap utilities */
1447
1552
  .kds-gap-1 { gap: var(--kds-spacing-1); }
1448
1553
  .kds-gap-2 { gap: var(--kds-spacing-2); }
@@ -1479,6 +1584,7 @@ a.kds-btn.kds-btn-block {
1479
1584
  /* Spacing utilities - Margin */
1480
1585
  .kds-m-0 { margin: 0; }
1481
1586
  .kds-m-2 { margin: var(--kds-spacing-2); }
1587
+ .kds-m-2-5 { margin: var(--kds-spacing-2-5); }
1482
1588
  .kds-m-4 { margin: var(--kds-spacing-4); }
1483
1589
  .kds-m-6 { margin: var(--kds-spacing-6); }
1484
1590
  .kds-m-8 { margin: var(--kds-spacing-8); }
@@ -1492,6 +1598,7 @@ a.kds-btn.kds-btn-block {
1492
1598
  .kds-mt-8 { margin-top: var(--kds-spacing-8); }
1493
1599
 
1494
1600
  .kds-mb-0 { margin-bottom: 0; }
1601
+ .kds-mb-0-5 { margin-bottom: var(--kds-spacing-0-5); }
1495
1602
  .kds-mb-1 { margin-bottom: var(--kds-spacing-1); }
1496
1603
  .kds-mb-2 { margin-bottom: var(--kds-spacing-2); }
1497
1604
  .kds-mb-3 { margin-bottom: var(--kds-spacing-3); }
@@ -1702,53 +1809,108 @@ a.kds-btn.kds-btn-block {
1702
1809
  }
1703
1810
 
1704
1811
  /* ========================================
1705
- Snackbar Positioning
1812
+ Snackbar Positioning & Styling
1706
1813
  ======================================== */
1707
1814
 
1708
1815
  .snackbar {
1709
1816
  position: fixed;
1710
- bottom: var(--kds-spacing-3);
1711
- left: 50%;
1712
- transform: translateX(-50%);
1713
1817
  z-index: var(--kds-z-index-snackbar);
1714
1818
  min-width: 344px;
1715
1819
  max-width: var(--kds-snackbar-max-width);
1716
1820
  box-shadow: var(--kds-shadow-8);
1821
+ border-radius: var(--kds-radius-md);
1822
+ padding: var(--kds-spacing-1-5) var(--kds-spacing-2);
1823
+ gap: var(--kds-spacing-1);
1824
+ font-family: var(--kds-font-family-primary);
1825
+ font-size: var(--kds-font-size-body2);
1826
+ font-weight: var(--kds-font-weight-medium);
1827
+ line-height: var(--kds-line-height-normal);
1828
+ letter-spacing: var(--kds-letter-spacing-normal);
1829
+ overflow: hidden;
1717
1830
  }
1718
1831
 
1719
1832
  /* Snackbar active state - ensure visibility when toggled via JS */
1720
1833
  .snackbar.active {
1721
1834
  visibility: visible !important;
1722
1835
  opacity: 1 !important;
1723
- transform: translateX(-50%) !important;
1724
1836
  }
1725
1837
 
1726
- /* Snackbar semantic variants - background + text/icon color */
1838
+ /* Snackbar semantic variants
1839
+ All use white text (--kds-color-primary-contrast) on solid semantic backgrounds */
1727
1840
  .snackbar.error {
1728
1841
  background-color: var(--kds-color-error-main) !important;
1729
- color: var(--on-error, var(--kds-color-primary-contrast)) !important;
1842
+ color: var(--kds-color-primary-contrast) !important;
1730
1843
  }
1731
1844
 
1732
1845
  .snackbar.error i {
1733
- color: var(--on-error, var(--kds-color-primary-contrast)) !important;
1846
+ color: var(--kds-color-primary-contrast) !important;
1734
1847
  }
1735
1848
 
1736
1849
  .snackbar.info {
1737
1850
  background-color: var(--kds-color-info-main) !important;
1738
- color: var(--on-info, var(--kds-color-primary-contrast)) !important;
1851
+ color: var(--kds-color-primary-contrast) !important;
1739
1852
  }
1740
1853
 
1741
1854
  .snackbar.info i {
1742
- color: var(--on-info, var(--kds-color-primary-contrast)) !important;
1855
+ color: var(--kds-color-primary-contrast) !important;
1743
1856
  }
1744
1857
 
1745
1858
  .snackbar.success {
1746
1859
  background-color: var(--kds-color-success-main) !important;
1747
- color: var(--on-success, var(--kds-color-primary-contrast)) !important;
1860
+ color: var(--kds-color-primary-contrast) !important;
1748
1861
  }
1749
1862
 
1750
1863
  .snackbar.success i {
1751
- color: var(--on-success, var(--kds-color-primary-contrast)) !important;
1864
+ color: var(--kds-color-primary-contrast) !important;
1865
+ }
1866
+
1867
+ /* Snackbar progress bar — animated timer for auto-dismiss */
1868
+ .snackbar[data-auto-dismiss]::after {
1869
+ content: '';
1870
+ position: absolute;
1871
+ bottom: 0;
1872
+ left: 0;
1873
+ height: 3px;
1874
+ width: 100%;
1875
+ background: rgba(255, 255, 255, 0.35);
1876
+ border-radius: 0 0 var(--kds-radius-md) var(--kds-radius-md);
1877
+ animation: kds-snackbar-timer var(--kds-snackbar-duration, 5s) linear forwards;
1878
+ }
1879
+
1880
+ @keyframes kds-snackbar-timer {
1881
+ from { width: 100%; }
1882
+ to { width: 0; }
1883
+ }
1884
+
1885
+ /* Snackbar close button */
1886
+ .kds-snackbar-close {
1887
+ background: none !important;
1888
+ border: none !important;
1889
+ color: var(--kds-color-primary-contrast) !important;
1890
+ cursor: pointer;
1891
+ padding: var(--kds-spacing-0-5) !important;
1892
+ margin: calc(-1 * var(--kds-spacing-0-5)) !important;
1893
+ margin-left: 0 !important;
1894
+ border-radius: var(--kds-radius-full) !important;
1895
+ display: flex;
1896
+ align-items: center;
1897
+ justify-content: center;
1898
+ flex-shrink: 0;
1899
+ opacity: 0.7;
1900
+ transition: opacity 150ms;
1901
+ min-width: auto !important;
1902
+ width: auto !important;
1903
+ height: auto !important;
1904
+ }
1905
+
1906
+ .kds-snackbar-close:hover {
1907
+ opacity: 1;
1908
+ background: rgba(255, 255, 255, 0.15) !important;
1909
+ }
1910
+
1911
+ .kds-snackbar-close i {
1912
+ font-size: 18px !important;
1913
+ color: var(--kds-color-primary-contrast) !important;
1752
1914
  }
1753
1915
 
1754
1916
  /* ========================================
@@ -1949,6 +2111,221 @@ a.kds-btn-google:disabled {
1949
2111
  height: var(--kds-spacing-button-icon-size);
1950
2112
  }
1951
2113
 
2114
+ /* ========================================
2115
+ KDS LINEAR PROGRESS
2116
+ Native <progress> (KdsLinearProgress). Additive over BeerCSS `progress`,
2117
+ scoped to .kds-progress so other consumers are unaffected.
2118
+ ======================================== */
2119
+
2120
+ /* `progress` is inline-block by default → leaves a baseline (descender) gap
2121
+ below the bar. Block removes that gap so it sits flush with siblings. */
2122
+ .kds-progress {
2123
+ display: block;
2124
+ }
2125
+
2126
+ /* Animate the filled value when it changes (e.g. advancing a step). BeerCSS
2127
+ sets the value background but no transition, so the width jumps abruptly. */
2128
+ .kds-progress::-webkit-progress-value {
2129
+ transition: width var(--kds-transition-standard) var(--kds-easing-standard);
2130
+ }
2131
+
2132
+ .kds-progress::-moz-progress-bar {
2133
+ transition: width var(--kds-transition-standard) var(--kds-easing-standard);
2134
+ }
2135
+
2136
+ /* ========================================
2137
+ KDS SECURE LOADER
2138
+ Loader de espera: anillo circular + candado centrado + frases opcionales.
2139
+ El anillo reutiliza el spinner circular de BeerCSS, escalado.
2140
+ ======================================== */
2141
+
2142
+ .kds-secure-loader {
2143
+ display: flex;
2144
+ flex-direction: column;
2145
+ align-items: center;
2146
+ justify-content: center;
2147
+ gap: var(--kds-spacing-4);
2148
+ text-align: center;
2149
+ /* Llena y centra dentro de contenedores flex (pantalla de carga); en flujo
2150
+ normal (contenedor no-flex) se reduce a su contenido. */
2151
+ flex: 1 1 auto;
2152
+ }
2153
+
2154
+ .kds-secure-loader-text {
2155
+ display: flex;
2156
+ flex-direction: column;
2157
+ gap: var(--kds-spacing-0-25);
2158
+ }
2159
+
2160
+ .kds-secure-loader-title {
2161
+ margin: 0;
2162
+ font-family: var(--kds-font-family-primary);
2163
+ font-size: var(--kds-font-size-h6);
2164
+ font-weight: var(--kds-font-weight-semibold);
2165
+ line-height: var(--kds-line-height-snug);
2166
+ color: var(--kds-color-text-primary);
2167
+ }
2168
+
2169
+ .kds-secure-loader-message {
2170
+ margin: 0;
2171
+ font-family: var(--kds-font-family-secondary);
2172
+ font-size: var(--kds-font-size-body1);
2173
+ line-height: var(--kds-line-height-normal);
2174
+ color: var(--kds-color-primary-main);
2175
+ }
2176
+
2177
+ /* Caja del spinner con tamaño fijo: la animación no altera el layout.
2178
+ 6.25rem (100px) = tamaño del loader original (CircularProgress size=100). */
2179
+ .kds-secure-loader-spinner {
2180
+ position: relative;
2181
+ display: inline-grid;
2182
+ place-items: center;
2183
+ inline-size: var(--kds-secure-loader-size, 6.25rem);
2184
+ block-size: var(--kds-secure-loader-size, 6.25rem);
2185
+ }
2186
+
2187
+ /* Anillo: SVG nativo con arco vía stroke-dasharray, rotando. Replica el
2188
+ CircularProgress original (viewBox 44u, thickness 2, arco ~63%, disableShrink). */
2189
+ .kds-secure-loader-ring {
2190
+ inline-size: var(--kds-secure-loader-size, 6.25rem);
2191
+ block-size: var(--kds-secure-loader-size, 6.25rem);
2192
+ animation: kds-secure-loader-spin 1.2s linear infinite;
2193
+ }
2194
+
2195
+ .kds-secure-loader-ring circle {
2196
+ fill: none;
2197
+ stroke: var(--kds-color-primary-main);
2198
+ stroke-width: 2;
2199
+ stroke-linecap: round;
2200
+ /* circunferencia ≈ 2π·20.2 ≈ 127; arco visible ≈ 80 (~63%) */
2201
+ stroke-dasharray: 80 127;
2202
+ }
2203
+
2204
+ @keyframes kds-secure-loader-spin {
2205
+ to {
2206
+ transform: rotate(360deg);
2207
+ }
2208
+ }
2209
+
2210
+ /* Candado centrado sobre el anillo (~0.3 del diámetro). Centrado explícito
2211
+ (top/left 50% + translate) para que no dependa del grid ni se recorte. */
2212
+ .kds-secure-loader-lock {
2213
+ position: absolute;
2214
+ top: 50%;
2215
+ left: 50%;
2216
+ transform: translate(-50%, -50%);
2217
+ color: var(--kds-color-text-secondary);
2218
+ font-size: calc(var(--kds-secure-loader-size, 6.25rem) * 0.3);
2219
+ line-height: 1;
2220
+ pointer-events: none;
2221
+ }
2222
+
2223
+ /* ========================================
2224
+ KDS COPY BUTTON
2225
+ Chip compacto que muestra un valor + icono copy y lo copia al click.
2226
+ Acción inline (distinto de KdsCopyRow). Look del copy button de khenshin.
2227
+ ======================================== */
2228
+
2229
+ .kds-copy-button {
2230
+ display: inline-flex;
2231
+ align-items: center;
2232
+ gap: var(--kds-spacing-1);
2233
+ padding: var(--kds-spacing-0-25) var(--kds-spacing-1-5);
2234
+ /* No usar el alto de botón táctil de BeerCSS (~44px): es un chip compacto,
2235
+ su alto lo define el contenido + padding. */
2236
+ block-size: auto;
2237
+ min-block-size: 0;
2238
+ border: none;
2239
+ border-radius: var(--kds-radius-button);
2240
+ background: var(--kds-alert-info-bg);
2241
+ color: var(--kds-color-info-dark);
2242
+ font-family: var(--kds-font-family-secondary);
2243
+ font-size: var(--kds-font-size-sm);
2244
+ font-weight: var(--kds-font-weight-medium);
2245
+ line-height: var(--kds-line-height-normal);
2246
+ cursor: pointer;
2247
+ transition: background-color var(--kds-transition-shorter) var(--kds-easing-standard),
2248
+ color var(--kds-transition-shorter) var(--kds-easing-standard);
2249
+ }
2250
+
2251
+ /* active = hover: sin el aro de focus/active (outline morado de BeerCSS). */
2252
+ .kds-copy-button:focus,
2253
+ .kds-copy-button:focus-visible,
2254
+ .kds-copy-button:active {
2255
+ outline: none;
2256
+ }
2257
+
2258
+ /* value y copiedText se apilan en la MISMA celda de grid: la celda toma el
2259
+ ancho del texto más largo, por lo que el botón conserva su ancho al alternar
2260
+ entre "valor" y "copiado" (sin reflow). */
2261
+ .kds-copy-button-label {
2262
+ display: inline-grid;
2263
+ }
2264
+
2265
+ .kds-copy-button-value,
2266
+ .kds-copy-button-copied {
2267
+ grid-area: 1 / 1;
2268
+ white-space: nowrap;
2269
+ }
2270
+
2271
+ /* Estado por defecto: visible el valor, oculto (pero ocupando espacio) el copiado */
2272
+ .kds-copy-button-copied {
2273
+ visibility: hidden;
2274
+ }
2275
+
2276
+ /* Al copiar se invierte la visibilidad; el ancho no cambia */
2277
+ .kds-copy-button.copied .kds-copy-button-value {
2278
+ visibility: hidden;
2279
+ }
2280
+
2281
+ .kds-copy-button.copied .kds-copy-button-copied {
2282
+ visibility: visible;
2283
+ }
2284
+
2285
+ .kds-copy-button .material-symbols-outlined {
2286
+ font-size: 1rem;
2287
+ color: var(--kds-color-info-main);
2288
+ flex-shrink: 0;
2289
+ }
2290
+
2291
+ .kds-copy-button.copied {
2292
+ background: var(--kds-alert-success-bg);
2293
+ color: var(--kds-alert-success-text);
2294
+ animation: kds-copy-button-pulse var(--kds-transition-short) var(--kds-easing-standard);
2295
+ }
2296
+
2297
+ .kds-copy-button.copied .material-symbols-outlined {
2298
+ color: var(--kds-color-success-main);
2299
+ /* el check entra con un pop al copiar */
2300
+ animation: kds-copy-button-pop var(--kds-transition-short) var(--kds-easing-standard);
2301
+ }
2302
+
2303
+ @keyframes kds-copy-button-pulse {
2304
+ 0% {
2305
+ transform: scale(1);
2306
+ }
2307
+ 50% {
2308
+ transform: scale(1.04);
2309
+ }
2310
+ 100% {
2311
+ transform: scale(1);
2312
+ }
2313
+ }
2314
+
2315
+ @keyframes kds-copy-button-pop {
2316
+ 0% {
2317
+ transform: scale(0.3);
2318
+ opacity: 0;
2319
+ }
2320
+ 60% {
2321
+ transform: scale(1.25);
2322
+ opacity: 1;
2323
+ }
2324
+ 100% {
2325
+ transform: scale(1);
2326
+ }
2327
+ }
2328
+
1952
2329
  /* ========================================
1953
2330
  Link Styles
1954
2331
  ======================================== */
@@ -2050,6 +2427,16 @@ footer.primary a:hover {
2050
2427
  margin-right: var(--kds-spacing-2);
2051
2428
  }
2052
2429
 
2430
+ /* Ícono(s) en color primary. Para íconos MUI/SVG dentro del scope que, por el reset
2431
+ `.kds-theme-root svg { fill: currentColor }`, terminan heredando el color de texto
2432
+ (#333) en vez de su color propio — el `color="primary"` de MUI no le gana al contexto.
2433
+ Aplica al contenedor y a sus i/svg hijos. */
2434
+ .kds-icon-primary,
2435
+ .kds-icon-primary i,
2436
+ .kds-icon-primary svg {
2437
+ color: var(--kds-color-primary-main);
2438
+ }
2439
+
2053
2440
  /* Section title icon */
2054
2441
  .kds-stage-section-title i {
2055
2442
  vertical-align: middle;
@@ -2081,9 +2468,28 @@ body.dark {
2081
2468
  transition: border-color 0.2s, box-shadow 0.2s, outline-color 0.2s;
2082
2469
  }
2083
2470
 
2084
- /* ==========================================
2085
- NOTCH VISIBILITY (opacity)
2086
- ========================================== */
2471
+ /* === TEXTAREA FIX === */
2472
+ /* BeerCSS base sets minimal block padding; add breathing room for textarea */
2473
+ .field > textarea {
2474
+ padding-block: 0.75rem;
2475
+ resize: vertical;
2476
+ }
2477
+
2478
+ .field.label > textarea {
2479
+ padding-block-start: 1.5rem;
2480
+ }
2481
+
2482
+ /* Label en reposo (estado "abajo", como placeholder): font-size menor al 1rem de BeerCSS
2483
+ para que un label largo no estorbe con un ícono (prefix/suffix) del input. Token sm
2484
+ (13–14px, siempre < 1rem del input incluso en desktop). Al flotar, BeerCSS lo reduce a
2485
+ .75rem con mayor especificidad, así que esto solo afecta el reposo. */
2486
+ .field.label > label {
2487
+ font-size: var(--kds-font-size-sm);
2488
+ }
2489
+
2490
+ /* ==========================================
2491
+ NOTCH VISIBILITY (opacity)
2492
+ ========================================== */
2087
2493
 
2088
2494
  /* Ocultar notch por defecto */
2089
2495
  .field.label.border:not(.fill) > label::after {
@@ -2168,12 +2574,16 @@ body.dark {
2168
2574
  Asegurar que el dropdown arrow sea visible
2169
2575
  ========================================== */
2170
2576
 
2171
- /* Select: mantener appearance nativa para mostrar el dropdown arrow */
2577
+ /* Select: reset nativo + arrow custom via SVG (iOS Safari ignora estilos con appearance:auto) */
2172
2578
  .field select {
2173
- /* BeerCSS puede estar ocultando el arrow, aseguramos que sea visible */
2174
- appearance: auto;
2175
- -webkit-appearance: auto;
2176
- -moz-appearance: auto;
2579
+ -webkit-appearance: none;
2580
+ -moz-appearance: none;
2581
+ appearance: none;
2582
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='%23333' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
2583
+ background-repeat: no-repeat;
2584
+ background-position: right var(--kds-spacing-1) center;
2585
+ background-size: 20px;
2586
+ padding-right: var(--kds-spacing-4) !important;
2177
2587
  }
2178
2588
 
2179
2589
  /* ==========================================
@@ -2198,6 +2608,23 @@ body.dark {
2198
2608
  color: var(--error); /* Rojo error */
2199
2609
  }
2200
2610
 
2611
+ /* ==========================================
2612
+ PASSWORD REVEAL TOGGLE (KdsTextField `revealable`)
2613
+ El <a role="button"> reusa el posicionamiento de icono de BeerCSS
2614
+ (.field > a, pointer-events: all). Aquí solo: color del icono
2615
+ (on-surface-variant) y un focus ring accesible para el toggle
2616
+ navegable por teclado (BeerCSS hace `outline: inherit` en <a>).
2617
+ ========================================== */
2618
+ .field > a.kds-field-reveal {
2619
+ color: var(--on-surface-variant);
2620
+ }
2621
+
2622
+ .field > a.kds-field-reveal:focus-visible {
2623
+ outline: 2px solid var(--primary);
2624
+ outline-offset: 2px;
2625
+ border-radius: 50%;
2626
+ }
2627
+
2201
2628
  /* ==========================================
2202
2629
  LABEL COLOR
2203
2630
  Mantener sincronizado con border
@@ -2305,6 +2732,71 @@ body.dark {
2305
2732
  display: inline-flex;
2306
2733
  }
2307
2734
 
2735
+ /* ========================================
2736
+ Radix Tooltip (.kds-tooltip)
2737
+ Espejo de `.tooltip` pero para popovers de Radix:
2738
+ bg oscuro, texto blanco, sombra + animación fade/slide direccional.
2739
+ ======================================== */
2740
+
2741
+ .kds-tooltip {
2742
+ background-color: var(--kds-color-text-primary);
2743
+ color: var(--kds-color-background-paper);
2744
+ font-family: var(--kds-font-family-primary);
2745
+ font-size: var(--kds-font-size-xs);
2746
+ font-weight: var(--kds-font-weight-medium);
2747
+ line-height: var(--kds-line-height-normal);
2748
+ border-radius: var(--kds-radius-sm);
2749
+ padding: var(--kds-spacing-0-75) var(--kds-spacing-1-5);
2750
+ box-shadow: var(--kds-shadow-4);
2751
+ max-width: 280px;
2752
+ z-index: var(--kds-z-index-tooltip, 1500);
2753
+ user-select: none;
2754
+ /* Animación direccional según Radix data-side — coordinada con copy-row
2755
+ (cubic-bezier 0.2, 0.8, 0.2, 1) para un feel consistente del DS. */
2756
+ animation-duration: 240ms;
2757
+ animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
2758
+ will-change: transform, opacity;
2759
+ }
2760
+
2761
+ .kds-tooltip[data-state='closed'] {
2762
+ animation-duration: 140ms;
2763
+ animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
2764
+ }
2765
+
2766
+ /* Direccional según data-side (Radix añade el attr en runtime).
2767
+ Cada lado entra desde su dirección con ~8px de offset (más visible que 4px). */
2768
+ .kds-tooltip[data-side='top'][data-state='delayed-open'],
2769
+ .kds-tooltip[data-side='top'][data-state='instant-open'] { animation-name: kds-tooltip-in-top; }
2770
+ .kds-tooltip[data-side='bottom'][data-state='delayed-open'],
2771
+ .kds-tooltip[data-side='bottom'][data-state='instant-open'] { animation-name: kds-tooltip-in-bottom; }
2772
+ .kds-tooltip[data-side='left'][data-state='delayed-open'],
2773
+ .kds-tooltip[data-side='left'][data-state='instant-open'] { animation-name: kds-tooltip-in-left; }
2774
+ .kds-tooltip[data-side='right'][data-state='delayed-open'],
2775
+ .kds-tooltip[data-side='right'][data-state='instant-open'] { animation-name: kds-tooltip-in-right; }
2776
+
2777
+ /* Fallback cuando no hay data-side resuelto aún */
2778
+ .kds-tooltip[data-state='delayed-open']:not([data-side]),
2779
+ .kds-tooltip[data-state='instant-open']:not([data-side]) {
2780
+ animation-name: kds-tooltip-in-top;
2781
+ }
2782
+
2783
+ .kds-tooltip[data-state='closed'] { animation-name: kds-tooltip-out; }
2784
+
2785
+ @keyframes kds-tooltip-in-top { from { opacity: 0; transform: translateY(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2786
+ @keyframes kds-tooltip-in-bottom { from { opacity: 0; transform: translateY(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2787
+ @keyframes kds-tooltip-in-left { from { opacity: 0; transform: translateX(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2788
+ @keyframes kds-tooltip-in-right { from { opacity: 0; transform: translateX(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2789
+
2790
+ @keyframes kds-tooltip-out {
2791
+ from { opacity: 1; transform: none; }
2792
+ to { opacity: 0; transform: scale(0.96); }
2793
+ }
2794
+
2795
+ /* Arrow (SVG path generado por Radix) */
2796
+ .kds-tooltip-arrow {
2797
+ fill: var(--kds-color-text-primary);
2798
+ }
2799
+
2308
2800
  /* ========================================
2309
2801
  Material Symbols Icon Sizing
2310
2802
  ======================================== */
@@ -2339,6 +2831,16 @@ body.dark {
2339
2831
  width: 100%;
2340
2832
  }
2341
2833
 
2834
+ /* Truncado en una línea con ellipsis. Incluye min-width:0 para que funcione
2835
+ dentro de contenedores flex/grid (el ítem puede encogerse por debajo de su
2836
+ contenido). Útil para nombres/asuntos largos en headers y filas. */
2837
+ .kds-truncate {
2838
+ min-width: 0;
2839
+ overflow: hidden;
2840
+ text-overflow: ellipsis;
2841
+ white-space: nowrap;
2842
+ }
2843
+
2342
2844
  .kds-max-w-sm {
2343
2845
  max-width: 400px;
2344
2846
  }
@@ -2382,6 +2884,11 @@ body.dark {
2382
2884
  display: flex;
2383
2885
  flex-direction: column;
2384
2886
  gap: var(--kds-spacing-3);
2887
+ /* Reset del fieldset nativo: sin borde/padding/margin por defecto del navegador. */
2888
+ margin: 0;
2889
+ padding: 0;
2890
+ border: 0;
2891
+ min-inline-size: 0;
2385
2892
  }
2386
2893
 
2387
2894
  /* Checkbox Label - BeerCSS override */
@@ -2393,7 +2900,7 @@ label.radio {
2393
2900
  border-radius: 8px;
2394
2901
  cursor: pointer;
2395
2902
  transition: background-color 0.2s;
2396
- font-size: 16px;
2903
+ font-size: var(--kds-font-size-sm);
2397
2904
  line-height: 1.5;
2398
2905
  color: var(--kds-color-text-primary);
2399
2906
  }
@@ -2431,6 +2938,42 @@ label.radio:has(input:disabled) {
2431
2938
  opacity: 0.6;
2432
2939
  }
2433
2940
 
2941
+ /* ========================================
2942
+ RADIO GROUP — variante card (.kds-radio-group--card)
2943
+ Cada opción como fila con borde (estilo selección de banco/cuenta),
2944
+ manteniendo el control radio. Hover + opción seleccionada resaltada.
2945
+ ======================================== */
2946
+ .kds-radio-group--card {
2947
+ gap: var(--kds-spacing-2);
2948
+ }
2949
+
2950
+ .kds-radio-group--card label.radio {
2951
+ gap: var(--kds-spacing-1-5);
2952
+ /* Vertical con un poco más de aire; horizontal reducido para pegar el radio a la izquierda. */
2953
+ padding: var(--kds-spacing-2) var(--kds-spacing-1-5);
2954
+ /* Bordes con los valores del bank selector. */
2955
+ border: 1px solid var(--kds-color-border-subtle);
2956
+ border-radius: var(--kds-radius-card);
2957
+ background: var(--kds-color-surface);
2958
+ transition: border-color 0.2s, background 0.2s;
2959
+ }
2960
+
2961
+ /* Leve separación extra entre el radio y el texto de la opción. */
2962
+ .kds-radio-group--card label.radio span {
2963
+ margin-left: var(--kds-spacing-0-5);
2964
+ }
2965
+
2966
+ .kds-radio-group--card label.radio:hover {
2967
+ border-color: var(--kds-color-border-default);
2968
+ }
2969
+
2970
+ /* Seleccionada: poco color primario — solo un fondo faint sutil + borde gris
2971
+ (el punto del radio ya comunica la selección). */
2972
+ .kds-radio-group--card label.radio:has(input:checked) {
2973
+ border-color: var(--kds-color-border-default);
2974
+ background: var(--kds-color-primary-faint);
2975
+ }
2976
+
2434
2977
  /* ========================================
2435
2978
  ONBOARDING COMPONENTS
2436
2979
  Multi-stage onboarding flow with form validation
@@ -2721,7 +3264,8 @@ dialog.modal .field.border:focus-within {
2721
3264
  padding: var(--kds-spacing-2);
2722
3265
  }
2723
3266
 
2724
- .snackbar {
3267
+ .snackbar,
3268
+ .snackbar.active {
2725
3269
  min-width: calc(100% - 32px);
2726
3270
  left: 16px;
2727
3271
  right: 16px;
@@ -2927,19 +3471,17 @@ footer > .kds-container-center {
2927
3471
  display: flex;
2928
3472
  align-items: center;
2929
3473
  gap: var(--kds-spacing-1);
2930
- padding: var(--kds-spacing-2);
3474
+ /* Padding compacto: vertical spacing-1 (8px), horizontal spacing-2 (16px). */
3475
+ padding: var(--kds-spacing-1) var(--kds-spacing-2);
2931
3476
  border-radius: var(--kds-radius-md);
2932
3477
  border: 1px solid;
2933
3478
  font-family: var(--kds-font-family-primary);
2934
3479
  min-width: 0;
2935
- flex: 1 1 100%;
2936
- }
2937
-
2938
- @media (min-width: 768px) {
2939
- .kds-alert {
2940
- padding: var(--kds-spacing-2);
2941
- flex: 1 1 auto;
2942
- }
3480
+ /* Banner: ocupa siempre el ancho del contenedor. width explícito porque como
3481
+ flex item de una columna con align-items:center el cross-axis no se estira.
3482
+ Sin flex-grow para no estirarse verticalmente en contenedores flex-column. */
3483
+ width: 100%;
3484
+ flex: 0 1 auto;
2943
3485
  }
2944
3486
 
2945
3487
  .kds-alert:last-child {
@@ -2965,7 +3507,9 @@ footer > .kds-container-center {
2965
3507
  font-size: var(--kds-font-size-sm);
2966
3508
  font-weight: var(--kds-font-weight-semibold);
2967
3509
  line-height: var(--kds-line-height-normal);
2968
- margin-bottom: var(--kds-spacing-0-5);
3510
+ /* Solo margin-bottom: el padding del alert da el espaciado. Reset del resto para
3511
+ evitar el margin-block que BeerCSS aplica a <p> dentro del scope. */
3512
+ margin: 0 0 var(--kds-spacing-0-5);
2969
3513
  word-break: normal;
2970
3514
  overflow-wrap: break-word;
2971
3515
  }
@@ -2975,6 +3519,9 @@ footer > .kds-container-center {
2975
3519
  font-size: var(--kds-font-size-sm);
2976
3520
  font-weight: var(--kds-font-weight-regular);
2977
3521
  line-height: var(--kds-line-height-relaxed);
3522
+ /* Sin margen propio: el padding del alert es el único espaciado (evita el
3523
+ margin-block de <p> de BeerCSS dentro del scope). */
3524
+ margin: 0;
2978
3525
  word-break: normal;
2979
3526
  overflow-wrap: break-word;
2980
3527
  }
@@ -3020,6 +3567,32 @@ footer > .kds-container-center {
3020
3567
  color: var(--kds-color-error-dark);
3021
3568
  }
3022
3569
 
3570
+ /* Close button — icon-only, discreto, no usa kds-btn para no romper el flex layout del alert */
3571
+ .kds-alert-close {
3572
+ flex-shrink: 0;
3573
+ display: inline-flex;
3574
+ align-items: center;
3575
+ justify-content: center;
3576
+ width: 28px;
3577
+ height: 28px;
3578
+ padding: 0;
3579
+ background: transparent;
3580
+ border: 0;
3581
+ border-radius: 50%;
3582
+ color: inherit;
3583
+ cursor: pointer;
3584
+ transition: background-color 0.15s ease;
3585
+ }
3586
+
3587
+ .kds-alert-close:hover {
3588
+ background: rgba(0, 0, 0, 0.06);
3589
+ }
3590
+
3591
+ .kds-alert-close i {
3592
+ font-size: 18px;
3593
+ line-height: 1;
3594
+ }
3595
+
3023
3596
  /* Lists inside alerts */
3024
3597
  .kds-alert ul {
3025
3598
  padding-left: var(--kds-spacing-2);
@@ -4016,6 +4589,14 @@ dialog#surveyModal button.circle {
4016
4589
  text-align: center;
4017
4590
  }
4018
4591
 
4592
+ .kds-text-left {
4593
+ text-align: left;
4594
+ }
4595
+
4596
+ .kds-text-right {
4597
+ text-align: right;
4598
+ }
4599
+
4019
4600
  .kds-text-underline {
4020
4601
  text-decoration: underline;
4021
4602
  }
@@ -4028,10 +4609,187 @@ dialog#surveyModal button.circle {
4028
4609
  color: var(--on-surface-variant);
4029
4610
  }
4030
4611
 
4612
+ .kds-text-primary {
4613
+ color: var(--kds-color-primary-main);
4614
+ }
4615
+
4031
4616
  .kds-text-sm {
4032
4617
  font-size: var(--kds-font-size-sm);
4033
4618
  }
4034
4619
 
4620
+ /* ── Font-size scale utilities (additive — opt-in companions to .kds-text-sm) ── */
4621
+ .kds-text-base {
4622
+ font-size: var(--kds-font-size-base);
4623
+ }
4624
+
4625
+ .kds-text-lg {
4626
+ font-size: var(--kds-font-size-lg);
4627
+ }
4628
+
4629
+ .kds-text-xl {
4630
+ font-size: var(--kds-font-size-xl);
4631
+ }
4632
+
4633
+ .kds-text-2xl {
4634
+ font-size: var(--kds-font-size-2xl);
4635
+ }
4636
+
4637
+ /* ── Font-weight utilities ── */
4638
+ .kds-fw-regular {
4639
+ font-weight: var(--kds-font-weight-regular);
4640
+ }
4641
+
4642
+ .kds-fw-medium {
4643
+ font-weight: var(--kds-font-weight-medium);
4644
+ }
4645
+
4646
+ .kds-fw-semibold {
4647
+ font-weight: var(--kds-font-weight-semibold);
4648
+ }
4649
+
4650
+ .kds-fw-bold {
4651
+ font-weight: var(--kds-font-weight-bold);
4652
+ }
4653
+
4654
+ /* ── Text-transform utilities ── */
4655
+ .kds-text-transform-none {
4656
+ text-transform: none;
4657
+ }
4658
+
4659
+ /* ── Soft background utilities (semantic muted backgrounds for callouts) ── */
4660
+ .kds-bg-warning-soft {
4661
+ background-color: var(--kds-color-warning-soft);
4662
+ }
4663
+
4664
+ .kds-bg-info-soft {
4665
+ background-color: var(--kds-color-info-soft);
4666
+ }
4667
+
4668
+ /* ── Typography variants ── */
4669
+ .kds-text-display1 {
4670
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4671
+ font-size: var(--kds-font-size-4xl, 36px);
4672
+ font-weight: var(--kds-font-weight-bold, 700);
4673
+ line-height: var(--kds-line-height-tight, 1.2);
4674
+ letter-spacing: var(--kds-letter-spacing-tight, -0.025em);
4675
+ }
4676
+
4677
+ .kds-text-display2 {
4678
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4679
+ font-size: var(--kds-font-size-3xl, 30px);
4680
+ font-weight: var(--kds-font-weight-bold, 700);
4681
+ line-height: var(--kds-line-height-tight, 1.2);
4682
+ letter-spacing: var(--kds-letter-spacing-tight, -0.025em);
4683
+ }
4684
+
4685
+ .kds-text-heading1 {
4686
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4687
+ font-size: var(--kds-font-size-2xl, 24px);
4688
+ font-weight: var(--kds-font-weight-semibold, 600);
4689
+ line-height: var(--kds-line-height-snug, 1.375);
4690
+ }
4691
+
4692
+ .kds-text-heading2 {
4693
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4694
+ font-size: var(--kds-font-size-xl, 20px);
4695
+ font-weight: var(--kds-font-weight-semibold, 600);
4696
+ line-height: var(--kds-line-height-snug, 1.375);
4697
+ }
4698
+
4699
+ .kds-text-heading3 {
4700
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4701
+ font-size: var(--kds-font-size-lg, 18px);
4702
+ font-weight: var(--kds-font-weight-semibold, 600);
4703
+ line-height: var(--kds-line-height-normal, 1.5);
4704
+ }
4705
+
4706
+ .kds-text-body-large {
4707
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4708
+ font-size: var(--kds-font-size-base, 16px);
4709
+ font-weight: var(--kds-font-weight-regular, 400);
4710
+ line-height: var(--kds-line-height-relaxed, 1.66);
4711
+ }
4712
+
4713
+ .kds-text-body {
4714
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4715
+ font-size: var(--kds-font-size-sm, 14px);
4716
+ font-weight: var(--kds-font-weight-regular, 400);
4717
+ line-height: var(--kds-line-height-normal, 1.5);
4718
+ }
4719
+
4720
+ .kds-text-body-small {
4721
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4722
+ font-size: var(--kds-font-size-sm, 12px);
4723
+ font-weight: var(--kds-font-weight-regular, 400);
4724
+ line-height: var(--kds-line-height-normal, 1.5);
4725
+ }
4726
+
4727
+ .kds-text-label {
4728
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4729
+ font-size: var(--kds-font-size-sm, 12px);
4730
+ font-weight: var(--kds-font-weight-semibold, 600);
4731
+ line-height: var(--kds-line-height-normal, 1.5);
4732
+ letter-spacing: var(--kds-letter-spacing-widest, 1px);
4733
+ text-transform: uppercase;
4734
+ }
4735
+
4736
+ .kds-text-label-small {
4737
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4738
+ font-size: var(--kds-font-size-xs, 10px);
4739
+ font-weight: var(--kds-font-weight-semibold, 600);
4740
+ line-height: var(--kds-line-height-normal, 1.5);
4741
+ letter-spacing: var(--kds-letter-spacing-widest, 1px);
4742
+ text-transform: uppercase;
4743
+ }
4744
+
4745
+ /* Value — dato/valor destacado (ej. nombre del comercio en el header del cobro). */
4746
+ .kds-text-value {
4747
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4748
+ font-size: var(--kds-font-size-sm);
4749
+ font-weight: var(--kds-font-weight-semibold);
4750
+ line-height: var(--kds-line-height-relaxed);
4751
+ color: var(--kds-color-gray-800);
4752
+ }
4753
+
4754
+ /* Code — texto tipo código/referencia (mono, uppercase, gris), como el "CÓDIGO" del header. */
4755
+ .kds-text-code {
4756
+ font-family: var(--kds-font-family-mono);
4757
+ font-size: var(--kds-font-size-xs);
4758
+ font-weight: var(--kds-font-weight-regular);
4759
+ letter-spacing: var(--kds-letter-spacing-wider);
4760
+ font-variant-numeric: tabular-nums;
4761
+ color: var(--kds-color-gray-400);
4762
+ text-transform: uppercase;
4763
+ }
4764
+
4765
+ /* Caption — texto muy chico y liviano para pie de página (ej. número de versión). */
4766
+ .kds-text-caption {
4767
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4768
+ font-size: var(--kds-font-size-2xs);
4769
+ font-weight: var(--kds-font-weight-regular);
4770
+ line-height: var(--kds-line-height-normal);
4771
+ color: var(--kds-color-gray-400);
4772
+ }
4773
+
4774
+ .kds-text-link {
4775
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4776
+ font-size: inherit;
4777
+ font-weight: var(--kds-font-weight-medium, 500);
4778
+ color: var(--kds-color-primary-main, #8347AD);
4779
+ text-decoration: underline;
4780
+ cursor: pointer;
4781
+ }
4782
+
4783
+ .kds-text-link:hover {
4784
+ color: var(--kds-color-primary-dark, #5B3179);
4785
+ }
4786
+
4787
+ /* Inline emphasis: bold weight only, inherits size/color/family from context so it
4788
+ works as a highlighted fragment inside any other variant (body, heading, etc.). */
4789
+ .kds-text-strong {
4790
+ font-weight: var(--kds-font-weight-bold, 700);
4791
+ }
4792
+
4035
4793
  /* Display utilities */
4036
4794
  .kds-hidden {
4037
4795
  display: none;
@@ -4152,7 +4910,9 @@ dialog#surveyModal button.circle {
4152
4910
  ======================================== */
4153
4911
 
4154
4912
  .kds-badge {
4155
- display: inline-block;
4913
+ display: inline-flex;
4914
+ align-items: center;
4915
+ gap: 4px;
4156
4916
  padding: 2px 8px;
4157
4917
  border-radius: var(--kds-radius-sm);
4158
4918
  font-size: var(--kds-font-size-xs);
@@ -4160,6 +4920,40 @@ dialog#surveyModal button.circle {
4160
4920
  line-height: 1.5;
4161
4921
  }
4162
4922
 
4923
+ /* Icon prefix inside chip — small inline icon */
4924
+ .kds-badge > i.material-symbols-outlined {
4925
+ font-size: 14px;
4926
+ line-height: 1;
4927
+ }
4928
+
4929
+ /* Deletable chip close button — discreto, sin kds-btn (eso lo agrandaba ridículo) */
4930
+ .kds-badge-close {
4931
+ display: inline-flex;
4932
+ align-items: center;
4933
+ justify-content: center;
4934
+ width: 16px;
4935
+ height: 16px;
4936
+ margin-right: -2px;
4937
+ padding: 0;
4938
+ background: transparent;
4939
+ border: 0;
4940
+ border-radius: 50%;
4941
+ color: inherit;
4942
+ cursor: pointer;
4943
+ opacity: 0.7;
4944
+ transition: opacity 0.15s, background-color 0.15s;
4945
+ }
4946
+
4947
+ .kds-badge-close:hover {
4948
+ opacity: 1;
4949
+ background: rgba(0, 0, 0, 0.1);
4950
+ }
4951
+
4952
+ .kds-badge-close i {
4953
+ font-size: 14px;
4954
+ line-height: 1;
4955
+ }
4956
+
4163
4957
  .kds-badge.success {
4164
4958
  background-color: var(--kds-color-success-container);
4165
4959
  color: var(--kds-color-success-dark);
@@ -4371,21 +5165,46 @@ dialog#surveyModal button.circle {
4371
5165
  flex-shrink: 0;
4372
5166
  }
4373
5167
 
4374
- /* Merchant tile with logo variant */
5168
+ /* Merchant tile with logo variant — el logo (avatar del comercio) llena TODO el tile.
5169
+ `display: block` evita el desborde del auto-grid; `overflow: hidden` recorta la imagen
5170
+ a las esquinas redondeadas del tile. La imagen va CUADRADA (sin border-radius propio):
5171
+ solo el contenedor recorta, evitando el hairline sub-pixel del doble redondeo. El fondo
5172
+ se deja transparente bajo el logo como respaldo (no debe verse púrpura en los bordes). */
4375
5173
  .kds-merchant-tile.logo {
4376
- padding: var(--kds-spacing-0-5);
5174
+ padding: 0;
5175
+ display: block;
5176
+ overflow: hidden;
5177
+ background: transparent;
4377
5178
  }
4378
5179
 
4379
5180
  .kds-merchant-tile.logo img {
4380
5181
  width: 100%;
4381
5182
  height: 100%;
4382
5183
  object-fit: cover;
4383
- border-radius: var(--kds-radius-md);
5184
+ border-radius: 0;
5185
+ display: block;
5186
+ }
5187
+
5188
+ /* Variante para logos que traen su propio marco/forma (logos de comercio/servicio,
5189
+ no fotos): `contain` + padding para que el logo entre completo sin recortar sus
5190
+ esquinas. Opt-in: pasar className="kds-merchant-tile--contain". */
5191
+ .kds-merchant-tile.logo.kds-merchant-tile--contain {
5192
+ padding: var(--kds-spacing-1);
5193
+ }
5194
+ .kds-merchant-tile.logo.kds-merchant-tile--contain img {
5195
+ object-fit: contain;
4384
5196
  }
4385
5197
 
4386
5198
  .kds-merchant-meta {
4387
5199
  display: flex;
4388
5200
  flex-direction: column;
5201
+ gap: var(--kds-spacing-0-5);
5202
+ }
5203
+
5204
+ /* El meta controla su propio espaciado: anula el margin sibling de BeerCSS
5205
+ (`… + :is(p,h*,…) { margin-block-start: 1rem }`) que separaba de más las líneas. */
5206
+ .kds-merchant-meta > * {
5207
+ margin-block: 0 !important;
4389
5208
  }
4390
5209
 
4391
5210
  .kds-merchant-label {
@@ -4438,6 +5257,11 @@ dialog#surveyModal button.circle {
4438
5257
  color: var(--kds-color-text-primary);
4439
5258
  }
4440
5259
 
5260
+ /* Opt-in color modifier — switches the value to the LigoPay/khipu-blue tone */
5261
+ .kds-amount-value--info {
5262
+ color: var(--kds-color-info-blue); /* #5A5FE0 */
5263
+ }
5264
+
4441
5265
  .kds-amount-value small {
4442
5266
  font-size: 18px;
4443
5267
  font-weight: 500;
@@ -4535,14 +5359,26 @@ dialog#surveyModal button.circle {
4535
5359
 
4536
5360
  .field.locked > input,
4537
5361
  .field.locked > textarea {
4538
- background: var(--kds-color-shell);
4539
- color: var(--kds-color-text-secondary);
5362
+ color: var(--kds-color-text-disabled);
4540
5363
  cursor: default;
4541
- border-color: var(--kds-color-divider);
5364
+ pointer-events: none;
4542
5365
  }
4543
5366
 
4544
5367
  .field.locked > label {
4545
- color: var(--kds-color-text-hint);
5368
+ color: var(--kds-color-text-disabled);
5369
+ }
5370
+
5371
+ /* Locked: suppress all hover/focus visual changes */
5372
+ .field.label.border:not(.fill).locked:hover:not(:focus-within) > label::after,
5373
+ .field.label.border:not(.fill).locked:focus-within > label::after {
5374
+ border-block-start-color: var(--outline);
5375
+ }
5376
+ .field.label.border:not(.fill).locked:hover:not(:focus-within) > :is(input, textarea, select),
5377
+ .field.label.border:not(.fill).locked:focus-within > :is(input, textarea, select) {
5378
+ border-color: var(--outline);
5379
+ }
5380
+ .field.label.locked:hover:not(:focus-within) > label {
5381
+ color: var(--kds-color-text-disabled);
4546
5382
  }
4547
5383
 
4548
5384
  .field.locked > i {
@@ -4712,23 +5548,161 @@ dialog#surveyModal button.circle {
4712
5548
  }
4713
5549
 
4714
5550
  /* ========================================
4715
- 09 - SUCCESS MARK (.kds-success-mark)
4716
- Large success icon for completion screens
5551
+ 08b - FAB (.kds-fab)
5552
+ Circular, icon-only floating action button with an animated hide state.
5553
+ Presentational: drive `.kds-fab--hidden` from useHideOnScroll for scroll-away.
4717
5554
  ======================================== */
4718
5555
 
4719
- .kds-success-mark {
4720
- width: 64px;
4721
- height: 64px;
5556
+ .kds-fab {
5557
+ display: inline-flex;
5558
+ align-items: center;
5559
+ justify-content: center;
5560
+ width: var(--kds-spacing-5);
5561
+ height: var(--kds-spacing-5);
5562
+ padding: 0;
5563
+ border: none;
4722
5564
  border-radius: var(--kds-radius-full);
4723
- background: var(--kds-color-success-soft);
4724
- border: 2px solid var(--kds-color-success-main);
4725
- display: grid;
4726
- place-items: center;
4727
- color: var(--kds-color-success-main);
4728
- animation: kds-pop 0.45s ease-out;
4729
- margin: 0 auto;
4730
- }
4731
-
5565
+ background: var(--kds-color-background-paper);
5566
+ color: var(--kds-color-text-primary);
5567
+ box-shadow: var(--kds-shadow-elevated);
5568
+ cursor: pointer;
5569
+ z-index: 100;
5570
+ /* Neutralize native button rendering so the pressed state doesn't flash a square. */
5571
+ -webkit-appearance: none;
5572
+ appearance: none;
5573
+ -webkit-tap-highlight-color: transparent;
5574
+ transition: opacity var(--kds-transition-short) ease, transform var(--kds-transition-short) ease,
5575
+ background-color var(--kds-transition-shorter) ease;
5576
+ }
5577
+
5578
+ /* Keep the circle in EVERY interaction state. Uses `button.kds-fab` (element + class) to
5579
+ out-specify BeerCSS's base `button`/`button:active` rules — same trick as `.kds-btn`. */
5580
+ button.kds-fab,
5581
+ button.kds-fab:hover,
5582
+ button.kds-fab:active,
5583
+ button.kds-fab:focus,
5584
+ button.kds-fab:focus-visible {
5585
+ border-radius: var(--kds-radius-full);
5586
+ background: var(--kds-color-background-paper);
5587
+ }
5588
+
5589
+ button.kds-fab:hover:not(:disabled) {
5590
+ background: var(--kds-color-background-muted);
5591
+ }
5592
+
5593
+ /* Subtle press feedback that preserves the round shape. */
5594
+ button.kds-fab:active:not(:disabled) {
5595
+ transform: translateY(var(--kds-spacing-0-25));
5596
+ }
5597
+
5598
+ button.kds-fab:focus-visible {
5599
+ outline: var(--kds-spacing-0-25) solid var(--kds-color-primary-main);
5600
+ outline-offset: var(--kds-spacing-0-25);
5601
+ }
5602
+
5603
+ .kds-fab > i.material-symbols-outlined {
5604
+ font-size: var(--kds-spacing-button-icon-size);
5605
+ line-height: 1;
5606
+ }
5607
+
5608
+ /* Pinned corners — fixed to the viewport (stays visible on scroll-up, iframe-friendly).
5609
+ Horizontally the top-right FAB hugs the right edge of the centered content column set via
5610
+ `--kds-fab-column-width` (default 100% → viewport edge). The consumer sets that var to its
5611
+ widget width so on desktop the FAB overlaps the header's top-right corner instead of drifting
5612
+ to the far viewport edge. `max(...)` keeps at least a token inset on narrow (mobile) viewports. */
5613
+ .kds-fab--top-right,
5614
+ .kds-fab--top-left,
5615
+ .kds-fab--bottom-right,
5616
+ .kds-fab--bottom-left {
5617
+ position: fixed;
5618
+ }
5619
+
5620
+ .kds-fab--top-right {
5621
+ top: var(--kds-spacing-2);
5622
+ right: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5623
+ }
5624
+
5625
+ .kds-fab--top-left {
5626
+ top: var(--kds-spacing-2);
5627
+ left: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5628
+ }
5629
+
5630
+ .kds-fab--bottom-right {
5631
+ bottom: var(--kds-spacing-2);
5632
+ right: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5633
+ }
5634
+
5635
+ .kds-fab--bottom-left {
5636
+ bottom: var(--kds-spacing-2);
5637
+ left: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5638
+ }
5639
+
5640
+ /* Desktop: nudge the top-right FAB up so it sits partially over the header's top edge. */
5641
+ @media (min-width: 768px) {
5642
+ .kds-fab--top-right {
5643
+ top: var(--kds-spacing-1);
5644
+ }
5645
+ }
5646
+
5647
+ /* Corner-overlap: mount the FAB centered OVER the top-right corner of the content column
5648
+ (`--kds-fab-column-width`), overlapping outward — vs `--top-right` which insets inside the
5649
+ column. Mobile keeps a small inset from the viewport via the `--kds-fab-inset` token. */
5650
+ .kds-fab--corner {
5651
+ --kds-fab-inset: 5px;
5652
+ position: fixed;
5653
+ top: var(--kds-fab-inset);
5654
+ right: var(--kds-fab-inset);
5655
+ }
5656
+
5657
+ @media (min-width: 768px) {
5658
+ .kds-fab--corner {
5659
+ right: max(
5660
+ var(--kds-fab-inset),
5661
+ calc((100% - var(--kds-fab-column-width, 100%)) / 2 - var(--kds-spacing-5) / 2)
5662
+ );
5663
+ }
5664
+ }
5665
+
5666
+ /* Hidden (scroll-away) state — fade + slide toward the nearest edge */
5667
+ .kds-fab--hidden {
5668
+ opacity: 0;
5669
+ transform: translateY(calc(-1 * var(--kds-spacing-1))) scale(0.9);
5670
+ pointer-events: none;
5671
+ }
5672
+
5673
+ .kds-fab--bottom-right.kds-fab--hidden,
5674
+ .kds-fab--bottom-left.kds-fab--hidden {
5675
+ transform: translateY(var(--kds-spacing-1)) scale(0.9);
5676
+ }
5677
+
5678
+ @media (prefers-reduced-motion: reduce) {
5679
+ .kds-fab {
5680
+ transition: opacity var(--kds-transition-short) ease;
5681
+ }
5682
+
5683
+ .kds-fab--hidden {
5684
+ transform: none;
5685
+ }
5686
+ }
5687
+
5688
+ /* ========================================
5689
+ 09 - SUCCESS MARK (.kds-success-mark)
5690
+ Large success icon for completion screens
5691
+ ======================================== */
5692
+
5693
+ .kds-success-mark {
5694
+ width: 64px;
5695
+ height: 64px;
5696
+ border-radius: var(--kds-radius-full);
5697
+ background: var(--kds-color-success-soft);
5698
+ border: 2px solid var(--kds-color-success-main);
5699
+ display: grid;
5700
+ place-items: center;
5701
+ color: var(--kds-color-success-main);
5702
+ animation: kds-pop 0.45s ease-out;
5703
+ margin: 0 auto;
5704
+ }
5705
+
4732
5706
  .kds-success-mark i {
4733
5707
  font-size: 32px;
4734
5708
  font-weight: 700;
@@ -4783,20 +5757,76 @@ dialog#surveyModal button.circle {
4783
5757
  display: flex;
4784
5758
  align-items: center;
4785
5759
  justify-content: center;
4786
- gap: var(--kds-spacing-1);
4787
- color: var(--kds-color-text-disabled);
5760
+ gap: var(--kds-spacing-0-5);
5761
+ color: var(--kds-color-gray-400);
4788
5762
  font-size: var(--kds-font-size-xs);
5763
+ letter-spacing: var(--kds-letter-spacing-wide);
4789
5764
  padding: var(--kds-spacing-1) 0;
4790
5765
  }
4791
5766
 
4792
- .kds-secure-footer i {
4793
- font-size: var(--kds-font-size-sm);
5767
+ /* Footer SIEMPRE fuera del card body (desktop y mobile): el footer interno
5768
+ (variant="inside") queda oculto en todos los breakpoints; se muestra el
5769
+ externo, hermano directo del card bajo `.kds-screen`. */
5770
+ .kds-card-elevated > .kds-secure-footer {
5771
+ display: none;
4794
5772
  }
4795
5773
 
4796
- /* Inside a card: push to bottom with auto margin, subtle top spacing */
4797
- .kds-secure-footer.inside {
4798
- margin-top: auto;
4799
- padding-top: var(--kds-spacing-3);
5774
+ .kds-screen > form {
5775
+ margin-block-start: 0 !important;
5776
+ }
5777
+
5778
+ /* Footer externo adyacente a la card: cancela el gap del .kds-screen para que
5779
+ quede pegado debajo de la card y no flotando lejos. Las dos cards
5780
+ (header/body) sí conservan su separación. */
5781
+ .kds-screen > .kds-secure-footer {
5782
+ margin-top: calc(-1 * var(--kds-spacing-3));
5783
+ }
5784
+
5785
+ .kds-secure-footer-lock {
5786
+ width: 12px;
5787
+ height: 12px;
5788
+ flex: 0 0 auto;
5789
+ display: block;
5790
+ fill: none;
5791
+ stroke: currentColor;
5792
+ stroke-width: 1.75;
5793
+ stroke-linecap: round;
5794
+ stroke-linejoin: round;
5795
+ }
5796
+
5797
+ .kds-secure-footer .khipu-mark {
5798
+ height: 11px;
5799
+ width: auto;
5800
+ flex: 0 0 auto;
5801
+ display: block;
5802
+ object-fit: contain;
5803
+ overflow: visible;
5804
+ /* Corrección óptica: la masa visible del wordmark (el cuerpo de "Khipu") queda sobre el
5805
+ centro geométrico de su viewBox (45x15) porque el descendente de la "p" ocupa la parte
5806
+ baja. Al centrar por caja (align-items:center) el logo se ve ~1px alto respecto al texto,
5807
+ así que se baja 0.75px para alinear el centro óptico. Alto fijo (11px) → nudge consistente. */
5808
+ position: relative;
5809
+ top: 0.75px;
5810
+ }
5811
+
5812
+ /* Divisor entre el logo de Khipu y el del PSP ("Khipu | klap") */
5813
+ .kds-secure-footer-sep {
5814
+ width: 1px;
5815
+ height: 0.85em;
5816
+ background: currentColor;
5817
+ opacity: 0.35;
5818
+ flex: 0 0 auto;
5819
+ }
5820
+
5821
+ /* Logo del PSP (proveedor de pagos): lo provee el consumidor, lo alineamos al mismo
5822
+ alto que el mark de Khipu. Sirve para <img> o un elemento con .kds-psp-mark. */
5823
+ .kds-secure-footer img,
5824
+ .kds-secure-footer .kds-psp-mark {
5825
+ height: 11px;
5826
+ width: auto;
5827
+ flex: 0 0 auto;
5828
+ display: block;
5829
+ object-fit: contain;
4800
5830
  }
4801
5831
 
4802
5832
  .kds-secure-footer-code {
@@ -4811,26 +5841,46 @@ dialog#surveyModal button.circle {
4811
5841
  .kds-expand-toggle {
4812
5842
  background: none;
4813
5843
  border: 0;
4814
- padding: var(--kds-spacing-0-5) 0;
5844
+ padding: 0;
5845
+ /* Reset del bare `button { height: 2.5rem }` de BeerCSS (scoped en .kds-theme-root):
5846
+ sin esto el toggle quedaba en una caja de 40px con el texto centrado → espacio
5847
+ irregular arriba (pegado al resumen) y abajo (~26px hasta el panel). Con height
5848
+ auto el botón ajusta a su contenido y el ritmo lo gobiernan los márgenes. */
5849
+ height: auto;
4815
5850
  color: var(--kds-color-primary-main);
4816
5851
  font-weight: var(--kds-font-weight-medium);
4817
5852
  font-size: var(--kds-font-size-sm);
4818
5853
  cursor: pointer;
4819
5854
  display: inline-flex;
4820
5855
  align-items: center;
4821
- gap: var(--kds-spacing-0-75);
5856
+ gap: 0;
4822
5857
  }
4823
5858
 
4824
- .kds-expand-toggle:hover {
5859
+ .kds-expand-toggle:hover,
5860
+ .kds-expand-toggle:focus,
5861
+ .kds-expand-toggle:active {
4825
5862
  background: transparent;
5863
+ outline: none;
5864
+ box-shadow: none;
4826
5865
  }
4827
5866
 
4828
- .kds-expand-toggle:hover span {
5867
+ .kds-expand-toggle:hover span,
5868
+ .kds-expand-toggle:focus span,
5869
+ .kds-expand-toggle:active span {
4829
5870
  text-decoration: underline;
4830
5871
  }
4831
5872
 
4832
5873
  .kds-expand-toggle i {
4833
5874
  font-size: var(--kds-font-size-base);
5875
+ /* BeerCSS estiliza el `i` bare como caja flex de 30px (height/width/min: 30px), que
5876
+ inflaba el toggle y dejaba aire vertical de más alrededor del label. La achicamos a
5877
+ 1.25em MANTENIENDO el centrado flex de BeerCSS (display:flex/align/justify) — así el
5878
+ caret queda compacto Y ópticamente centrado con el texto (no usar height:auto ni
5879
+ line-height:1: descentran el glifo). */
5880
+ width: 1.25em;
5881
+ height: 1.25em;
5882
+ min-width: 0;
5883
+ min-height: 0;
4834
5884
  transition: transform var(--kds-transition-shorter, 0.2s);
4835
5885
  }
4836
5886
 
@@ -4850,8 +5900,11 @@ dialog#surveyModal button.circle {
4850
5900
  }
4851
5901
 
4852
5902
  .kds-expand-panel.open {
4853
- max-height: 800px;
4854
- margin-top: var(--kds-spacing-1);
5903
+ /* Fallback cap for no-JS consumers. With JS (React useExpandToggle / vanilla
5904
+ initExpandToggle) the panel's inline max-height is set to its exact scrollHeight,
5905
+ which overrides this and prevents clipping regardless of content length. */
5906
+ max-height: 2000px;
5907
+ margin-top: 0;
4855
5908
  }
4856
5909
 
4857
5910
  /* ========================================
@@ -4968,13 +6021,17 @@ dialog#surveyModal button.circle {
4968
6021
 
4969
6022
  .kds-status-block {
4970
6023
  text-align: center;
4971
- padding: var(--kds-spacing-6) 0;
6024
+ /* Padding vertical estándar: spacing-2 (16px), el mismo rhythm inter-elementos
6025
+ que usan kds-btn-stack y kds-hr-dashed. NO usar spacing-6 (48px): genera
6026
+ demasiado espacio cuando el bloque se compone con header/divider alrededor. */
6027
+ padding: var(--kds-spacing-2) 0;
4972
6028
  }
4973
6029
 
4974
6030
  .kds-status-block-icon {
4975
6031
  width: var(--kds-status-icon-size);
4976
6032
  height: var(--kds-status-icon-size);
4977
- margin: 0 auto var(--kds-spacing-3);
6033
+ /* spacing-1 (8px) icono→título: elementos relacionados dentro del bloque. */
6034
+ margin: 0 auto var(--kds-spacing-1);
4978
6035
  border-radius: var(--kds-radius-full);
4979
6036
  display: grid;
4980
6037
  place-items: center;
@@ -4990,12 +6047,18 @@ dialog#surveyModal button.circle {
4990
6047
  font-weight: var(--kds-font-weight-bold);
4991
6048
  color: var(--kds-color-text-primary);
4992
6049
  margin: 0 0 var(--kds-spacing-1);
6050
+ /* El reset global :where(h2) usa estas vars con !important; así se overridea. */
6051
+ --kds-typography-h2-margin-block-end: var(--kds-spacing-1);
4993
6052
  }
4994
6053
 
4995
6054
  .kds-status-block-description {
4996
6055
  font-size: var(--kds-font-size-sm);
4997
6056
  color: var(--kds-color-text-secondary);
4998
6057
  margin: 0;
6058
+ /* !important: anula el auto-espaciado de hermanos de BeerCSS
6059
+ (margin-block-start: 1rem, especificidad 0,5,1 imposible de igualar).
6060
+ La separación título→descripción la da el margin-bottom del título. */
6061
+ margin-top: 0 !important;
4999
6062
  }
5000
6063
 
5001
6064
  /* Variant: success */
@@ -5005,11 +6068,11 @@ dialog#surveyModal button.circle {
5005
6068
  color: var(--kds-color-success-main);
5006
6069
  }
5007
6070
 
5008
- /* Variant: pending (animated spinner) */
6071
+ /* Variant: pending (animated blue spinner, sin icono interno) */
5009
6072
  .kds-status-block[data-status="pending"] .kds-status-block-icon {
5010
6073
  background: transparent;
5011
6074
  border: 3px solid var(--kds-color-divider);
5012
- border-top-color: var(--kds-color-primary-main);
6075
+ border-top-color: var(--kds-color-info-main);
5013
6076
  animation: kds-spin 1s linear infinite;
5014
6077
  }
5015
6078
 
@@ -5027,12 +6090,21 @@ dialog#surveyModal button.circle {
5027
6090
  color: var(--kds-color-error-main);
5028
6091
  }
5029
6092
 
6093
+ /* Variant: info — usar SIEMPRE con icon "info_i" (i minúscula sin glyph circular)
6094
+ para que solo se vea nuestro círculo decorativo. Iconos como "info" tienen
6095
+ su propio círculo built-in → causarían doble círculo. */
6096
+ .kds-status-block[data-status="info"] .kds-status-block-icon {
6097
+ background: var(--kds-color-info-soft);
6098
+ border: var(--kds-border-width-md) solid var(--kds-color-info-main);
6099
+ color: var(--kds-color-info-main);
6100
+ }
6101
+
5030
6102
  /* Inline variant: icon left + text right */
5031
6103
  .kds-status-block.inline {
5032
6104
  text-align: left;
5033
6105
  display: flex;
5034
6106
  align-items: center;
5035
- gap: var(--kds-spacing-3);
6107
+ gap: var(--kds-spacing-2);
5036
6108
  padding: var(--kds-spacing-1) 0;
5037
6109
  }
5038
6110
 
@@ -5074,6 +6146,9 @@ dialog#surveyModal button.circle {
5074
6146
  .kds-bottom-sheet {
5075
6147
  width: 100%;
5076
6148
  max-width: var(--kds-bottom-sheet-max-width);
6149
+ max-height: 90dvh;
6150
+ display: flex;
6151
+ flex-direction: column;
5077
6152
  background: var(--kds-color-background-paper);
5078
6153
  border-radius: var(--kds-radius-2xl) var(--kds-radius-2xl) 0 0;
5079
6154
  padding: var(--kds-spacing-3-5) var(--kds-spacing-3) var(--kds-spacing-3);
@@ -5094,6 +6169,42 @@ dialog#surveyModal button.circle {
5094
6169
  background: var(--kds-color-divider);
5095
6170
  }
5096
6171
 
6172
+ /* Close button — top-right discreto, NO usa kds-btn (rompía el flex layout) */
6173
+ .kds-bottom-sheet-close {
6174
+ position: absolute;
6175
+ top: var(--kds-spacing-1);
6176
+ right: var(--kds-spacing-1);
6177
+ width: 32px;
6178
+ height: 32px;
6179
+ display: inline-flex;
6180
+ align-items: center;
6181
+ justify-content: center;
6182
+ padding: 0;
6183
+ background: transparent;
6184
+ border: 0;
6185
+ border-radius: 50%;
6186
+ color: var(--kds-color-text-secondary);
6187
+ cursor: pointer;
6188
+ transition: background-color 0.15s ease;
6189
+ }
6190
+
6191
+ .kds-bottom-sheet-close:hover {
6192
+ background: rgba(0, 0, 0, 0.06);
6193
+ }
6194
+
6195
+ .kds-bottom-sheet-close i {
6196
+ font-size: 20px;
6197
+ line-height: 1;
6198
+ }
6199
+
6200
+ /* Body container — separa el content del title/actions */
6201
+ .kds-bottom-sheet-body {
6202
+ text-align: left;
6203
+ margin-top: var(--kds-spacing-1);
6204
+ overflow-y: auto;
6205
+ min-height: 0;
6206
+ }
6207
+
5097
6208
  .kds-bottom-sheet-icon {
5098
6209
  font-size: var(--kds-font-size-4xl);
5099
6210
  }
@@ -5140,6 +6251,19 @@ dialog#surveyModal button.circle {
5140
6251
  to { opacity: 1; }
5141
6252
  }
5142
6253
 
6254
+ /* Botón con llenado progresivo (feedback visual de auto-cierre).
6255
+ Duración parametrizable con --kds-fill-duration (default 12s). */
6256
+ .kds-btn-fill-progress {
6257
+ background-image: linear-gradient(to right, var(--kds-color-primary-dark), var(--kds-color-primary-dark));
6258
+ background-repeat: no-repeat;
6259
+ background-size: 0% 100%;
6260
+ animation: kds-btn-fill var(--kds-fill-duration, 12s) linear forwards;
6261
+ }
6262
+
6263
+ @keyframes kds-btn-fill {
6264
+ to { background-size: 100% 100%; }
6265
+ }
6266
+
5143
6267
  @keyframes kds-rise {
5144
6268
  from { transform: translateY(var(--kds-spacing-2-5)); opacity: 0.4; }
5145
6269
  to { transform: none; opacity: 1; }
@@ -5187,6 +6311,7 @@ dialog#surveyModal button.circle {
5187
6311
  background: var(--kds-color-background-muted);
5188
6312
  border-radius: var(--kds-radius-lg);
5189
6313
  padding: var(--kds-spacing-0-25);
6314
+ margin-bottom: var(--kds-spacing-2);
5190
6315
  display: flex;
5191
6316
  position: relative;
5192
6317
  }
@@ -5284,8 +6409,8 @@ dialog#surveyModal button.circle {
5284
6409
  /* Symmetric padding */
5285
6410
  padding: var(--kds-spacing-2);
5286
6411
 
5287
- /* Static border-radius on all corners */
5288
- border-radius: var(--kds-radius-card);
6412
+ /* Bottom-only border-radius top is flush so the brand-inner logo isn't clipped */
6413
+ border-radius: 0 0 var(--kds-radius-card) var(--kds-radius-card);
5289
6414
 
5290
6415
  /* Override .kds-card-elevated transition — scroll drives the animation, not CSS transitions */
5291
6416
  transition: none;
@@ -5297,10 +6422,8 @@ dialog#surveyModal button.circle {
5297
6422
  /* clip-path clips the card from the bottom to hide the collapsible space.
5298
6423
  This is VISUAL ONLY — no layout change — prevents scroll feedback loop.
5299
6424
  Safari 13.1+ compatible (inset + round)
5300
- When collapsed (progress=1): bottom corners get border-radius,
5301
- top stays flush with screen edge. */
5302
- /* Bottom inset = collapsible height + half the card padding to tighten
5303
- the gap between "Código" and the visible bottom edge when collapsed. */
6425
+ round uses bottom-only radii (0 top, card-radius bottom) to match
6426
+ border-radius and avoid clipping the brand logo at the top corners. */
5304
6427
  clip-path: inset(
5305
6428
  0 0
5306
6429
  calc(
@@ -5308,7 +6431,7 @@ dialog#surveyModal button.circle {
5308
6431
  + var(--kds-spacing-1) * var(--collapse-progress)
5309
6432
  )
5310
6433
  0
5311
- round var(--kds-radius-card)
6434
+ round 0 0 var(--kds-radius-card) var(--kds-radius-card)
5312
6435
  );
5313
6436
 
5314
6437
  /* Suppress card's own shadow — wrapper handles it */
@@ -5319,7 +6442,8 @@ dialog#surveyModal button.circle {
5319
6442
  .kds-invoice-sticky .kds-brand-inner {
5320
6443
  margin-bottom: calc(var(--kds-spacing-1) * (1 - var(--collapse-progress)) + var(--kds-spacing-0-5) * var(--collapse-progress));
5321
6444
  }
5322
- .kds-invoice-sticky .kds-brand-inner svg {
6445
+ .kds-invoice-sticky .kds-brand-inner svg,
6446
+ .kds-invoice-sticky .kds-brand-inner img {
5323
6447
  height: calc(22px - 5px * var(--collapse-progress));
5324
6448
  }
5325
6449
 
@@ -5327,9 +6451,39 @@ dialog#surveyModal button.circle {
5327
6451
  /* No max-height — clip-path on parent handles visual collapse without layout changes */
5328
6452
  .kds-invoice-sticky .kds-invoice-collapsible {
5329
6453
  opacity: calc(1 - var(--collapse-progress) * 1.5);
6454
+
6455
+ /* Scroll interno discreto (mobile): cuando el detalle abierto excede el viewport, el
6456
+ collapsible scrollea internamente (monto/merchant quedan fijos arriba) para poder leer
6457
+ todo el detalle. Al tocar el fondo, `overscroll-behavior: auto` ENCADENA el gesto al
6458
+ scroll del body → dispara useStickyInvoiceCollapse → colapsa el header y aparece el form
6459
+ (flujo natural). Se auto-desactiva con el detalle cerrado (contenido más corto que el
6460
+ max-height → sin scroll ni efecto visual). */
6461
+ max-height: calc(100vh - var(--kds-spacing-12) - var(--kds-spacing-4));
6462
+ max-height: calc(100dvh - var(--kds-spacing-12) - var(--kds-spacing-4));
6463
+ overflow-y: auto;
6464
+ overflow-x: hidden;
6465
+ overscroll-behavior-y: auto;
6466
+ scrollbar-width: thin;
6467
+ scrollbar-color: var(--kds-color-gray-300) transparent;
6468
+ }
6469
+ .kds-invoice-sticky .kds-invoice-collapsible::-webkit-scrollbar {
6470
+ width: 4px;
6471
+ }
6472
+ .kds-invoice-sticky .kds-invoice-collapsible::-webkit-scrollbar-thumb {
6473
+ background: var(--kds-color-gray-300);
6474
+ border-radius: var(--kds-radius-full);
6475
+ }
6476
+ .kds-invoice-sticky .kds-invoice-collapsible::-webkit-scrollbar-track {
6477
+ background: transparent;
5330
6478
  }
5331
6479
 
5332
- /* Amount: NO font-size change (source keeps 30px always) */
6480
+ /* Amount: 30px 24px (progressive) */
6481
+ .kds-invoice-sticky .kds-invoice-amount {
6482
+ font-size: calc(
6483
+ var(--kds-font-size-3xl) -
6484
+ (var(--kds-font-size-3xl) - var(--kds-font-size-2xl)) * var(--collapse-progress)
6485
+ );
6486
+ }
5333
6487
 
5334
6488
  /* Merchant tile: 64×64px → 50×50px, radius 8px → 6px (progressive) */
5335
6489
  .kds-invoice-sticky .kds-invoice-merchant {
@@ -5355,10 +6509,11 @@ dialog#surveyModal button.circle {
5355
6509
  );
5356
6510
  }
5357
6511
 
5358
- /* Code: margin-top 4px → 0 (progressive). Font-size stays 12px. */
6512
+ /* Code: margin-top 8px → 0, font-size 12px → 11px (progressive) */
5359
6513
  .kds-invoice-sticky .kds-invoice-code {
5360
6514
  margin-top: calc(var(--kds-spacing-1) * (1 - var(--collapse-progress)));
5361
6515
  margin-bottom: 0;
6516
+ font-size: calc(var(--kds-font-size-xs) - 1px * var(--collapse-progress));
5362
6517
  }
5363
6518
 
5364
6519
  /* Pull all siblings after sticky wrapper up to fill clipped gap.
@@ -5380,32 +6535,64 @@ dialog#surveyModal button.circle {
5380
6535
  }
5381
6536
  }
5382
6537
 
6538
+ /* Invoice sticky: mobile-first — bottom-only border-radius to prevent clipping the brand logo.
6539
+ Desktop restores full border-radius (see min-width:768px block below). */
6540
+ .kds-card-elevated.kds-invoice-sticky {
6541
+ border-radius: 0 0 var(--kds-radius-card) var(--kds-radius-card);
6542
+ }
6543
+
5383
6544
  /* -- Invoice Collapsible (kv rows below header) -- */
5384
6545
  .kds-invoice-collapsible {
5385
- margin-top: var(--kds-spacing-1-5);
6546
+ margin-top: var(--kds-spacing-1);
6547
+ }
6548
+
6549
+ /* Ritmo uniforme alrededor del toggle: spacing-2 arriba (resumen↔"Ver detalle")
6550
+ iguala el padding-top spacing-2 que la .kds-detail-list da debajo
6551
+ ("Ver detalle"↔primer label del panel). Antes el alto fijo del bare button
6552
+ (40px) hacía que el espacio de arriba y de abajo fueran distintos. */
6553
+ .kds-invoice-collapsible > .kds-expand-toggle {
6554
+ margin-top: var(--kds-spacing-2);
5386
6555
  }
5387
6556
 
5388
- /* -- Invoice Summary (kv + expand toggle side by side) -- */
6557
+ /* -- Invoice Summary -- */
5389
6558
  .kds-invoice-summary {
5390
6559
  display: flex;
5391
6560
  align-items: flex-end;
5392
- gap: var(--kds-spacing-2);
6561
+ gap: var(--kds-spacing-1);
5393
6562
  }
5394
6563
  .kds-invoice-summary .kds-kv {
5395
6564
  flex: 1;
5396
6565
  min-width: 0;
5397
6566
  }
5398
- .kds-invoice-summary .kds-expand-toggle {
5399
- flex-shrink: 0;
5400
- white-space: nowrap;
5401
- }
5402
6567
 
5403
6568
  /* -- Invoice Header (amount + merchant tile) -- */
6569
+ /* Compound selector overrides BeerCSS `header { padding:0 1rem; display:grid; align-content:center }` */
6570
+ header.kds-invoice-header,
6571
+ div.kds-invoice-header,
5404
6572
  .kds-invoice-header {
5405
6573
  display: flex;
5406
6574
  align-items: flex-start;
5407
6575
  justify-content: space-between;
5408
6576
  gap: var(--kds-spacing-2);
6577
+ padding: 0;
6578
+ border-radius: 0;
6579
+ align-content: initial;
6580
+ /* Override BeerCSS `header { min-height: ... }` — el header debe ajustarse a su
6581
+ contenido (sigue el alto del merchant tile: 64px→50px al colapsar). Sin esto
6582
+ quedaba un min-height fijo de 64px → hueco muerto debajo al colapsar en mobile. */
6583
+ min-height: 0;
6584
+ }
6585
+
6586
+ /* Mobile: center-align el header (merchant tile vs bloque monto+código) tanto
6587
+ expandido como colapsado. Al quitar el logo del header, el bloque de texto quedaba
6588
+ más bajo que el merchant tile y con `flex-start` dejaba hueco abajo; centrado los
6589
+ alinea. CSS-only (no depende de la clase .is-collapsed, que el JS de collapse no setea). */
6590
+ @media (max-width: 767px) {
6591
+ header.kds-invoice-header,
6592
+ div.kds-invoice-header,
6593
+ .kds-invoice-header {
6594
+ align-items: center;
6595
+ }
5409
6596
  }
5410
6597
 
5411
6598
  /* Reset BeerCSS sibling margin on <p> inside invoice header — specificity (0,4,1) ties BeerCSS, wins by source order */
@@ -5415,11 +6602,11 @@ dialog#surveyModal button.circle {
5415
6602
  }
5416
6603
 
5417
6604
  .kds-invoice-amount {
5418
- font-weight: 700;
5419
- font-size: 30px;
5420
- line-height: 1.25;
5421
- letter-spacing: 0.4px;
5422
- color: var(--kds-color-text-primary);
6605
+ font-weight: var(--kds-font-weight-semibold);
6606
+ font-size: var(--kds-font-size-3xl);
6607
+ line-height: var(--kds-line-height-tight);
6608
+ letter-spacing: var(--kds-letter-spacing-wide);
6609
+ color: var(--kds-color-gray-900);
5423
6610
  margin: 0;
5424
6611
  }
5425
6612
 
@@ -5428,10 +6615,25 @@ dialog#surveyModal button.circle {
5428
6615
  }
5429
6616
 
5430
6617
  .kds-invoice-code {
6618
+ font-family: var(--kds-font-family-mono);
5431
6619
  font-size: var(--kds-font-size-xs);
5432
- color: var(--kds-color-text-hint);
6620
+ font-weight: var(--kds-font-weight-regular);
6621
+ letter-spacing: var(--kds-letter-spacing-wider);
6622
+ font-variant-numeric: tabular-nums;
6623
+ color: var(--kds-color-gray-400);
6624
+ text-transform: uppercase;
5433
6625
  margin: 0;
5434
- margin-top: var(--kds-spacing-1);
6626
+ margin-block: unset;
6627
+ display: flex;
6628
+ gap: var(--kds-spacing-1-5);
6629
+ }
6630
+
6631
+ .kds-invoice-code-value {
6632
+ color: var(--kds-color-gray-400);
6633
+ }
6634
+
6635
+ .kds-invoice-code-value--lowercase {
6636
+ text-transform: lowercase;
5435
6637
  }
5436
6638
 
5437
6639
  .kds-invoice-merchant {
@@ -5443,6 +6645,9 @@ dialog#surveyModal button.circle {
5443
6645
  place-items: center;
5444
6646
  color: #fff;
5445
6647
  flex-shrink: 0;
6648
+ /* Clip the slightly-oversized logo (see `.kds-invoice-merchant img`) to the
6649
+ rounded square so it can fully cover the deep-purple background. */
6650
+ overflow: hidden;
5446
6651
  }
5447
6652
 
5448
6653
  .kds-invoice-merchant i {
@@ -5461,29 +6666,52 @@ dialog#surveyModal button.circle {
5461
6666
  line-height: 1;
5462
6667
  }
5463
6668
 
6669
+ .kds-invoice-merchant img {
6670
+ /* Slightly larger than the container (+2px, centered by the grid) so the
6671
+ logo overflows under the parent's rounded clip and the deep-purple
6672
+ background never peeks through at the corners when the logo shrinks. */
6673
+ width: calc(100% + 2px);
6674
+ height: calc(100% + 2px);
6675
+ object-fit: cover;
6676
+ border-radius: var(--kds-radius-md);
6677
+ }
6678
+
5464
6679
  /* -- Card Title -- */
5465
6680
  .kds-card-title {
5466
- font-weight: 700;
6681
+ font-weight: var(--kds-font-weight-semibold);
5467
6682
  font-size: var(--kds-font-size-base);
5468
6683
  line-height: 1.5;
5469
6684
  letter-spacing: -0.31px;
5470
6685
  color: var(--kds-color-text-primary);
5471
- margin: 0 0 var(--kds-spacing-2);
6686
+ /* sin !important: no hay regla de margin-bottom para h1 en BeerCSS que competir, y así un
6687
+ consumidor puede anularlo (p.ej. FormTitle dentro de un Stack que ya da el espacio). */
6688
+ margin-bottom: var(--kds-spacing-2);
6689
+ }
6690
+
6691
+ /* Opt-in size modifiers (additive — do NOT change default 16/600) */
6692
+ .kds-card-title--lg {
6693
+ font-size: var(--kds-font-size-xl); /* 20px */
6694
+ font-weight: var(--kds-font-weight-semibold);
6695
+ }
6696
+
6697
+ .kds-card-title--xl {
6698
+ font-size: var(--kds-font-size-2xl); /* 24px */
6699
+ font-weight: var(--kds-font-weight-semibold);
5472
6700
  }
5473
6701
 
5474
6702
  /* -- Key-Value Grid -- */
5475
6703
  .kds-kv {
5476
6704
  display: grid;
5477
6705
  grid-template-columns: auto 1fr;
5478
- row-gap: var(--kds-spacing-1);
5479
- column-gap: var(--kds-spacing-1-5);
6706
+ column-gap: var(--kds-spacing-1);
5480
6707
  align-items: baseline;
5481
6708
  }
5482
6709
 
5483
6710
  .kds-kv dt {
5484
6711
  font-size: var(--kds-font-size-xs);
5485
- letter-spacing: 0.2px;
5486
- color: var(--kds-color-text-hint);
6712
+ line-height: var(--kds-line-height-relaxed);
6713
+ letter-spacing: normal;
6714
+ color: var(--kds-color-text-secondary);
5487
6715
  text-transform: uppercase;
5488
6716
  margin: 0;
5489
6717
  }
@@ -5491,8 +6719,14 @@ dialog#surveyModal button.circle {
5491
6719
  .kds-kv dd {
5492
6720
  margin: 0;
5493
6721
  font-size: var(--kds-font-size-sm);
5494
- font-weight: 600;
5495
- color: var(--kds-color-text-primary);
6722
+ line-height: var(--kds-line-height-relaxed);
6723
+ font-weight: var(--kds-font-weight-semibold);
6724
+ letter-spacing: normal;
6725
+ color: var(--kds-color-gray-800);
6726
+ min-width: 0;
6727
+ white-space: nowrap;
6728
+ overflow: hidden;
6729
+ text-overflow: ellipsis;
5496
6730
  }
5497
6731
 
5498
6732
  /* -- Dividers -- */
@@ -5514,34 +6748,59 @@ dialog#surveyModal button.circle {
5514
6748
  .kds-detail-list {
5515
6749
  display: flex;
5516
6750
  flex-direction: column;
5517
- gap: var(--kds-spacing-1-75);
5518
- margin: var(--kds-spacing-1-75) 0 0;
5519
- padding: 0;
6751
+ /* spacing-2 entre grupos del detalle (separación estándar entre piezas de info
6752
+ distintas, ej. "Emisor cobro" vs "Descripción"). El padding-top da la misma
6753
+ separación spacing-2 arriba del primer grupo (Asunto↔Emisor cobro). */
6754
+ gap: var(--kds-spacing-2);
6755
+ margin: 0;
6756
+ padding: var(--kds-spacing-2) 0 0;
5520
6757
  }
5521
6758
 
5522
- .kds-detail-group {
5523
- margin-bottom: var(--kds-spacing-1-75);
6759
+ @media (max-width: 767px) {
6760
+ .kds-detail-list {
6761
+ padding-bottom: var(--kds-spacing-2);
6762
+ }
5524
6763
  }
5525
6764
 
5526
- .kds-detail-group:last-child {
6765
+ .kds-detail-group {
6766
+ /* El espacio ENTRE grupos lo da el `gap` de .kds-detail-list (spacing-2).
6767
+ Dentro del grupo, label↔value llevan un gap chico (spacing-0-5) para un
6768
+ ritmo parejo: antes el dt iba pegado al dd (0px) y se veía desigual frente
6769
+ a los 16px entre los demás elementos del panel. */
6770
+ display: flex;
6771
+ flex-direction: column;
6772
+ gap: var(--kds-spacing-0-5);
5527
6773
  margin-bottom: 0;
5528
6774
  }
5529
6775
 
5530
6776
  .kds-detail-group dt {
5531
6777
  font-size: var(--kds-font-size-xs);
5532
- letter-spacing: 0.2px;
6778
+ letter-spacing: var(--kds-letter-spacing-wide);
5533
6779
  color: var(--kds-color-text-hint);
5534
6780
  text-transform: uppercase;
5535
- margin: 0 0 var(--kds-spacing-0-5);
6781
+ margin: 0;
5536
6782
  }
5537
6783
 
5538
6784
  .kds-detail-group dd {
5539
6785
  margin: 0;
5540
6786
  font-size: var(--kds-font-size-sm);
5541
- line-height: 1.45;
6787
+ line-height: var(--kds-line-height-normal);
5542
6788
  color: var(--kds-color-text-primary);
5543
6789
  }
5544
6790
 
6791
+ /* Imagen adjunta del cobro dentro del panel de detalle (ej. comprobante/producto).
6792
+ Reemplaza los inline styles del antiguo modal MerchantInfo: ancho contenido, borde
6793
+ y radio del DS. Va como un grupo más de la .kds-detail-list (hereda su gap). */
6794
+ .kds-detail-image {
6795
+ display: block;
6796
+ max-width: 100%;
6797
+ width: 160px;
6798
+ height: auto;
6799
+ object-fit: contain;
6800
+ border-radius: var(--kds-radius-md);
6801
+ border: 1px solid var(--kds-color-border);
6802
+ }
6803
+
5545
6804
  /* -- Amount Summary Row -- */
5546
6805
  .kds-amount-row {
5547
6806
  display: flex;
@@ -5601,16 +6860,16 @@ dialog#surveyModal button.circle {
5601
6860
  font-size: var(--kds-font-size-sm);
5602
6861
  }
5603
6862
 
5604
- .kds-recap-list .k {
6863
+ .kds-recap-list .kds-key {
5605
6864
  color: var(--kds-color-text-secondary);
5606
6865
  }
5607
6866
 
5608
- .kds-recap-list .v {
6867
+ .kds-recap-list .kds-value {
5609
6868
  color: var(--kds-color-text-primary);
5610
6869
  font-weight: 500;
5611
6870
  }
5612
6871
 
5613
- .kds-recap-list .v.placeholder {
6872
+ .kds-recap-list .kds-value.placeholder {
5614
6873
  color: var(--kds-color-text-hint);
5615
6874
  }
5616
6875
 
@@ -5637,15 +6896,81 @@ a.kds-btn-success:disabled {
5637
6896
  box-shadow: none;
5638
6897
  }
5639
6898
 
5640
- /* -- Field Helper Text -- */
5641
- .kds-field-helper {
5642
- font-size: var(--kds-font-size-xs);
5643
- color: var(--kds-color-text-secondary);
5644
- margin: var(--kds-spacing-0-75) var(--kds-spacing-1-75) 0;
6899
+ /* -- Button Warning (amber CTA) -- */
6900
+ button.kds-btn-warning,
6901
+ a.kds-btn-warning {
6902
+ background: var(--kds-color-warning-main);
6903
+ color: var(--kds-color-warning-contrast);
6904
+ border: none;
5645
6905
  }
5646
6906
 
5647
- /* -- Bank Row Avatar with initials -- */
5648
- .kds-bank-row-logo.initials {
6907
+ button.kds-btn-warning:hover:not(:disabled),
6908
+ a.kds-btn-warning:hover:not(:disabled) {
6909
+ background: var(--kds-color-warning-dark);
6910
+ }
6911
+
6912
+ button.kds-btn-warning:active:not(:disabled),
6913
+ button.kds-btn-warning:focus-visible:not(:disabled),
6914
+ a.kds-btn-warning:active:not(:disabled),
6915
+ a.kds-btn-warning:focus-visible:not(:disabled) {
6916
+ background: var(--kds-color-warning-dark);
6917
+ outline: 2px solid var(--kds-color-warning-main);
6918
+ outline-offset: 2px;
6919
+ }
6920
+
6921
+ button.kds-btn-warning:disabled,
6922
+ a.kds-btn-warning:disabled {
6923
+ background-color: var(--kds-color-action-disabled-bg);
6924
+ color: var(--kds-color-action-disabled);
6925
+ box-shadow: none;
6926
+ }
6927
+
6928
+ button.kds-btn-warning::after {
6929
+ display: none;
6930
+ }
6931
+
6932
+ /* -- Button Error (red / destructive CTA) -- */
6933
+ button.kds-btn-error,
6934
+ a.kds-btn-error {
6935
+ background: var(--kds-color-error-main);
6936
+ color: var(--kds-color-error-contrast);
6937
+ border: none;
6938
+ }
6939
+
6940
+ button.kds-btn-error:hover:not(:disabled),
6941
+ a.kds-btn-error:hover:not(:disabled) {
6942
+ background: var(--kds-color-error-dark);
6943
+ }
6944
+
6945
+ button.kds-btn-error:active:not(:disabled),
6946
+ button.kds-btn-error:focus-visible:not(:disabled),
6947
+ a.kds-btn-error:active:not(:disabled),
6948
+ a.kds-btn-error:focus-visible:not(:disabled) {
6949
+ background: var(--kds-color-error-dark);
6950
+ outline: 2px solid var(--kds-color-error-main);
6951
+ outline-offset: 2px;
6952
+ }
6953
+
6954
+ button.kds-btn-error:disabled,
6955
+ a.kds-btn-error:disabled {
6956
+ background-color: var(--kds-color-action-disabled-bg);
6957
+ color: var(--kds-color-action-disabled);
6958
+ box-shadow: none;
6959
+ }
6960
+
6961
+ button.kds-btn-error::after {
6962
+ display: none;
6963
+ }
6964
+
6965
+ /* -- Field Helper Text -- */
6966
+ .kds-field-helper {
6967
+ font-size: var(--kds-font-size-xs);
6968
+ color: var(--kds-color-text-secondary);
6969
+ margin: var(--kds-spacing-0-75) var(--kds-spacing-1-75) 0;
6970
+ }
6971
+
6972
+ /* -- Bank Row Avatar with initials -- */
6973
+ .kds-bank-row-logo.initials {
5649
6974
  border-radius: var(--kds-radius-full);
5650
6975
  color: #fff;
5651
6976
  font-weight: 700;
@@ -5679,6 +7004,8 @@ button.kds-btn-success::after {
5679
7004
  /* -- Alert inline (borderless, used inside cards) -- */
5680
7005
  .kds-alert-inline {
5681
7006
  border: none;
7007
+ padding: var(--kds-spacing-1) var(--kds-spacing-1-5);
7008
+ margin-bottom: var(--kds-spacing-1-5);
5682
7009
  }
5683
7010
 
5684
7011
  /* -- Card dimmed (behind overlays) -- */
@@ -5700,9 +7027,12 @@ button.kds-btn-success::after {
5700
7027
  display: flex;
5701
7028
  flex-direction: column;
5702
7029
  gap: var(--kds-spacing-1);
5703
- margin-top: var(--kds-spacing-1);
7030
+ margin-bottom: var(--kds-spacing-1);
5704
7031
  }
5705
7032
 
7033
+ .kds-bank-list:last-child {
7034
+ margin-bottom: 0;
7035
+ }
5706
7036
 
5707
7037
  /* -- Field group spacing -- */
5708
7038
  .kds-field-group {
@@ -5755,6 +7085,159 @@ button.kds-btn-success::after {
5755
7085
  margin-top: var(--kds-spacing-2-5);
5756
7086
  }
5757
7087
 
7088
+ /* -- PSP Banner -- */
7089
+ .kds-psp-banner {
7090
+ padding: var(--kds-spacing-0-5) var(--kds-spacing-1-25);
7091
+ font-size: var(--kds-font-size-sm);
7092
+ border-radius: var(--kds-radius-sm);
7093
+ margin-top: var(--kds-spacing-1-5);
7094
+ }
7095
+
7096
+ /* -- Bill Description -- */
7097
+ .kds-bill-description-body {
7098
+ font-family: inherit;
7099
+ white-space: pre-wrap;
7100
+ overflow-wrap: anywhere;
7101
+ margin: 0;
7102
+ padding: 0;
7103
+ background: transparent;
7104
+ color: var(--kds-color-text-secondary);
7105
+ font-size: var(--kds-font-size-sm);
7106
+ line-height: var(--kds-line-height-normal);
7107
+ }
7108
+
7109
+ .kds-bill-description-picture {
7110
+ max-width: 100px;
7111
+ object-fit: contain;
7112
+ background: var(--kds-color-background-paper);
7113
+ margin-top: var(--kds-spacing-1-25);
7114
+ display: block;
7115
+ box-sizing: content-box;
7116
+ }
7117
+
7118
+ /* -- Bill Attachments -- */
7119
+ .kds-bill-attachments {
7120
+ display: flex;
7121
+ flex-direction: column;
7122
+ gap: var(--kds-spacing-0-75);
7123
+ }
7124
+
7125
+ .kds-bill-attachment {
7126
+ display: inline-flex;
7127
+ align-items: center;
7128
+ justify-content: flex-start;
7129
+ width: fit-content;
7130
+ color: var(--kds-color-info-main);
7131
+ font-size: var(--kds-font-size-sm);
7132
+ font-weight: var(--kds-font-weight-medium);
7133
+ text-decoration: none;
7134
+ }
7135
+
7136
+ .kds-bill-attachment:hover span {
7137
+ text-decoration: underline;
7138
+ }
7139
+
7140
+ .kds-bill-attachment i {
7141
+ font-size: var(--kds-font-size-lg);
7142
+ min-width: unset;
7143
+ justify-content: flex-start;
7144
+ }
7145
+
7146
+ /* -- Share Card (mustContinue) -- */
7147
+ .kds-share-card {
7148
+ margin-top: var(--kds-spacing-2);
7149
+ padding: var(--kds-spacing-2);
7150
+ border: var(--kds-border-width-sm) solid var(--kds-color-gray-200);
7151
+ border-radius: var(--kds-radius-lg);
7152
+ background: var(--kds-color-background-paper);
7153
+ }
7154
+
7155
+ .kds-share-eyebrow {
7156
+ font-size: var(--kds-font-size-caption);
7157
+ letter-spacing: var(--kds-letter-spacing-wide);
7158
+ color: var(--kds-color-gray-500);
7159
+ text-transform: uppercase;
7160
+ font-weight: var(--kds-font-weight-bold);
7161
+ margin: 0 0 var(--kds-spacing-0-75);
7162
+ }
7163
+
7164
+ .kds-share-copy {
7165
+ font-size: var(--kds-font-size-body1);
7166
+ line-height: var(--kds-line-height-normal);
7167
+ color: var(--kds-color-gray-800);
7168
+ margin: 0 0 var(--kds-spacing-1-5);
7169
+ }
7170
+
7171
+ .kds-share-divider {
7172
+ height: 0;
7173
+ border: 0;
7174
+ border-top: var(--kds-border-width-sm) dashed var(--kds-color-gray-200);
7175
+ margin: var(--kds-spacing-1-5) 0;
7176
+ }
7177
+
7178
+ .kds-share-link {
7179
+ display: block;
7180
+ font-size: var(--kds-font-size-sm);
7181
+ color: var(--kds-color-primary-main);
7182
+ text-decoration: none;
7183
+ word-break: break-all;
7184
+ margin: 0 0 var(--kds-spacing-1-5);
7185
+ }
7186
+
7187
+ .kds-share-link:hover {
7188
+ text-decoration: underline;
7189
+ }
7190
+
7191
+ .kds-share-action {
7192
+ display: flex;
7193
+ align-items: center;
7194
+ justify-content: center;
7195
+ gap: var(--kds-spacing-0-75);
7196
+ background: none;
7197
+ border: 0;
7198
+ padding: var(--kds-spacing-0-75) var(--kds-spacing-1-25);
7199
+ cursor: pointer;
7200
+ color: var(--kds-color-text-primary);
7201
+ font-size: var(--kds-font-size-sm);
7202
+ font-family: inherit;
7203
+ border-radius: var(--kds-radius-sm);
7204
+ margin: 0 auto;
7205
+ }
7206
+
7207
+ .kds-share-action:hover {
7208
+ background: var(--kds-color-primary-hover);
7209
+ color: var(--kds-color-primary-main);
7210
+ }
7211
+
7212
+ .kds-share-action .material-symbols-outlined {
7213
+ font-size: var(--kds-font-size-2xl);
7214
+ }
7215
+
7216
+ /* -- Participants List (mustContinue) -- */
7217
+ .kds-participants {
7218
+ margin: 0 0 var(--kds-spacing-2);
7219
+ padding: var(--kds-spacing-1-5) var(--kds-spacing-1-75);
7220
+ background: var(--kds-alert-success-bg);
7221
+ border-radius: var(--kds-radius-md);
7222
+ }
7223
+
7224
+ .kds-participants-label {
7225
+ font-size: var(--kds-font-size-xs);
7226
+ font-weight: var(--kds-font-weight-bold);
7227
+ color: var(--kds-alert-success-text);
7228
+ margin: 0 0 var(--kds-spacing-0-75);
7229
+ text-transform: uppercase;
7230
+ letter-spacing: var(--kds-letter-spacing-wide);
7231
+ }
7232
+
7233
+ .kds-participants-list {
7234
+ margin: 0;
7235
+ padding-left: var(--kds-spacing-2);
7236
+ color: var(--kds-alert-success-text);
7237
+ font-size: var(--kds-font-size-sm);
7238
+ line-height: var(--kds-line-height-relaxed);
7239
+ }
7240
+
5758
7241
  /* ================================================================
5759
7242
  PAYMENT FLOW LAYOUT
5760
7243
  Stage, flow container, brand row, screen transitions
@@ -5765,12 +7248,65 @@ button.kds-btn-success::after {
5765
7248
  box-shadow: var(--kds-shadow-card);
5766
7249
  }
5767
7250
 
5768
- /* Payment stagefull-viewport centered wrapper */
7251
+ /* Payment flow cards mobile-first: no vertical padding.
7252
+ Desktop (min-width: 768px) restores padding + full border-radius. */
7253
+ .kds-payment-flow .kds-card-elevated {
7254
+ margin-top: 0;
7255
+ /* Vertical > lateral: la card del flujo respira arriba/abajo (spacing-3)
7256
+ manteniendo el padding lateral del base (spacing-2 / spacing-3 mobile). */
7257
+ padding-top: var(--kds-spacing-3);
7258
+ padding-bottom: var(--kds-spacing-3);
7259
+ }
7260
+
7261
+ /* Reset BeerCSS sibling margin on form/section inside payment cards.
7262
+ BeerCSS sets `:not(.grid,nav,.row) > … + form/section { margin-block-start:1rem }`
7263
+ which adds unwanted spacing inside cards that contain forms. */
7264
+ .kds-payment-flow .kds-card-elevated > form,
7265
+ .kds-payment-flow .kds-card-elevated > section {
7266
+ margin-block-start: 0;
7267
+ }
7268
+ .kds-payment-flow .kds-card-elevated.kds-invoice-sticky {
7269
+ padding-top: var(--kds-spacing-1);
7270
+ padding-bottom: 0;
7271
+ }
7272
+
7273
+ /* Body card: alto mínimo estable para que NO salte entre estados de distinta altura
7274
+ (loader/progress ↔ formulario). Solo la body card = hijo directo de `.kds-screen`
7275
+ (los headers van dentro de `.kds-invoice-sticky-wrap`, no la afecta).
7276
+ Flex-column para que el contenido quede arriba y el footer interno (versión / secure
7277
+ footer) pueda pinearse al fondo con `margin-top: auto` aunque el contenido sea corto. */
7278
+ .kds-screen > .kds-card-elevated {
7279
+ min-height: 36rem;
7280
+ display: flex;
7281
+ flex-direction: column;
7282
+ /* mismo radio que el header (invoice-sticky usa radius-card); el base card-elevated
7283
+ es radius-md (8px) y quedaba distinto al header en desktop. */
7284
+ border-radius: var(--kds-radius-card);
7285
+ }
7286
+
7287
+ /* Variante sin radio superior: pantallas de resultado (éxito/fallo/timeout) que van
7288
+ SIN header arriba — la body card va sola y su tope queda plano (flush) en vez de
7289
+ con esquinas redondeadas sueltas. El padding del card sigue manejando el inset. */
7290
+ /* Tope plano SOLO en mobile (< 768px): la body card se pega al borde superior del widget
7291
+ (igual que el header sticky, que también aplana el tope solo en mobile). En desktop la card
7292
+ va centrada y separada, así que conserva el border-radius superior redondeado. */
7293
+ @media (max-width: 767px) {
7294
+ .kds-screen > .kds-card-elevated.kds-card-elevated--flush-top,
7295
+ .kds-card-elevated.kds-card-elevated--flush-top {
7296
+ border-top-left-radius: 0;
7297
+ border-top-right-radius: 0;
7298
+ }
7299
+ }
7300
+
7301
+ /* Payment stage — full-viewport centered wrapper.
7302
+ Fondo muted (gris) para que las cards blancas (header + body) y el gap entre
7303
+ ellas se distingan; sin esto, card blanca sobre fondo blanco se funden. */
5769
7304
  .kds-payment-stage {
5770
7305
  min-height: 100vh;
5771
7306
  display: flex;
5772
7307
  justify-content: center;
5773
7308
  padding: var(--kds-spacing-2-5) var(--kds-spacing-2) var(--kds-spacing-8);
7309
+ background: var(--kds-color-background-muted);
5774
7310
  }
5775
7311
 
5776
7312
  /* Payment flow — narrow column */
@@ -5785,6 +7321,7 @@ button.kds-btn-success::after {
5785
7321
  /* Mobile: Cards full-width with rounded corners */
5786
7322
  @media (max-width: 767px) {
5787
7323
  .kds-payment-stage {
7324
+ padding-top: 0;
5788
7325
  padding-left: 0;
5789
7326
  padding-right: 0;
5790
7327
  }
@@ -5794,7 +7331,7 @@ button.kds-btn-success::after {
5794
7331
  padding: 0;
5795
7332
  }
5796
7333
 
5797
- /* Cards: rounded corners, full width within padded stage */
7334
+ /* Cards: rounded corners, full width, explicit vertical padding */
5798
7335
  .kds-card-elevated,
5799
7336
  .khipu-card-elevated {
5800
7337
  margin-left: 0;
@@ -5803,6 +7340,36 @@ button.kds-btn-success::after {
5803
7340
  width: 100%;
5804
7341
  }
5805
7342
 
7343
+ .kds-payment-flow .kds-card-elevated {
7344
+ padding-top: var(--kds-spacing-2);
7345
+ padding-bottom: var(--kds-spacing-2);
7346
+ }
7347
+
7348
+ /* Invoice sticky card padding (mobile).
7349
+ Top: estático 12px. Bottom: progresivo 16px (expandido, = desktop) → 8px (colapsado).
7350
+ El padding-bottom animado se reduce al colapsar — sin depender de que el clip-path
7351
+ corte el padding abruptamente. */
7352
+ .kds-payment-flow .kds-card-elevated.kds-invoice-sticky {
7353
+ padding-top: var(--kds-spacing-1-5);
7354
+ padding-bottom: calc(
7355
+ var(--kds-spacing-2)
7356
+ - var(--kds-spacing-1) * var(--collapse-progress, 0)
7357
+ );
7358
+ }
7359
+
7360
+
7361
+ }
7362
+
7363
+ /* Desktop: restore card padding and full border-radius on invoice sticky */
7364
+ @media (min-width: 768px) {
7365
+ .kds-payment-flow .kds-card-elevated,
7366
+ .kds-payment-flow .kds-card-elevated.kds-invoice-sticky {
7367
+ padding-top: var(--kds-spacing-2);
7368
+ padding-bottom: var(--kds-spacing-2);
7369
+ }
7370
+ .kds-card-elevated.kds-invoice-sticky {
7371
+ border-radius: var(--kds-radius-card);
7372
+ }
5806
7373
  }
5807
7374
 
5808
7375
  /* Brand logo row (external, outside cards) */
@@ -5811,7 +7378,8 @@ button.kds-btn-success::after {
5811
7378
  display: flex;
5812
7379
  align-items: center;
5813
7380
  }
5814
- .kds-brand-row svg {
7381
+ .kds-brand-row svg,
7382
+ .kds-brand-row img {
5815
7383
  height: 22px;
5816
7384
  display: block;
5817
7385
  }
@@ -5821,9 +7389,12 @@ button.kds-btn-success::after {
5821
7389
  display: none;
5822
7390
  align-items: center;
5823
7391
  margin-bottom: var(--kds-spacing-1);
7392
+ border-radius: 0;
5824
7393
  }
5825
- .kds-brand-inner svg {
5826
- height: 22px;
7394
+ .kds-brand-inner svg,
7395
+ .kds-brand-inner img {
7396
+ width: calc(50px - 16px * var(--collapse-progress, 0));
7397
+ height: auto;
5827
7398
  display: block;
5828
7399
  }
5829
7400
 
@@ -5835,6 +7406,7 @@ button.kds-btn-success::after {
5835
7406
  .kds-brand-inner {
5836
7407
  display: flex;
5837
7408
  }
7409
+
5838
7410
  }
5839
7411
 
5840
7412
  /* Screen transitions (multi-step flows) */
@@ -5848,8 +7420,8 @@ button.kds-btn-success::after {
5848
7420
  gap: var(--kds-spacing-3);
5849
7421
  }
5850
7422
  @keyframes kds-fadein {
5851
- from { opacity: 0; transform: translateY(var(--kds-spacing-0-5)); }
5852
- to { opacity: 1; transform: none; }
7423
+ from { opacity: 0; }
7424
+ to { opacity: 1; }
5853
7425
  }
5854
7426
 
5855
7427
  /* ================================================================
@@ -6041,7 +7613,7 @@ button.kds-btn-success::after {
6041
7613
  inset: 0;
6042
7614
  background: var(--kds-modal-backdrop);
6043
7615
  display: none;
6044
- align-items: center;
7616
+ align-items: flex-start;
6045
7617
  justify-content: center;
6046
7618
  z-index: var(--kds-z-index-modal, 50);
6047
7619
  animation: kds-fade 0.2s ease both;
@@ -6069,7 +7641,7 @@ button.kds-btn-success::after {
6069
7641
  display: flex;
6070
7642
  align-items: center;
6071
7643
  justify-content: space-between;
6072
- padding: var(--kds-spacing-2) var(--kds-spacing-2) var(--kds-spacing-1);
7644
+ padding: var(--kds-spacing-1) var(--kds-spacing-2) var(--kds-spacing-1);
6073
7645
  }
6074
7646
 
6075
7647
  .kds-bank-modal-header h3 {
@@ -6094,11 +7666,8 @@ button.kds-btn-success::after {
6094
7666
  display: none;
6095
7667
  }
6096
7668
 
6097
- .kds-bank-modal-search {
6098
- padding: 0 var(--kds-spacing-2) var(--kds-spacing-1-5);
6099
- }
6100
-
6101
- .kds-bank-modal-search input {
7669
+ /* Search field reutilizable (standalone o dentro del KdsBankModal). */
7670
+ .kds-search-field {
6102
7671
  width: 100%;
6103
7672
  padding: var(--kds-spacing-1-25) var(--kds-spacing-1-5);
6104
7673
  border: 1px solid var(--kds-color-divider);
@@ -6110,15 +7679,57 @@ button.kds-btn-success::after {
6110
7679
  background: var(--kds-color-surface);
6111
7680
  }
6112
7681
 
6113
- .kds-bank-modal-search input::placeholder {
7682
+ .kds-search-field::placeholder {
6114
7683
  color: var(--kds-color-text-hint);
6115
7684
  }
6116
7685
 
6117
- .kds-bank-modal-search input:focus {
7686
+ .kds-search-field:focus {
6118
7687
  border-color: var(--kds-color-primary-main);
6119
7688
  box-shadow: 0 0 0 2px var(--kds-color-primary-faint);
6120
7689
  }
6121
7690
 
7691
+ /* Variante con ícono (withIcon): lupa posicionada DENTRO del input, a la derecha. */
7692
+ .kds-search-field-wrapper {
7693
+ position: relative;
7694
+ width: 100%;
7695
+ }
7696
+
7697
+ .kds-search-field-icon {
7698
+ position: absolute;
7699
+ right: var(--kds-spacing-1-5);
7700
+ top: 50%;
7701
+ transform: translateY(-50%);
7702
+ font-size: 20px;
7703
+ color: var(--kds-color-text-hint);
7704
+ pointer-events: none;
7705
+ }
7706
+
7707
+ /* Espacio a la derecha del texto para no solaparse con la lupa. */
7708
+ .kds-search-field-wrapper .kds-search-field {
7709
+ padding-right: calc(var(--kds-spacing-1-5) + var(--kds-spacing-3));
7710
+ }
7711
+
7712
+ /* Variante angosta del field (prop `narrow` de KdsTextField): ancho reducido y texto
7713
+ centrado, para inputs de pocos caracteres dispuestos en fila (ej. segmentos de
7714
+ coordenadas o código). No crece ni se encoge dentro de un flex row. */
7715
+ .field.kds-field--narrow {
7716
+ width: 6rem;
7717
+ flex: 0 0 auto;
7718
+ /* En fila horizontal no aplica el margin vertical que BeerCSS da a fields
7719
+ hermanos (regla de "flow" `... + :is(.field,...)`, specificity ~0,3,1);
7720
+ sin el reset los siguientes quedan desalineados hacia abajo. `!important`
7721
+ para ganarle a esa regla de framework. */
7722
+ margin-block: 0 !important;
7723
+ }
7724
+
7725
+ .field.kds-field--narrow > input {
7726
+ text-align: center;
7727
+ }
7728
+
7729
+ .kds-bank-modal-search {
7730
+ padding: 0 var(--kds-spacing-2) var(--kds-spacing-1-5);
7731
+ }
7732
+
6122
7733
  .kds-bank-modal-body {
6123
7734
  flex: 1;
6124
7735
  overflow-y: auto;
@@ -6216,7 +7827,7 @@ button.kds-btn-success::after {
6216
7827
  min-width: 0;
6217
7828
  }
6218
7829
 
6219
- .kds-qr-text .title {
7830
+ .kds-qr-text .kds-qr-title {
6220
7831
  font-family: var(--kds-font-family-primary);
6221
7832
  font-weight: 600;
6222
7833
  font-size: var(--kds-font-size-sm);
@@ -6224,10 +7835,15 @@ button.kds-btn-success::after {
6224
7835
  color: var(--kds-color-text-primary);
6225
7836
  }
6226
7837
 
6227
- .kds-qr-text .sub {
7838
+ .kds-qr-text .kds-qr-subtitle {
6228
7839
  font-family: var(--kds-font-family-primary);
6229
7840
  font-size: var(--kds-font-size-caption);
6230
7841
  color: var(--kds-color-text-secondary);
7842
+ /* Trunca con ellipsis en lugar de wrap a 2 líneas — evita apretar el row
7843
+ cuando el contenedor es angosto (mobile o decorator constrained). */
7844
+ overflow: hidden;
7845
+ text-overflow: ellipsis;
7846
+ white-space: nowrap;
6231
7847
  }
6232
7848
 
6233
7849
  /* QR Badge - "Rápido" indicator */
@@ -6250,46 +7866,26 @@ button.kds-btn-success::after {
6250
7866
  font-size: 20px;
6251
7867
  }
6252
7868
 
6253
- /* Mobile responsive: Ajustes para pantallas pequeñas */
7869
+ /* Mobile responsive (≤480px): respira más mantenemos padding/gap/avatar igual
7870
+ que desktop y solo agregamos truncation al subtitle y `flex-shrink: 0` en los
7871
+ ítems que deben mantener su tamaño (avatar, badge, chevron). */
6254
7872
  @media (max-width: 480px) {
6255
- .kds-qr-row {
6256
- gap: var(--kds-spacing-1-5);
6257
- padding: var(--kds-spacing-1-5);
6258
- }
6259
-
6260
7873
  .kds-qr-avatar {
6261
- width: var(--kds-spacing-4-5);
6262
- height: var(--kds-spacing-4-5);
6263
7874
  flex-shrink: 0;
6264
7875
  }
6265
7876
 
6266
- .kds-qr-avatar .material-symbols-outlined,
6267
- .kds-qr-avatar .material-icons-round {
6268
- font-size: var(--kds-font-size-lg);
6269
- }
6270
-
6271
- .kds-qr-text .title {
6272
- font-size: var(--kds-font-size-xs);
6273
- line-height: var(--kds-line-height-tight);
6274
- }
6275
-
6276
7877
  .kds-qr-text .sub {
6277
- font-size: var(--kds-font-size-caption);
6278
- line-height: var(--kds-line-height-tight);
6279
7878
  overflow: hidden;
6280
7879
  text-overflow: ellipsis;
6281
7880
  white-space: nowrap;
6282
7881
  }
6283
7882
 
6284
7883
  .kds-qr-badge {
6285
- font-size: var(--kds-font-size-caption);
6286
- padding: var(--kds-spacing-0-25) var(--kds-spacing-0-75);
6287
7884
  flex-shrink: 0;
6288
7885
  }
6289
7886
 
6290
7887
  .kds-qr-row .material-symbols-outlined:last-child,
6291
7888
  .kds-qr-row .material-icons-round:last-child {
6292
- font-size: var(--kds-font-size-base);
6293
7889
  flex-shrink: 0;
6294
7890
  }
6295
7891
  }
@@ -6318,7 +7914,11 @@ button.kds-btn-success::after {
6318
7914
  border-radius: var(--kds-spacing-0-75);
6319
7915
  font-size: var(--kds-font-size-sm);
6320
7916
  cursor: pointer;
6321
- transition: background 0.12s ease;
7917
+ /* Transición más amplia y suave: bg + color + border ease-out */
7918
+ transition:
7919
+ background-color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
7920
+ color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
7921
+ border-top-color 280ms ease-out;
6322
7922
  position: relative;
6323
7923
  user-select: none;
6324
7924
  }
@@ -6327,19 +7927,21 @@ button.kds-btn-success::after {
6327
7927
  border-top: 0;
6328
7928
  }
6329
7929
 
6330
- .kds-copyable-table-row:hover {
7930
+ /* Hover NO aplica mientras la row esté en `.copied` o `.settling`
7931
+ (evita el flicker del hover state al desaparecer el verde de "copiado") */
7932
+ .kds-copyable-table-row:not(.copied):not(.settling):hover {
6331
7933
  background: var(--kds-color-primary-faint);
6332
7934
  }
6333
7935
 
6334
- .kds-copyable-table-row:hover + .kds-copyable-table-row {
7936
+ .kds-copyable-table-row:not(.copied):not(.settling):hover + .kds-copyable-table-row {
6335
7937
  border-top-color: transparent;
6336
7938
  }
6337
7939
 
6338
- .kds-copyable-table-row:active {
7940
+ .kds-copyable-table-row:not(.copied):not(.settling):active {
6339
7941
  background: var(--kds-color-primary-selected);
6340
7942
  }
6341
7943
 
6342
- .kds-copyable-table-row .k {
7944
+ .kds-copyable-table-row .kds-key {
6343
7945
  color: var(--kds-color-text-secondary);
6344
7946
  font-size: var(--kds-font-size-caption);
6345
7947
  letter-spacing: 0.3px;
@@ -6348,7 +7950,7 @@ button.kds-btn-success::after {
6348
7950
  flex: 0 0 auto;
6349
7951
  }
6350
7952
 
6351
- .kds-copyable-table-row .v {
7953
+ .kds-copyable-table-row .kds-value {
6352
7954
  color: var(--kds-color-text-primary);
6353
7955
  font-family: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace;
6354
7956
  font-weight: var(--kds-font-weight-medium);
@@ -6364,17 +7966,18 @@ button.kds-btn-success::after {
6364
7966
  flex: 1 1 auto;
6365
7967
  }
6366
7968
 
6367
- .kds-copyable-table-row .v::after {
7969
+ .kds-copyable-table-row .kds-value::after {
6368
7970
  content: 'content_copy';
6369
7971
  font-family: 'Material Symbols Outlined';
6370
7972
  font-size: var(--kds-font-size-sm);
6371
7973
  color: var(--kds-color-primary-main);
6372
7974
  opacity: 0;
6373
- transition: opacity 0.12s ease;
7975
+ /* Transición coordinada con la row */
7976
+ transition: opacity 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
6374
7977
  flex: 0 0 auto;
6375
7978
  }
6376
7979
 
6377
- .kds-copyable-table-row:hover .v::after {
7980
+ .kds-copyable-table-row:not(.copied):not(.settling):hover .kds-value::after {
6378
7981
  opacity: 0.7;
6379
7982
  }
6380
7983
 
@@ -6382,22 +7985,76 @@ button.kds-btn-success::after {
6382
7985
  background: var(--kds-color-success-soft);
6383
7986
  }
6384
7987
 
6385
- .kds-copyable-table-row.copied .v {
7988
+ .kds-copyable-table-row.copied .kds-value {
6386
7989
  color: var(--kds-color-success-dark);
6387
7990
  }
6388
7991
 
6389
- .kds-copyable-table-row.copied .v::after {
7992
+ .kds-copyable-table-row.copied .kds-value::after {
6390
7993
  content: 'check';
6391
7994
  font-family: 'Material Symbols Outlined';
6392
7995
  color: var(--kds-color-success-dark);
6393
7996
  opacity: 1;
6394
7997
  }
6395
7998
 
7999
+ /* `.settling`: estado de "recién copiado" — la row vuelve al normal sin
8000
+ activar hover. Dura lo mismo que la transición (~300ms) y se aplica
8001
+ desde React tras quitar `.copied`. */
8002
+ .kds-copyable-table-row.settling .kds-value::after {
8003
+ /* Mantén el check con opacity 0 mientras settling, fade out suave */
8004
+ opacity: 0;
8005
+ }
8006
+
6396
8007
  /* Disable BeerCSS ripple on copyable table rows */
6397
8008
  .kds-copyable-table-row::after {
6398
8009
  display: none;
6399
8010
  }
6400
8011
 
8012
+ /* ========================================
8013
+ GRID VARIANT (.kds-copyable-table--grid)
8014
+ Read-only grid of N text cells per row. No copy,
8015
+ no role=button, no "copy all". Cells share the row
8016
+ width equally. Used inside radio options, etc.
8017
+ ======================================== */
8018
+
8019
+ /* La grilla es solo columnas de texto (como el DataTable original): sin caja,
8020
+ borde, fondo ni sombra del contenedor copyable. */
8021
+ .kds-copyable-table--grid {
8022
+ border: 0;
8023
+ border-radius: 0;
8024
+ background: none;
8025
+ padding: 0;
8026
+ box-shadow: none;
8027
+ }
8028
+
8029
+ .kds-copyable-table-row--grid {
8030
+ display: flex;
8031
+ align-items: center;
8032
+ gap: var(--kds-spacing-1-5);
8033
+ padding: 0;
8034
+ /* Sin el divisor border-top que trae la fila base del copyable. */
8035
+ border-top: 0;
8036
+ cursor: default;
8037
+ user-select: text;
8038
+ }
8039
+
8040
+ /* Separación entre filas de la grilla (sin divisores). */
8041
+ .kds-copyable-table-row--grid + .kds-copyable-table-row--grid {
8042
+ margin-top: var(--kds-spacing-0-5);
8043
+ }
8044
+
8045
+ .kds-grid-cell {
8046
+ flex: 1 1 0;
8047
+ min-width: 0;
8048
+ font-size: var(--kds-font-size-sm);
8049
+ font-weight: var(--kds-font-weight-medium);
8050
+ color: var(--kds-color-text-primary);
8051
+ word-break: break-word;
8052
+ }
8053
+
8054
+ .kds-grid-cell--disabled {
8055
+ color: var(--kds-color-text-disabled);
8056
+ }
8057
+
6401
8058
  /* ========================================
6402
8059
  COPY-ALL BUTTON (.kds-copy-all-btn)
6403
8060
  Modifier for kds-btn kds-btn-outlined that adds
@@ -6455,6 +8112,14 @@ a.kds-copy-all-btn.copied:hover {
6455
8112
  min-height: unset;
6456
8113
  }
6457
8114
 
8115
+ /* Severity variants — default stays warning (backward-compatible) */
8116
+ .kds-section-note.kds-info { color: var(--kds-color-info-dark); }
8117
+ .kds-section-note.kds-info > i { color: var(--kds-color-info-dark); }
8118
+ .kds-section-note.kds-success { color: var(--kds-color-success-dark); }
8119
+ .kds-section-note.kds-success > i { color: var(--kds-color-success-dark); }
8120
+ .kds-section-note.kds-error { color: var(--kds-color-error-dark); }
8121
+ .kds-section-note.kds-error > i { color: var(--kds-color-error-dark); }
8122
+
6458
8123
  /* ========================================
6459
8124
  INFO TOOLTIP (.kds-info-tip)
6460
8125
  Inline info button with hover/click tooltip bubble.
@@ -6550,7 +8215,7 @@ a.kds-copy-all-btn.copied:hover {
6550
8215
  .kds-monto-row {
6551
8216
  display: flex;
6552
8217
  justify-content: space-between;
6553
- align-items: flex-end;
8218
+ align-items: flex-start;
6554
8219
  padding: var(--kds-spacing-1-75) 0 var(--kds-spacing-1);
6555
8220
  border-top: 1px dashed var(--kds-color-divider);
6556
8221
  margin-top: var(--kds-spacing-1-75);
@@ -6574,3 +8239,191 @@ a.kds-copy-all-btn.copied:hover {
6574
8239
  color: var(--kds-color-text-primary);
6575
8240
  }
6576
8241
 
8242
+ /* ========================================
8243
+ PAYMENT TOTAL (.kds-payment-total)
8244
+ Bloque "monto a pagar" para QR view y email templates.
8245
+ Portado desde paylink-ligopay → <kh:paymentTotal> + materialize-config.css.
8246
+ Variantes:
8247
+ - default: amount grande (3rem) en color primario Khipu.
8248
+ - email: amount compacto (1.5rem) en color texto primario.
8249
+ Responsive (default): mobile (≤ 1024px) centra y oculta titleMobile.
8250
+ ======================================== */
8251
+
8252
+ .kds-payment-total {
8253
+ /* Component-scoped tokens — overrideables sin tocar el CSS global. */
8254
+ --kds-payment-total-title-size: var(--kds-font-size-2xl); /* 24px */
8255
+ --kds-payment-total-label-size: var(--kds-font-size-xl); /* 20px */
8256
+ --kds-payment-amount-size: 3rem; /* 48px — destacado */
8257
+ --kds-payment-amount-line-height: var(--kds-line-height-snug);
8258
+ --kds-payment-amount-color: var(--kds-color-primary-main);
8259
+ --kds-payment-amount-weight: var(--kds-font-weight-medium);
8260
+
8261
+ text-align: left;
8262
+ }
8263
+
8264
+ .kds-payment-total-title,
8265
+ .kds-payment-total-title-mobile {
8266
+ font-size: var(--kds-payment-total-title-size);
8267
+ font-weight: var(--kds-font-weight-semibold);
8268
+ color: var(--kds-color-text-primary);
8269
+ margin-bottom: var(--kds-spacing-4);
8270
+ }
8271
+
8272
+ .kds-payment-total-title-mobile {
8273
+ display: none;
8274
+ }
8275
+
8276
+ .kds-payment-total .kds-payment-label {
8277
+ font-size: var(--kds-payment-total-label-size);
8278
+ font-weight: var(--kds-font-weight-semibold);
8279
+ color: var(--kds-color-text-primary);
8280
+ margin-bottom: var(--kds-spacing-1);
8281
+ padding-top: 0;
8282
+ }
8283
+
8284
+ .kds-payment-total .kds-payment-amount {
8285
+ font-size: var(--kds-payment-amount-size);
8286
+ font-weight: var(--kds-payment-amount-weight);
8287
+ line-height: var(--kds-payment-amount-line-height);
8288
+ color: var(--kds-payment-amount-color);
8289
+ margin-bottom: var(--kds-spacing-4);
8290
+ }
8291
+
8292
+ .kds-payment-total .kds-payment-amount .kds-payment-total-decimal-sup,
8293
+ .kds-invoice-amount .kds-payment-total-decimal-sup {
8294
+ font-size: var(--kds-font-size-decimal-sup);
8295
+ font-weight: var(--kds-font-weight-semibold);
8296
+ position: relative;
8297
+ top: 0;
8298
+ }
8299
+
8300
+ /* Variante email: amount compacto en color texto primario, alineación izquierda fija */
8301
+ .kds-payment-total--email {
8302
+ --kds-payment-amount-size: var(--kds-font-size-2xl); /* 24px */
8303
+ --kds-payment-amount-line-height: var(--kds-line-height-snug);
8304
+ --kds-payment-amount-color: var(--kds-color-text-primary);
8305
+ --kds-payment-amount-weight: var(--kds-font-weight-semibold);
8306
+ }
8307
+
8308
+ /* Tone modifier: swaps the amount color to the khipu-blue / LigoPay info blue.
8309
+ Combinable with --email or with the default variant. */
8310
+ .kds-payment-total--tone-info {
8311
+ --kds-payment-amount-color: var(--kds-color-info-blue); /* #5A5FE0 */
8312
+ }
8313
+
8314
+ /* Centered modifier: removes the asymmetric desktop padding (which exists for
8315
+ LigoPay QR view) and centers all internal text. Composable with --email and
8316
+ --tone-info. */
8317
+ .kds-payment-total--centered {
8318
+ padding-left: 0;
8319
+ padding-top: 0;
8320
+ text-align: center;
8321
+ }
8322
+ .kds-payment-total--centered .kds-payment-total-title,
8323
+ .kds-payment-total--centered .kds-payment-total-title-mobile,
8324
+ .kds-payment-total--centered .kds-payment-label,
8325
+ .kds-payment-total--centered .kds-payment-amount {
8326
+ text-align: center;
8327
+ }
8328
+
8329
+ /* Responsive: mobile ≤ 1024px — centra y conmuta los títulos (sólo variante default) */
8330
+ @media (max-width: 1024px) {
8331
+ .kds-payment-total {
8332
+ text-align: center;
8333
+ }
8334
+
8335
+ .kds-payment-total .kds-payment-total-title {
8336
+ display: none;
8337
+ }
8338
+
8339
+ .kds-payment-total .kds-payment-total-title-mobile {
8340
+ display: block;
8341
+ text-align: center;
8342
+ }
8343
+
8344
+ .kds-payment-total .kds-payment-label,
8345
+ .kds-payment-total .kds-payment-amount {
8346
+ text-align: center;
8347
+ }
8348
+
8349
+ /* Email mantiene alineación izquierda incluso en mobile (matchea email clients) */
8350
+ .kds-payment-total--email,
8351
+ .kds-payment-total--email .kds-payment-label,
8352
+ .kds-payment-total--email .kds-payment-amount {
8353
+ text-align: left;
8354
+ }
8355
+ }
8356
+
8357
+ /* ==========================================================================
8358
+ GRID UTILITIES — semantic aliases for BeerCSS .grid / .s* / .m* / .l*
8359
+
8360
+ Estas utilidades son ALIAS de las clases cortas de BeerCSS para que
8361
+ consumers (payment, LigoPay, Grails legacy) puedan escribir markup con
8362
+ nombres descriptivos sin renunciar al grid de 12 columnas de BeerCSS.
8363
+
8364
+ Convención (estilo Bootstrap responsive):
8365
+ - kds-grid → .grid (12-col CSS grid + 1rem gap)
8366
+ - kds-col-sm-{1..12} → .s{1..12} (mobile, siempre aplica)
8367
+ - kds-col-md-{1..12} → .m{1..12} (>=601px)
8368
+ - kds-col-lg-{1..12} → .l{1..12} (>=993px)
8369
+
8370
+ Las definiciones originales de BeerCSS NO se tocan; estas son aditivas.
8371
+ ========================================================================== */
8372
+
8373
+ .kds-grid {
8374
+ --_gap: 1rem;
8375
+ display: grid;
8376
+ grid-template-columns: repeat(12, 1fr);
8377
+ gap: var(--_gap);
8378
+ block-size: auto;
8379
+ }
8380
+
8381
+ .kds-grid.kds-grid-no-space { --_gap: 0rem; }
8382
+ .kds-grid.kds-grid-medium-space { --_gap: 1.5rem; }
8383
+ .kds-grid.kds-grid-large-space { --_gap: 2rem; }
8384
+
8385
+ .kds-grid > * { margin: 0; }
8386
+
8387
+ .kds-col-sm-1 { grid-area: auto/span 1; }
8388
+ .kds-col-sm-2 { grid-area: auto/span 2; }
8389
+ .kds-col-sm-3 { grid-area: auto/span 3; }
8390
+ .kds-col-sm-4 { grid-area: auto/span 4; }
8391
+ .kds-col-sm-5 { grid-area: auto/span 5; }
8392
+ .kds-col-sm-6 { grid-area: auto/span 6; }
8393
+ .kds-col-sm-7 { grid-area: auto/span 7; }
8394
+ .kds-col-sm-8 { grid-area: auto/span 8; }
8395
+ .kds-col-sm-9 { grid-area: auto/span 9; }
8396
+ .kds-col-sm-10 { grid-area: auto/span 10; }
8397
+ .kds-col-sm-11 { grid-area: auto/span 11; }
8398
+ .kds-col-sm-12 { grid-area: auto/span 12; }
8399
+
8400
+ @media only screen and (min-width: 601px) {
8401
+ .kds-col-md-1 { grid-area: auto/span 1; }
8402
+ .kds-col-md-2 { grid-area: auto/span 2; }
8403
+ .kds-col-md-3 { grid-area: auto/span 3; }
8404
+ .kds-col-md-4 { grid-area: auto/span 4; }
8405
+ .kds-col-md-5 { grid-area: auto/span 5; }
8406
+ .kds-col-md-6 { grid-area: auto/span 6; }
8407
+ .kds-col-md-7 { grid-area: auto/span 7; }
8408
+ .kds-col-md-8 { grid-area: auto/span 8; }
8409
+ .kds-col-md-9 { grid-area: auto/span 9; }
8410
+ .kds-col-md-10 { grid-area: auto/span 10; }
8411
+ .kds-col-md-11 { grid-area: auto/span 11; }
8412
+ .kds-col-md-12 { grid-area: auto/span 12; }
8413
+ }
8414
+
8415
+ @media only screen and (min-width: 993px) {
8416
+ .kds-col-lg-1 { grid-area: auto/span 1; }
8417
+ .kds-col-lg-2 { grid-area: auto/span 2; }
8418
+ .kds-col-lg-3 { grid-area: auto/span 3; }
8419
+ .kds-col-lg-4 { grid-area: auto/span 4; }
8420
+ .kds-col-lg-5 { grid-area: auto/span 5; }
8421
+ .kds-col-lg-6 { grid-area: auto/span 6; }
8422
+ .kds-col-lg-7 { grid-area: auto/span 7; }
8423
+ .kds-col-lg-8 { grid-area: auto/span 8; }
8424
+ .kds-col-lg-9 { grid-area: auto/span 9; }
8425
+ .kds-col-lg-10 { grid-area: auto/span 10; }
8426
+ .kds-col-lg-11 { grid-area: auto/span 11; }
8427
+ .kds-col-lg-12 { grid-area: auto/span 12; }
8428
+ }
8429
+