@khipu/design-system 0.2.0-alpha.12 → 0.2.0-alpha.121

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-18T16:52:10.770Z
14
+ * Generated: 2026-07-15T15:17:25.725Z
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;
@@ -69,6 +75,7 @@
69
75
  --kds-color-background-paper: #FFFFFF;
70
76
  --kds-color-background-elevated: #FAFAFA;
71
77
  --kds-color-background-muted: #F4F4F7;
78
+ --kds-color-background-brand-subtle: #F0F0FA;
72
79
 
73
80
  /* Action colors */
74
81
  --kds-color-action-active: rgba(0, 0, 0, 0.56);
@@ -134,6 +141,8 @@
134
141
  --kds-font-weight-bold: 700;
135
142
 
136
143
  /* Font sizes (base scale xs–4xl: see responsive section below) */
144
+ --kds-font-size-decimal-sup: 0.5em;
145
+
137
146
  /* Line heights */
138
147
  --kds-line-height-tight: 1.2;
139
148
  --kds-line-height-snug: 1.375;
@@ -355,6 +364,7 @@
355
364
  RESPONSIVE TYPOGRAPHY (MOBILE BASE)
356
365
  ========================================================================== */
357
366
 
367
+ --kds-font-size-2xs: 0.5625rem;
358
368
 
359
369
  /* Base font-size scale */
360
370
  --kds-font-size-xs: 0.6875rem;
@@ -402,6 +412,7 @@
402
412
  /* Tablet (600px+) - Typography */
403
413
  @media (min-width: 600px) {
404
414
  :root {
415
+ --kds-font-size-2xs: 0.625rem;
405
416
 
406
417
  /* Base font-size scale */
407
418
  --kds-font-size-xs: 0.75rem;
@@ -439,6 +450,7 @@
439
450
  /* Desktop (840px+) - Typography */
440
451
  @media (min-width: 840px) {
441
452
  :root {
453
+ --kds-font-size-2xs: 0.625rem;
442
454
 
443
455
  /* Base font-size scale */
444
456
  --kds-font-size-xs: 0.75rem;
@@ -688,7 +700,8 @@ body.dark {
688
700
  --kds-color-danger-soft: var(--kds-alert-error-bg); /* #FEF2F2 */
689
701
 
690
702
  /* Bottom Sheet */
691
- --kds-bottom-sheet-max-width: 480px;
703
+ /* Mismo ancho que la card principal del flujo (stage narrow). */
704
+ --kds-bottom-sheet-max-width: var(--kds-stage-narrow-max-width);
692
705
  --kds-bottom-sheet-shadow: 0 -8px var(--kds-spacing-3-5) rgba(0, 0, 0, 0.18);
693
706
 
694
707
  /* Status Block */
@@ -839,6 +852,10 @@ a.kds-btn {
839
852
  /* Spacing - Using design tokens */
840
853
  padding: var(--kds-spacing-button-padding); /* 0 16px */
841
854
  height: var(--kds-spacing-button-min-height); /* 44px */
855
+ /* min-height además de height: en contenedores flex-column (p.ej. pantallas de
856
+ resultado/timeout) el botón es flex-item y, con solo `height`, flex-shrink lo
857
+ colapsaba a la altura del texto (~21px). min-height impide que se encoja. */
858
+ min-height: var(--kds-spacing-button-min-height); /* 44px */
842
859
 
843
860
  /* Border - Using design token */
844
861
  border-radius: var(--kds-radius-button); /* 10px */
@@ -846,7 +863,10 @@ a.kds-btn {
846
863
 
847
864
  /* Interaction */
848
865
  cursor: pointer;
849
- transition: background .15s, box-shadow .15s, transform .05s;
866
+ transition: background-color var(--kds-transition-shorter) var(--kds-easing-standard),
867
+ color var(--kds-transition-shorter) var(--kds-easing-standard),
868
+ box-shadow var(--kds-transition-shorter) var(--kds-easing-standard),
869
+ transform var(--kds-transition-shortest) var(--kds-easing-standard);
850
870
  box-sizing: border-box;
851
871
  vertical-align: middle;
852
872
  }
@@ -978,7 +998,7 @@ a.kds-btn-text {
978
998
 
979
999
  button.kds-btn-text:hover:not(:disabled),
980
1000
  a.kds-btn-text:hover:not(:disabled) {
981
- background: var(--kds-color-primary-hover); /* rgba(131, 71, 173, 0.04) */
1001
+ color: var(--kds-color-primary-dark);
982
1002
  }
983
1003
 
984
1004
  button.kds-btn-text:disabled,
@@ -988,6 +1008,30 @@ a.kds-btn-text:disabled {
988
1008
  box-shadow: none;
989
1009
  }
990
1010
 
1011
+ /* Error text (destructive, ghost) — red text, no fill/border. Para acciones
1012
+ destructivas secundarias que no deben competir con el CTA primario. */
1013
+ button.kds-btn-error-text,
1014
+ a.kds-btn-error-text {
1015
+ background: transparent;
1016
+ color: var(--kds-color-error-main);
1017
+ border: none;
1018
+ padding: 6px var(--kds-spacing-2);
1019
+ min-height: 32px;
1020
+ box-shadow: none;
1021
+ }
1022
+
1023
+ button.kds-btn-error-text:hover:not(:disabled),
1024
+ a.kds-btn-error-text:hover:not(:disabled) {
1025
+ color: var(--kds-color-error-dark);
1026
+ }
1027
+
1028
+ button.kds-btn-error-text:disabled,
1029
+ a.kds-btn-error-text:disabled {
1030
+ background: transparent;
1031
+ color: var(--kds-color-action-disabled);
1032
+ box-shadow: none;
1033
+ }
1034
+
991
1035
  /* Icon wrapper - control size via span container */
992
1036
  button.kds-btn > .kds-icon,
993
1037
  a.kds-btn > .kds-icon {
@@ -1073,63 +1117,90 @@ a.kds-btn.kds-btn-md {
1073
1117
  }
1074
1118
  }
1075
1119
 
1076
- /* Selection card */
1120
+ /* Selection card.
1121
+ IMPORTANTE: este componente se renderiza como `<button>`. BeerCSS aplica al
1122
+ `button` base: `display: inline-flex; align-items: center; justify-content: center;
1123
+ block-size: 2.5rem; padding: 0 1rem; background: var(--primary); color: on-primary`.
1124
+ Todas esas reglas hay que sobreescribirlas para que el card-selector funcione como
1125
+ un contenedor flex column de altura variable y alineado a la izquierda.
1126
+
1127
+ Convención del DS: spacing entre hijos via `gap` del flex padre + padding.
1128
+ Los elementos internos (.kds-card-selector-icon/-title/-description) NO usan margin. */
1077
1129
  .kds-card-selector {
1130
+ /* Reset BeerCSS button */
1131
+ display: flex;
1132
+ flex-direction: column;
1133
+ align-items: stretch;
1134
+ justify-content: flex-start;
1135
+ block-size: auto;
1136
+ inline-size: 100%;
1137
+ text-align: left;
1138
+ line-height: 1.5;
1139
+ color: var(--kds-color-text-primary);
1140
+ /* Estilos propios del card-selector */
1078
1141
  padding: var(--kds-spacing-3);
1142
+ gap: var(--kds-spacing-1-5);
1079
1143
  border-radius: var(--kds-radius-md);
1080
- border: 2px solid var(--kds-border-light);
1144
+ border: var(--kds-border-width-md) solid var(--kds-border-light);
1081
1145
  background: var(--kds-color-background-paper);
1082
1146
  transition: all 0.3s ease;
1083
- text-align: left;
1084
1147
  cursor: pointer;
1085
- display: flex;
1086
- flex-direction: column;
1087
1148
  }
1088
1149
 
1089
- .kds-card-selector:hover {
1090
- border-color: #D1D5DB; /* gray-300 */
1150
+ .kds-card-selector:hover:not(.selected) {
1151
+ border-color: var(--kds-color-primary-light);
1152
+ background: var(--kds-color-primary-hover);
1153
+ }
1154
+
1155
+ /* Override del ripple/overlay default de BeerCSS:
1156
+ `:is(.wave,.chip,.button,button,nav.tabbed>a,...):not([class*=ripple])::after`
1157
+ tiene specificity (0,2,4) según DevTools (Chrome cuenta cada selector dentro
1158
+ de :is() individualmente para algunos motores). Usamos !important — consistente
1159
+ con cómo se overridean otros estilos de BeerCSS en este archivo (67 usos previos).
1160
+ Antes pintaba negro porque `currentColor` resolvía a text-primary del card. */
1161
+ .kds-card-selector::after {
1162
+ background-image: radial-gradient(circle, var(--kds-color-primary-main) 1%, transparent 1%) !important;
1091
1163
  }
1092
1164
 
1093
1165
  .kds-card-selector.selected {
1094
- border-color: #3B82F6; /* blue-600 */
1095
- background: #EFF6FF; /* blue-50 */
1166
+ border-color: var(--kds-color-primary-main);
1167
+ background: var(--kds-color-primary-faint);
1096
1168
  box-shadow: var(--kds-shadow-md);
1097
1169
  }
1098
1170
 
1099
- /* Icon container */
1171
+ /* Icon container — spacing manejado por gap del padre, no margin */
1100
1172
  .kds-card-selector-icon {
1101
- width: 48px;
1102
- height: 48px;
1103
- background: #DBEAFE; /* blue-100 */
1104
- border-radius: 8px;
1173
+ width: var(--kds-spacing-6);
1174
+ height: var(--kds-spacing-6);
1175
+ background: var(--kds-color-primary-focus);
1176
+ border-radius: var(--kds-radius-sm);
1105
1177
  display: flex;
1106
1178
  align-items: center;
1107
1179
  justify-content: center;
1108
- margin-bottom: 16px;
1109
1180
  }
1110
1181
 
1111
1182
  .kds-card-selector-icon i,
1112
1183
  .kds-card-selector-icon svg {
1113
- width: 24px;
1114
- height: 24px;
1115
- min-width: 24px;
1116
- min-height: 24px;
1117
- color: #3B82F6; /* blue-600 */
1184
+ width: var(--kds-spacing-3);
1185
+ height: var(--kds-spacing-3);
1186
+ min-width: var(--kds-spacing-3);
1187
+ min-height: var(--kds-spacing-3);
1188
+ font-size: var(--kds-spacing-3);
1189
+ color: var(--kds-color-primary-main);
1118
1190
  }
1119
1191
 
1120
- /* Title */
1192
+ /* Title — spacing manejado por gap del padre, no margin */
1121
1193
  .kds-card-selector-title {
1122
- font-weight: 600;
1194
+ font-weight: var(--kds-font-weight-semibold);
1123
1195
  color: var(--kds-color-text-primary);
1124
- margin-bottom: 8px;
1125
- font-size: 16px;
1196
+ font-size: var(--kds-font-size-lg);
1126
1197
  }
1127
1198
 
1128
1199
  /* Description */
1129
1200
  .kds-card-selector-description {
1130
- font-size: 14px;
1131
- color: #4B5563; /* gray-600 */
1132
- line-height: 1.5;
1201
+ font-size: var(--kds-font-size-sm);
1202
+ color: var(--kds-color-text-secondary);
1203
+ line-height: var(--kds-line-height-normal);
1133
1204
  }
1134
1205
 
1135
1206
  /* Selected state - visual feedback via border only */
@@ -1141,14 +1212,22 @@ a.kds-btn.kds-btn-md {
1141
1212
  display: flex;
1142
1213
  flex-direction: column;
1143
1214
  gap: var(--kds-spacing-2);
1144
- padding: var(--kds-spacing-4);
1215
+ padding: var(--kds-spacing-2);
1145
1216
  border-radius: var(--kds-radius-lg);
1146
1217
  border: 2px solid var(--kds-border-medium);
1147
- max-width: 400px; /* Increased from 365px for better text spacing */
1218
+ /* Ancho mínimo aplicado a TODOS los planes así un plan sin badge en una
1219
+ grilla con un plan recomendado mantiene la misma anchura, y el badge nunca
1220
+ se superpone al título por estrechez del card. */
1221
+ min-width: 260px;
1222
+ max-width: 400px;
1148
1223
  background: var(--kds-surface-base);
1149
1224
  transition: all 0.3s ease;
1150
1225
  cursor: pointer;
1151
- height: 100%; /* Ensure cards fill grid height */
1226
+ /* Alto fijo: el card se estira al alto de su row del grid (align-items stretch
1227
+ es el default) — todas las cards de la misma fila quedan a la misma altura
1228
+ sin importar el contenido. `align-self: stretch` lo hace explícito. */
1229
+ height: 100%;
1230
+ align-self: stretch;
1152
1231
  }
1153
1232
 
1154
1233
  .kds-card-plan:hover {
@@ -1168,18 +1247,19 @@ a.kds-btn.kds-btn-md {
1168
1247
  box-shadow: var(--kds-shadow-elevation-4);
1169
1248
  }
1170
1249
 
1171
- /* Recommended Badge */
1250
+ /* Recommended Badge — inline dentro del card (no flotante).
1251
+ Es el primer hijo del .kds-card-plan, así que aparece arriba de todo
1252
+ el contenido, alineado a la izquierda. */
1172
1253
  .kds-card-plan-badge {
1173
- position: absolute;
1174
- top: -12px;
1175
- right: var(--kds-spacing-6);
1176
- padding: var(--kds-spacing-1) var(--kds-spacing-4);
1254
+ align-self: flex-start;
1255
+ padding: var(--kds-spacing-0-5) var(--kds-spacing-1-5);
1177
1256
  background: var(--primary);
1178
1257
  color: white;
1179
- font-size: var(--kds-font-size-sm);
1258
+ font-size: var(--kds-font-size-xs);
1180
1259
  font-weight: var(--kds-font-weight-semibold);
1260
+ line-height: 1;
1181
1261
  border-radius: var(--kds-radius-full);
1182
- box-shadow: var(--kds-shadow-elevation-1);
1262
+ white-space: nowrap;
1183
1263
  }
1184
1264
 
1185
1265
  /* Plan Header */
@@ -1207,13 +1287,11 @@ a.kds-btn.kds-btn-md {
1207
1287
  display: flex;
1208
1288
  align-items: baseline;
1209
1289
  gap: var(--kds-spacing-2);
1210
- padding: var(--kds-spacing-4) 0;
1211
1290
  border-bottom: 1px solid var(--kds-border-light);
1212
- min-height: 88px; /* Standardize price area height */
1213
1291
  }
1214
1292
 
1215
1293
  .kds-price {
1216
- font-size: 42px;
1294
+ font-size: var(--kds-font-size-4xl);
1217
1295
  font-weight: var(--kds-font-weight-bold);
1218
1296
  color: var(--primary);
1219
1297
  line-height: 1.1;
@@ -1468,7 +1546,63 @@ a.kds-btn.kds-btn-md {
1468
1546
  align-items: flex-end;
1469
1547
  }
1470
1548
 
1549
+ .kds-self-center {
1550
+ align-self: center;
1551
+ }
1552
+
1553
+ /* Botón "pelado": neutraliza el chrome de button de BeerCSS (pill 2.5rem,
1554
+ radius, fondo y hover) para botones de terceros con su propio look,
1555
+ p.ej. los share buttons de react-share (ícono circular). */
1556
+ .kds-btn-bare,
1557
+ .kds-btn-bare:hover,
1558
+ .kds-btn-bare:focus,
1559
+ .kds-btn-bare:active {
1560
+ background: none !important;
1561
+ block-size: auto !important;
1562
+ inline-size: auto !important;
1563
+ min-inline-size: 0 !important;
1564
+ padding: 0 !important;
1565
+ margin: 0 !important;
1566
+ border: 0 !important;
1567
+ border-radius: var(--kds-radius-full) !important;
1568
+ box-sizing: border-box !important;
1569
+ box-shadow: none !important;
1570
+ transform: none !important;
1571
+ }
1572
+
1573
+ .kds-btn-bare::before,
1574
+ .kds-btn-bare::after {
1575
+ display: none !important;
1576
+ }
1577
+
1578
+ /* BeerCSS también encoge los íconos hijos de button a 1.5rem (min/max);
1579
+ un botón pelado respeta el tamaño propio del ícono. */
1580
+ .kds-btn-bare > :is(img, svg) {
1581
+ max-block-size: none !important;
1582
+ max-inline-size: none !important;
1583
+ min-block-size: 0 !important;
1584
+ min-inline-size: 0 !important;
1585
+ }
1586
+
1587
+ /* Versión de la app anclada al fondo del card body (flex column): margin-top
1588
+ auto absorbe el espacio libre; el padding garantiza respiro mínimo cuando el
1589
+ contenido llena la card. */
1590
+ .kds-card-version {
1591
+ margin-top: auto;
1592
+ padding-top: var(--kds-spacing-2);
1593
+ text-align: center;
1594
+ }
1595
+
1596
+ /* Separador vertical (entre chips/logos hermanos en una fila). */
1597
+ .kds-vr {
1598
+ width: 1px;
1599
+ height: var(--kds-spacing-3);
1600
+ background: var(--kds-color-divider);
1601
+ flex: 0 0 auto;
1602
+ }
1603
+
1471
1604
  /* Gap utilities */
1605
+ .kds-gap-0-25 { gap: var(--kds-spacing-0-25); }
1472
1606
  .kds-gap-1 { gap: var(--kds-spacing-1); }
1473
1607
  .kds-gap-2 { gap: var(--kds-spacing-2); }
1474
1608
  .kds-gap-3 { gap: var(--kds-spacing-3); }
@@ -1504,6 +1638,7 @@ a.kds-btn.kds-btn-md {
1504
1638
  /* Spacing utilities - Margin */
1505
1639
  .kds-m-0 { margin: 0; }
1506
1640
  .kds-m-2 { margin: var(--kds-spacing-2); }
1641
+ .kds-m-2-5 { margin: var(--kds-spacing-2-5); }
1507
1642
  .kds-m-4 { margin: var(--kds-spacing-4); }
1508
1643
  .kds-m-6 { margin: var(--kds-spacing-6); }
1509
1644
  .kds-m-8 { margin: var(--kds-spacing-8); }
@@ -1517,6 +1652,7 @@ a.kds-btn.kds-btn-md {
1517
1652
  .kds-mt-8 { margin-top: var(--kds-spacing-8); }
1518
1653
 
1519
1654
  .kds-mb-0 { margin-bottom: 0; }
1655
+ .kds-mb-0-5 { margin-bottom: var(--kds-spacing-0-5); }
1520
1656
  .kds-mb-1 { margin-bottom: var(--kds-spacing-1); }
1521
1657
  .kds-mb-2 { margin-bottom: var(--kds-spacing-2); }
1522
1658
  .kds-mb-3 { margin-bottom: var(--kds-spacing-3); }
@@ -2029,6 +2165,226 @@ a.kds-btn-google:disabled {
2029
2165
  height: var(--kds-spacing-button-icon-size);
2030
2166
  }
2031
2167
 
2168
+ /* ========================================
2169
+ KDS LINEAR PROGRESS
2170
+ Native <progress> (KdsLinearProgress). Additive over BeerCSS `progress`,
2171
+ scoped to .kds-progress so other consumers are unaffected.
2172
+ ======================================== */
2173
+
2174
+ /* `progress` is inline-block by default → leaves a baseline (descender) gap
2175
+ below the bar. Block removes that gap so it sits flush with siblings. */
2176
+ .kds-progress {
2177
+ display: block;
2178
+ }
2179
+
2180
+ /* Animate the filled value when it changes (e.g. advancing a step). BeerCSS
2181
+ sets the value background but no transition, so the width jumps abruptly. */
2182
+ .kds-progress::-webkit-progress-value {
2183
+ transition: width var(--kds-transition-standard) var(--kds-easing-standard);
2184
+ }
2185
+
2186
+ .kds-progress::-moz-progress-bar {
2187
+ transition: width var(--kds-transition-standard) var(--kds-easing-standard);
2188
+ }
2189
+
2190
+ /* ========================================
2191
+ KDS SECURE LOADER
2192
+ Loader de espera: anillo circular + candado centrado + frases opcionales.
2193
+ El anillo reutiliza el spinner circular de BeerCSS, escalado.
2194
+ ======================================== */
2195
+
2196
+ .kds-secure-loader {
2197
+ display: flex;
2198
+ flex-direction: column;
2199
+ align-items: center;
2200
+ justify-content: center;
2201
+ gap: var(--kds-spacing-4);
2202
+ text-align: center;
2203
+ /* Llena y centra dentro de contenedores flex (pantalla de carga); en flujo
2204
+ normal (contenedor no-flex) se reduce a su contenido. */
2205
+ flex: 1 1 auto;
2206
+ }
2207
+
2208
+ .kds-secure-loader-text {
2209
+ display: flex;
2210
+ flex-direction: column;
2211
+ gap: var(--kds-spacing-0-25);
2212
+ }
2213
+
2214
+ .kds-secure-loader-title {
2215
+ margin: 0;
2216
+ font-family: var(--kds-font-family-primary);
2217
+ font-size: var(--kds-font-size-h6);
2218
+ font-weight: var(--kds-font-weight-semibold);
2219
+ line-height: var(--kds-line-height-snug);
2220
+ color: var(--kds-color-text-primary);
2221
+ }
2222
+
2223
+ .kds-secure-loader-message {
2224
+ margin: 0;
2225
+ /* !important: anula el auto-espaciado de hermanos de BeerCSS (0,5,1);
2226
+ la separación con el título la da el gap del contenedor (spacing-0-25). */
2227
+ margin-top: 0 !important;
2228
+ font-family: var(--kds-font-family-secondary);
2229
+ font-size: var(--kds-font-size-body1);
2230
+ line-height: var(--kds-line-height-normal);
2231
+ color: var(--kds-color-primary-main);
2232
+ }
2233
+
2234
+ /* Caja del spinner con tamaño fijo: la animación no altera el layout.
2235
+ 6.25rem (100px) = tamaño del loader original (CircularProgress size=100). */
2236
+ .kds-secure-loader-spinner {
2237
+ position: relative;
2238
+ display: inline-grid;
2239
+ place-items: center;
2240
+ inline-size: var(--kds-secure-loader-size, 6.25rem);
2241
+ block-size: var(--kds-secure-loader-size, 6.25rem);
2242
+ }
2243
+
2244
+ /* Anillo: SVG nativo con arco vía stroke-dasharray. Replica el CircularProgress
2245
+ original (viewBox 44u, thickness 2, arco ~63%, disableShrink). El giro se anima
2246
+ con stroke-dashoffset (el círculo queda estático y nítido); rotar el SVG con
2247
+ transform rasteriza el anillo y se ve irregular durante el giro. */
2248
+ .kds-secure-loader-ring {
2249
+ inline-size: var(--kds-secure-loader-size, 6.25rem);
2250
+ block-size: var(--kds-secure-loader-size, 6.25rem);
2251
+ }
2252
+
2253
+ .kds-secure-loader-ring circle {
2254
+ fill: none;
2255
+ stroke: var(--kds-color-primary-main);
2256
+ stroke-width: 2;
2257
+ stroke-linecap: round;
2258
+ /* circunferencia = 2π·20.2 ≈ 126.92; arco visible 80 (~63%) + hueco 46.92 */
2259
+ stroke-dasharray: 80 46.92;
2260
+ animation: kds-secure-loader-dash 1.2s linear infinite;
2261
+ }
2262
+
2263
+ @keyframes kds-secure-loader-dash {
2264
+ to {
2265
+ stroke-dashoffset: -126.92;
2266
+ }
2267
+ }
2268
+
2269
+ /* Candado centrado sobre el anillo (~0.3 del diámetro). Centrado explícito
2270
+ (top/left 50% + translate) para que no dependa del grid ni se recorte. */
2271
+ .kds-secure-loader-lock {
2272
+ position: absolute;
2273
+ top: 50%;
2274
+ left: 50%;
2275
+ transform: translate(-50%, -50%);
2276
+ color: var(--kds-color-text-secondary);
2277
+ font-size: calc(var(--kds-secure-loader-size, 6.25rem) * 0.3);
2278
+ line-height: 1;
2279
+ pointer-events: none;
2280
+ }
2281
+
2282
+ /* ========================================
2283
+ KDS COPY BUTTON
2284
+ Chip compacto que muestra un valor + icono copy y lo copia al click.
2285
+ Acción inline (distinto de KdsCopyRow). Look del copy button de khenshin.
2286
+ ======================================== */
2287
+
2288
+ .kds-copy-button {
2289
+ display: inline-flex;
2290
+ align-items: center;
2291
+ gap: var(--kds-spacing-1);
2292
+ padding: var(--kds-spacing-0-25) var(--kds-spacing-1-5);
2293
+ /* No usar el alto de botón táctil de BeerCSS (~44px): es un chip compacto,
2294
+ su alto lo define el contenido + padding. */
2295
+ block-size: auto;
2296
+ min-block-size: 0;
2297
+ border: none;
2298
+ border-radius: var(--kds-radius-button);
2299
+ background: var(--kds-alert-info-bg);
2300
+ color: var(--kds-color-info-dark);
2301
+ font-family: var(--kds-font-family-secondary);
2302
+ font-size: var(--kds-font-size-sm);
2303
+ font-weight: var(--kds-font-weight-medium);
2304
+ line-height: var(--kds-line-height-normal);
2305
+ cursor: pointer;
2306
+ transition: background-color var(--kds-transition-shorter) var(--kds-easing-standard),
2307
+ color var(--kds-transition-shorter) var(--kds-easing-standard);
2308
+ }
2309
+
2310
+ /* active = hover: sin el aro de focus/active (outline morado de BeerCSS). */
2311
+ .kds-copy-button:focus,
2312
+ .kds-copy-button:focus-visible,
2313
+ .kds-copy-button:active {
2314
+ outline: none;
2315
+ }
2316
+
2317
+ /* value y copiedText se apilan en la MISMA celda de grid: la celda toma el
2318
+ ancho del texto más largo, por lo que el botón conserva su ancho al alternar
2319
+ entre "valor" y "copiado" (sin reflow). */
2320
+ .kds-copy-button-label {
2321
+ display: inline-grid;
2322
+ }
2323
+
2324
+ .kds-copy-button-value,
2325
+ .kds-copy-button-copied {
2326
+ grid-area: 1 / 1;
2327
+ white-space: nowrap;
2328
+ }
2329
+
2330
+ /* Estado por defecto: visible el valor, oculto (pero ocupando espacio) el copiado */
2331
+ .kds-copy-button-copied {
2332
+ visibility: hidden;
2333
+ }
2334
+
2335
+ /* Al copiar se invierte la visibilidad; el ancho no cambia */
2336
+ .kds-copy-button.copied .kds-copy-button-value {
2337
+ visibility: hidden;
2338
+ }
2339
+
2340
+ .kds-copy-button.copied .kds-copy-button-copied {
2341
+ visibility: visible;
2342
+ }
2343
+
2344
+ .kds-copy-button .material-symbols-outlined {
2345
+ font-size: 1rem;
2346
+ color: var(--kds-color-info-main);
2347
+ flex-shrink: 0;
2348
+ }
2349
+
2350
+ .kds-copy-button.copied {
2351
+ background: var(--kds-alert-success-bg);
2352
+ color: var(--kds-alert-success-text);
2353
+ animation: kds-copy-button-pulse var(--kds-transition-short) var(--kds-easing-standard);
2354
+ }
2355
+
2356
+ .kds-copy-button.copied .material-symbols-outlined {
2357
+ color: var(--kds-color-success-main);
2358
+ /* el check entra con un pop al copiar */
2359
+ animation: kds-copy-button-pop var(--kds-transition-short) var(--kds-easing-standard);
2360
+ }
2361
+
2362
+ @keyframes kds-copy-button-pulse {
2363
+ 0% {
2364
+ transform: scale(1);
2365
+ }
2366
+ 50% {
2367
+ transform: scale(1.04);
2368
+ }
2369
+ 100% {
2370
+ transform: scale(1);
2371
+ }
2372
+ }
2373
+
2374
+ @keyframes kds-copy-button-pop {
2375
+ 0% {
2376
+ transform: scale(0.3);
2377
+ opacity: 0;
2378
+ }
2379
+ 60% {
2380
+ transform: scale(1.25);
2381
+ opacity: 1;
2382
+ }
2383
+ 100% {
2384
+ transform: scale(1);
2385
+ }
2386
+ }
2387
+
2032
2388
  /* ========================================
2033
2389
  Link Styles
2034
2390
  ======================================== */
@@ -2130,6 +2486,16 @@ footer.primary a:hover {
2130
2486
  margin-right: var(--kds-spacing-2);
2131
2487
  }
2132
2488
 
2489
+ /* Ícono(s) en color primary. Para íconos MUI/SVG dentro del scope que, por el reset
2490
+ `.kds-theme-root svg { fill: currentColor }`, terminan heredando el color de texto
2491
+ (#333) en vez de su color propio — el `color="primary"` de MUI no le gana al contexto.
2492
+ Aplica al contenedor y a sus i/svg hijos. */
2493
+ .kds-icon-primary,
2494
+ .kds-icon-primary i,
2495
+ .kds-icon-primary svg {
2496
+ color: var(--kds-color-primary-main);
2497
+ }
2498
+
2133
2499
  /* Section title icon */
2134
2500
  .kds-stage-section-title i {
2135
2501
  vertical-align: middle;
@@ -2161,6 +2527,25 @@ body.dark {
2161
2527
  transition: border-color 0.2s, box-shadow 0.2s, outline-color 0.2s;
2162
2528
  }
2163
2529
 
2530
+ /* === TEXTAREA FIX === */
2531
+ /* BeerCSS base sets minimal block padding; add breathing room for textarea */
2532
+ .field > textarea {
2533
+ padding-block: 0.75rem;
2534
+ resize: vertical;
2535
+ }
2536
+
2537
+ .field.label > textarea {
2538
+ padding-block-start: 1.5rem;
2539
+ }
2540
+
2541
+ /* Label en reposo (estado "abajo", como placeholder): font-size menor al 1rem de BeerCSS
2542
+ para que un label largo no estorbe con un ícono (prefix/suffix) del input. Token sm
2543
+ (13–14px, siempre < 1rem del input incluso en desktop). Al flotar, BeerCSS lo reduce a
2544
+ .75rem con mayor especificidad, así que esto solo afecta el reposo. */
2545
+ .field.label > label {
2546
+ font-size: var(--kds-font-size-sm);
2547
+ }
2548
+
2164
2549
  /* ==========================================
2165
2550
  NOTCH VISIBILITY (opacity)
2166
2551
  ========================================== */
@@ -2282,6 +2667,23 @@ body.dark {
2282
2667
  color: var(--error); /* Rojo error */
2283
2668
  }
2284
2669
 
2670
+ /* ==========================================
2671
+ PASSWORD REVEAL TOGGLE (KdsTextField `revealable`)
2672
+ El <a role="button"> reusa el posicionamiento de icono de BeerCSS
2673
+ (.field > a, pointer-events: all). Aquí solo: color del icono
2674
+ (on-surface-variant) y un focus ring accesible para el toggle
2675
+ navegable por teclado (BeerCSS hace `outline: inherit` en <a>).
2676
+ ========================================== */
2677
+ .field > a.kds-field-reveal {
2678
+ color: var(--on-surface-variant);
2679
+ }
2680
+
2681
+ .field > a.kds-field-reveal:focus-visible {
2682
+ outline: 2px solid var(--primary);
2683
+ outline-offset: 2px;
2684
+ border-radius: 50%;
2685
+ }
2686
+
2285
2687
  /* ==========================================
2286
2688
  LABEL COLOR
2287
2689
  Mantener sincronizado con border
@@ -2390,25 +2792,90 @@ body.dark {
2390
2792
  }
2391
2793
 
2392
2794
  /* ========================================
2393
- Material Symbols Icon Sizing
2795
+ Radix Tooltip (.kds-tooltip)
2796
+ Espejo de `.tooltip` pero para popovers de Radix:
2797
+ bg oscuro, texto blanco, sombra + animación fade/slide direccional.
2394
2798
  ======================================== */
2395
2799
 
2396
- .material-symbols-outlined {
2397
- font-variation-settings:
2398
- 'FILL' 0,
2399
- 'wght' 400,
2400
- 'GRAD' 0,
2401
- 'opsz' 24;
2402
- min-width: 30px;
2403
- min-height: 30px;
2404
- display: inline-flex;
2405
- align-items: center;
2406
- justify-content: center;
2800
+ .kds-tooltip {
2801
+ background-color: var(--kds-color-text-primary);
2802
+ color: var(--kds-color-background-paper);
2803
+ font-family: var(--kds-font-family-primary);
2804
+ font-size: var(--kds-font-size-xs);
2805
+ font-weight: var(--kds-font-weight-medium);
2806
+ line-height: var(--kds-line-height-normal);
2807
+ border-radius: var(--kds-radius-sm);
2808
+ padding: var(--kds-spacing-0-75) var(--kds-spacing-1-5);
2809
+ box-shadow: var(--kds-shadow-4);
2810
+ max-width: 280px;
2811
+ z-index: var(--kds-z-index-tooltip, 1500);
2812
+ user-select: none;
2813
+ /* Animación direccional según Radix data-side — coordinada con copy-row
2814
+ (cubic-bezier 0.2, 0.8, 0.2, 1) para un feel consistente del DS. */
2815
+ animation-duration: 240ms;
2816
+ animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
2817
+ will-change: transform, opacity;
2407
2818
  }
2408
2819
 
2409
- /* Filled icons for specific contexts */
2410
- .icon-filled {
2411
- font-variation-settings:
2820
+ .kds-tooltip[data-state='closed'] {
2821
+ animation-duration: 140ms;
2822
+ animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
2823
+ }
2824
+
2825
+ /* Direccional según data-side (Radix añade el attr en runtime).
2826
+ Cada lado entra desde su dirección con ~8px de offset (más visible que 4px). */
2827
+ .kds-tooltip[data-side='top'][data-state='delayed-open'],
2828
+ .kds-tooltip[data-side='top'][data-state='instant-open'] { animation-name: kds-tooltip-in-top; }
2829
+ .kds-tooltip[data-side='bottom'][data-state='delayed-open'],
2830
+ .kds-tooltip[data-side='bottom'][data-state='instant-open'] { animation-name: kds-tooltip-in-bottom; }
2831
+ .kds-tooltip[data-side='left'][data-state='delayed-open'],
2832
+ .kds-tooltip[data-side='left'][data-state='instant-open'] { animation-name: kds-tooltip-in-left; }
2833
+ .kds-tooltip[data-side='right'][data-state='delayed-open'],
2834
+ .kds-tooltip[data-side='right'][data-state='instant-open'] { animation-name: kds-tooltip-in-right; }
2835
+
2836
+ /* Fallback cuando no hay data-side resuelto aún */
2837
+ .kds-tooltip[data-state='delayed-open']:not([data-side]),
2838
+ .kds-tooltip[data-state='instant-open']:not([data-side]) {
2839
+ animation-name: kds-tooltip-in-top;
2840
+ }
2841
+
2842
+ .kds-tooltip[data-state='closed'] { animation-name: kds-tooltip-out; }
2843
+
2844
+ @keyframes kds-tooltip-in-top { from { opacity: 0; transform: translateY(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2845
+ @keyframes kds-tooltip-in-bottom { from { opacity: 0; transform: translateY(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2846
+ @keyframes kds-tooltip-in-left { from { opacity: 0; transform: translateX(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2847
+ @keyframes kds-tooltip-in-right { from { opacity: 0; transform: translateX(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2848
+
2849
+ @keyframes kds-tooltip-out {
2850
+ from { opacity: 1; transform: none; }
2851
+ to { opacity: 0; transform: scale(0.96); }
2852
+ }
2853
+
2854
+ /* Arrow (SVG path generado por Radix) */
2855
+ .kds-tooltip-arrow {
2856
+ fill: var(--kds-color-text-primary);
2857
+ }
2858
+
2859
+ /* ========================================
2860
+ Material Symbols Icon Sizing
2861
+ ======================================== */
2862
+
2863
+ .material-symbols-outlined {
2864
+ font-variation-settings:
2865
+ 'FILL' 0,
2866
+ 'wght' 400,
2867
+ 'GRAD' 0,
2868
+ 'opsz' 24;
2869
+ min-width: 30px;
2870
+ min-height: 30px;
2871
+ display: inline-flex;
2872
+ align-items: center;
2873
+ justify-content: center;
2874
+ }
2875
+
2876
+ /* Filled icons for specific contexts */
2877
+ .icon-filled {
2878
+ font-variation-settings:
2412
2879
  'FILL' 1,
2413
2880
  'wght' 400,
2414
2881
  'GRAD' 0,
@@ -2423,6 +2890,16 @@ body.dark {
2423
2890
  width: 100%;
2424
2891
  }
2425
2892
 
2893
+ /* Truncado en una línea con ellipsis. Incluye min-width:0 para que funcione
2894
+ dentro de contenedores flex/grid (el ítem puede encogerse por debajo de su
2895
+ contenido). Útil para nombres/asuntos largos en headers y filas. */
2896
+ .kds-truncate {
2897
+ min-width: 0;
2898
+ overflow: hidden;
2899
+ text-overflow: ellipsis;
2900
+ white-space: nowrap;
2901
+ }
2902
+
2426
2903
  .kds-max-w-sm {
2427
2904
  max-width: 400px;
2428
2905
  }
@@ -2466,6 +2943,11 @@ body.dark {
2466
2943
  display: flex;
2467
2944
  flex-direction: column;
2468
2945
  gap: var(--kds-spacing-3);
2946
+ /* Reset del fieldset nativo: sin borde/padding/margin por defecto del navegador. */
2947
+ margin: 0;
2948
+ padding: 0;
2949
+ border: 0;
2950
+ min-inline-size: 0;
2469
2951
  }
2470
2952
 
2471
2953
  /* Checkbox Label - BeerCSS override */
@@ -2477,7 +2959,7 @@ label.radio {
2477
2959
  border-radius: 8px;
2478
2960
  cursor: pointer;
2479
2961
  transition: background-color 0.2s;
2480
- font-size: 16px;
2962
+ font-size: var(--kds-font-size-sm);
2481
2963
  line-height: 1.5;
2482
2964
  color: var(--kds-color-text-primary);
2483
2965
  }
@@ -2515,6 +2997,42 @@ label.radio:has(input:disabled) {
2515
2997
  opacity: 0.6;
2516
2998
  }
2517
2999
 
3000
+ /* ========================================
3001
+ RADIO GROUP — variante card (.kds-radio-group--card)
3002
+ Cada opción como fila con borde (estilo selección de banco/cuenta),
3003
+ manteniendo el control radio. Hover + opción seleccionada resaltada.
3004
+ ======================================== */
3005
+ .kds-radio-group--card {
3006
+ gap: var(--kds-spacing-2);
3007
+ }
3008
+
3009
+ .kds-radio-group--card label.radio {
3010
+ gap: var(--kds-spacing-1-5);
3011
+ /* Vertical con un poco más de aire; horizontal reducido para pegar el radio a la izquierda. */
3012
+ padding: var(--kds-spacing-2) var(--kds-spacing-1-5);
3013
+ /* Bordes con los valores del bank selector. */
3014
+ border: 1px solid var(--kds-color-border-subtle);
3015
+ border-radius: var(--kds-radius-card);
3016
+ background: var(--kds-color-surface);
3017
+ transition: border-color 0.2s, background 0.2s;
3018
+ }
3019
+
3020
+ /* Leve separación extra entre el radio y el texto de la opción. */
3021
+ .kds-radio-group--card label.radio span {
3022
+ margin-left: var(--kds-spacing-0-5);
3023
+ }
3024
+
3025
+ .kds-radio-group--card label.radio:hover {
3026
+ border-color: var(--kds-color-border-default);
3027
+ }
3028
+
3029
+ /* Seleccionada: poco color primario — solo un fondo faint sutil + borde gris
3030
+ (el punto del radio ya comunica la selección). */
3031
+ .kds-radio-group--card label.radio:has(input:checked) {
3032
+ border-color: var(--kds-color-border-default);
3033
+ background: var(--kds-color-primary-faint);
3034
+ }
3035
+
2518
3036
  /* ========================================
2519
3037
  ONBOARDING COMPONENTS
2520
3038
  Multi-stage onboarding flow with form validation
@@ -3012,19 +3530,17 @@ footer > .kds-container-center {
3012
3530
  display: flex;
3013
3531
  align-items: center;
3014
3532
  gap: var(--kds-spacing-1);
3015
- padding: var(--kds-spacing-2);
3533
+ /* Padding compacto: vertical spacing-1 (8px), horizontal spacing-2 (16px). */
3534
+ padding: var(--kds-spacing-1) var(--kds-spacing-2);
3016
3535
  border-radius: var(--kds-radius-md);
3017
3536
  border: 1px solid;
3018
3537
  font-family: var(--kds-font-family-primary);
3019
3538
  min-width: 0;
3020
- flex: 1 1 100%;
3021
- }
3022
-
3023
- @media (min-width: 768px) {
3024
- .kds-alert {
3025
- padding: var(--kds-spacing-2);
3026
- flex: 1 1 auto;
3027
- }
3539
+ /* Banner: ocupa siempre el ancho del contenedor. width explícito porque como
3540
+ flex item de una columna con align-items:center el cross-axis no se estira.
3541
+ Sin flex-grow para no estirarse verticalmente en contenedores flex-column. */
3542
+ width: 100%;
3543
+ flex: 0 1 auto;
3028
3544
  }
3029
3545
 
3030
3546
  .kds-alert:last-child {
@@ -3050,7 +3566,9 @@ footer > .kds-container-center {
3050
3566
  font-size: var(--kds-font-size-sm);
3051
3567
  font-weight: var(--kds-font-weight-semibold);
3052
3568
  line-height: var(--kds-line-height-normal);
3053
- margin-bottom: var(--kds-spacing-0-5);
3569
+ /* Solo margin-bottom: el padding del alert da el espaciado. Reset del resto para
3570
+ evitar el margin-block que BeerCSS aplica a <p> dentro del scope. */
3571
+ margin: 0 0 var(--kds-spacing-0-5);
3054
3572
  word-break: normal;
3055
3573
  overflow-wrap: break-word;
3056
3574
  }
@@ -3060,6 +3578,9 @@ footer > .kds-container-center {
3060
3578
  font-size: var(--kds-font-size-sm);
3061
3579
  font-weight: var(--kds-font-weight-regular);
3062
3580
  line-height: var(--kds-line-height-relaxed);
3581
+ /* Sin margen propio: el padding del alert es el único espaciado (evita el
3582
+ margin-block de <p> de BeerCSS dentro del scope). */
3583
+ margin: 0;
3063
3584
  word-break: normal;
3064
3585
  overflow-wrap: break-word;
3065
3586
  }
@@ -3105,6 +3626,32 @@ footer > .kds-container-center {
3105
3626
  color: var(--kds-color-error-dark);
3106
3627
  }
3107
3628
 
3629
+ /* Close button — icon-only, discreto, no usa kds-btn para no romper el flex layout del alert */
3630
+ .kds-alert-close {
3631
+ flex-shrink: 0;
3632
+ display: inline-flex;
3633
+ align-items: center;
3634
+ justify-content: center;
3635
+ width: 28px;
3636
+ height: 28px;
3637
+ padding: 0;
3638
+ background: transparent;
3639
+ border: 0;
3640
+ border-radius: 50%;
3641
+ color: inherit;
3642
+ cursor: pointer;
3643
+ transition: background-color 0.15s ease;
3644
+ }
3645
+
3646
+ .kds-alert-close:hover {
3647
+ background: rgba(0, 0, 0, 0.06);
3648
+ }
3649
+
3650
+ .kds-alert-close i {
3651
+ font-size: 18px;
3652
+ line-height: 1;
3653
+ }
3654
+
3108
3655
  /* Lists inside alerts */
3109
3656
  .kds-alert ul {
3110
3657
  padding-left: var(--kds-spacing-2);
@@ -4101,6 +4648,14 @@ dialog#surveyModal button.circle {
4101
4648
  text-align: center;
4102
4649
  }
4103
4650
 
4651
+ .kds-text-left {
4652
+ text-align: left;
4653
+ }
4654
+
4655
+ .kds-text-right {
4656
+ text-align: right;
4657
+ }
4658
+
4104
4659
  .kds-text-underline {
4105
4660
  text-decoration: underline;
4106
4661
  }
@@ -4113,10 +4668,62 @@ dialog#surveyModal button.circle {
4113
4668
  color: var(--on-surface-variant);
4114
4669
  }
4115
4670
 
4671
+ .kds-text-primary {
4672
+ color: var(--kds-color-primary-main);
4673
+ }
4674
+
4116
4675
  .kds-text-sm {
4117
4676
  font-size: var(--kds-font-size-sm);
4118
4677
  }
4119
4678
 
4679
+ /* ── Font-size scale utilities (additive — opt-in companions to .kds-text-sm) ── */
4680
+ .kds-text-base {
4681
+ font-size: var(--kds-font-size-base);
4682
+ }
4683
+
4684
+ .kds-text-lg {
4685
+ font-size: var(--kds-font-size-lg);
4686
+ }
4687
+
4688
+ .kds-text-xl {
4689
+ font-size: var(--kds-font-size-xl);
4690
+ }
4691
+
4692
+ .kds-text-2xl {
4693
+ font-size: var(--kds-font-size-2xl);
4694
+ }
4695
+
4696
+ /* ── Font-weight utilities ── */
4697
+ .kds-fw-regular {
4698
+ font-weight: var(--kds-font-weight-regular);
4699
+ }
4700
+
4701
+ .kds-fw-medium {
4702
+ font-weight: var(--kds-font-weight-medium);
4703
+ }
4704
+
4705
+ .kds-fw-semibold {
4706
+ font-weight: var(--kds-font-weight-semibold);
4707
+ }
4708
+
4709
+ .kds-fw-bold {
4710
+ font-weight: var(--kds-font-weight-bold);
4711
+ }
4712
+
4713
+ /* ── Text-transform utilities ── */
4714
+ .kds-text-transform-none {
4715
+ text-transform: none;
4716
+ }
4717
+
4718
+ /* ── Soft background utilities (semantic muted backgrounds for callouts) ── */
4719
+ .kds-bg-warning-soft {
4720
+ background-color: var(--kds-color-warning-soft);
4721
+ }
4722
+
4723
+ .kds-bg-info-soft {
4724
+ background-color: var(--kds-color-info-soft);
4725
+ }
4726
+
4120
4727
  /* ── Typography variants ── */
4121
4728
  .kds-text-display1 {
4122
4729
  font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
@@ -4194,6 +4801,48 @@ dialog#surveyModal button.circle {
4194
4801
  text-transform: uppercase;
4195
4802
  }
4196
4803
 
4804
+ /* KV label — label del par clave↔valor (letra del dt de .kds-kv: "PAGO A" / "ASUNTO").
4805
+ line-height tight: en pares apilados el relaxed infla la separación de tinta. */
4806
+ .kds-text-kv-label {
4807
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4808
+ font-size: var(--kds-font-size-xs);
4809
+ font-weight: var(--kds-font-weight-regular);
4810
+ line-height: var(--kds-line-height-tight);
4811
+ letter-spacing: normal;
4812
+ text-transform: uppercase;
4813
+ color: var(--kds-color-text-secondary);
4814
+ }
4815
+
4816
+ /* Value — dato/valor destacado (ej. nombre del comercio en el header del cobro).
4817
+ line-height tight: se usa en pares apilados y el relaxed infla la separación. */
4818
+ .kds-text-value {
4819
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4820
+ font-size: var(--kds-font-size-sm);
4821
+ font-weight: var(--kds-font-weight-semibold);
4822
+ line-height: var(--kds-line-height-tight);
4823
+ color: var(--kds-color-gray-800);
4824
+ }
4825
+
4826
+ /* Code — texto tipo código/referencia (mono, uppercase, gris), como el "CÓDIGO" del header. */
4827
+ .kds-text-code {
4828
+ font-family: var(--kds-font-family-mono);
4829
+ font-size: var(--kds-font-size-xs);
4830
+ font-weight: var(--kds-font-weight-regular);
4831
+ letter-spacing: var(--kds-letter-spacing-wider);
4832
+ font-variant-numeric: tabular-nums;
4833
+ color: var(--kds-color-gray-400);
4834
+ text-transform: uppercase;
4835
+ }
4836
+
4837
+ /* Caption — texto muy chico y liviano para pie de página (ej. número de versión). */
4838
+ .kds-text-caption {
4839
+ font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4840
+ font-size: var(--kds-font-size-2xs);
4841
+ font-weight: var(--kds-font-weight-regular);
4842
+ line-height: var(--kds-line-height-normal);
4843
+ color: var(--kds-color-gray-400);
4844
+ }
4845
+
4197
4846
  .kds-text-link {
4198
4847
  font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
4199
4848
  font-size: inherit;
@@ -4207,6 +4856,12 @@ dialog#surveyModal button.circle {
4207
4856
  color: var(--kds-color-primary-dark, #5B3179);
4208
4857
  }
4209
4858
 
4859
+ /* Inline emphasis: bold weight only, inherits size/color/family from context so it
4860
+ works as a highlighted fragment inside any other variant (body, heading, etc.). */
4861
+ .kds-text-strong {
4862
+ font-weight: var(--kds-font-weight-bold, 700);
4863
+ }
4864
+
4210
4865
  /* Display utilities */
4211
4866
  .kds-hidden {
4212
4867
  display: none;
@@ -4296,7 +4951,25 @@ dialog#surveyModal button.circle {
4296
4951
  flex-shrink: 0;
4297
4952
  }
4298
4953
 
4954
+ /* Versión de la app anclada al fondo del card body (flex column): margin-top
4955
+ auto absorbe el espacio libre; el padding garantiza respiro mínimo cuando el
4956
+ contenido llena la card. */
4957
+ .kds-card-version {
4958
+ margin-top: auto;
4959
+ padding-top: var(--kds-spacing-2);
4960
+ text-align: center;
4961
+ }
4962
+
4963
+ /* Separador vertical (entre chips/logos hermanos en una fila). */
4964
+ .kds-vr {
4965
+ width: 1px;
4966
+ height: var(--kds-spacing-3);
4967
+ background: var(--kds-color-divider);
4968
+ flex: 0 0 auto;
4969
+ }
4970
+
4299
4971
  /* Gap utilities */
4972
+ .kds-gap-0-25 { gap: var(--kds-spacing-0-25); }
4300
4973
  .kds-gap-1 { gap: var(--kds-spacing-1); }
4301
4974
  .kds-gap-2 { gap: var(--kds-spacing-2); }
4302
4975
  .kds-gap-3 { gap: var(--kds-spacing-3); }
@@ -4327,7 +5000,9 @@ dialog#surveyModal button.circle {
4327
5000
  ======================================== */
4328
5001
 
4329
5002
  .kds-badge {
4330
- display: inline-block;
5003
+ display: inline-flex;
5004
+ align-items: center;
5005
+ gap: 4px;
4331
5006
  padding: 2px 8px;
4332
5007
  border-radius: var(--kds-radius-sm);
4333
5008
  font-size: var(--kds-font-size-xs);
@@ -4335,6 +5010,40 @@ dialog#surveyModal button.circle {
4335
5010
  line-height: 1.5;
4336
5011
  }
4337
5012
 
5013
+ /* Icon prefix inside chip — small inline icon */
5014
+ .kds-badge > i.material-symbols-outlined {
5015
+ font-size: 14px;
5016
+ line-height: 1;
5017
+ }
5018
+
5019
+ /* Deletable chip close button — discreto, sin kds-btn (eso lo agrandaba ridículo) */
5020
+ .kds-badge-close {
5021
+ display: inline-flex;
5022
+ align-items: center;
5023
+ justify-content: center;
5024
+ width: 16px;
5025
+ height: 16px;
5026
+ margin-right: -2px;
5027
+ padding: 0;
5028
+ background: transparent;
5029
+ border: 0;
5030
+ border-radius: 50%;
5031
+ color: inherit;
5032
+ cursor: pointer;
5033
+ opacity: 0.7;
5034
+ transition: opacity 0.15s, background-color 0.15s;
5035
+ }
5036
+
5037
+ .kds-badge-close:hover {
5038
+ opacity: 1;
5039
+ background: rgba(0, 0, 0, 0.1);
5040
+ }
5041
+
5042
+ .kds-badge-close i {
5043
+ font-size: 14px;
5044
+ line-height: 1;
5045
+ }
5046
+
4338
5047
  .kds-badge.success {
4339
5048
  background-color: var(--kds-color-success-container);
4340
5049
  color: var(--kds-color-success-dark);
@@ -4546,21 +5255,46 @@ dialog#surveyModal button.circle {
4546
5255
  flex-shrink: 0;
4547
5256
  }
4548
5257
 
4549
- /* Merchant tile with logo variant */
5258
+ /* Merchant tile with logo variant — el logo (avatar del comercio) llena TODO el tile.
5259
+ `display: block` evita el desborde del auto-grid; `overflow: hidden` recorta la imagen
5260
+ a las esquinas redondeadas del tile. La imagen va CUADRADA (sin border-radius propio):
5261
+ solo el contenedor recorta, evitando el hairline sub-pixel del doble redondeo. El fondo
5262
+ se deja transparente bajo el logo como respaldo (no debe verse púrpura en los bordes). */
4550
5263
  .kds-merchant-tile.logo {
4551
- padding: var(--kds-spacing-0-5);
5264
+ padding: 0;
5265
+ display: block;
5266
+ overflow: hidden;
5267
+ background: transparent;
4552
5268
  }
4553
5269
 
4554
5270
  .kds-merchant-tile.logo img {
4555
5271
  width: 100%;
4556
5272
  height: 100%;
4557
5273
  object-fit: cover;
4558
- border-radius: var(--kds-radius-md);
5274
+ border-radius: 0;
5275
+ display: block;
5276
+ }
5277
+
5278
+ /* Variante para logos que traen su propio marco/forma (logos de comercio/servicio,
5279
+ no fotos): `contain` + padding para que el logo entre completo sin recortar sus
5280
+ esquinas. Opt-in: pasar className="kds-merchant-tile--contain". */
5281
+ .kds-merchant-tile.logo.kds-merchant-tile--contain {
5282
+ padding: var(--kds-spacing-1);
5283
+ }
5284
+ .kds-merchant-tile.logo.kds-merchant-tile--contain img {
5285
+ object-fit: contain;
4559
5286
  }
4560
5287
 
4561
5288
  .kds-merchant-meta {
4562
5289
  display: flex;
4563
5290
  flex-direction: column;
5291
+ gap: var(--kds-spacing-0-5);
5292
+ }
5293
+
5294
+ /* El meta controla su propio espaciado: anula el margin sibling de BeerCSS
5295
+ (`… + :is(p,h*,…) { margin-block-start: 1rem }`) que separaba de más las líneas. */
5296
+ .kds-merchant-meta > * {
5297
+ margin-block: 0 !important;
4564
5298
  }
4565
5299
 
4566
5300
  .kds-merchant-label {
@@ -4613,6 +5347,11 @@ dialog#surveyModal button.circle {
4613
5347
  color: var(--kds-color-text-primary);
4614
5348
  }
4615
5349
 
5350
+ /* Opt-in color modifier — switches the value to the LigoPay/khipu-blue tone */
5351
+ .kds-amount-value--info {
5352
+ color: var(--kds-color-info-blue); /* #5A5FE0 */
5353
+ }
5354
+
4616
5355
  .kds-amount-value small {
4617
5356
  font-size: 18px;
4618
5357
  font-weight: 500;
@@ -4899,44 +5638,182 @@ dialog#surveyModal button.circle {
4899
5638
  }
4900
5639
 
4901
5640
  /* ========================================
4902
- 09 - SUCCESS MARK (.kds-success-mark)
4903
- Large success icon for completion screens
5641
+ 08b - FAB (.kds-fab)
5642
+ Circular, icon-only floating action button with an animated hide state.
5643
+ Presentational: drive `.kds-fab--hidden` from useHideOnScroll for scroll-away.
4904
5644
  ======================================== */
4905
5645
 
4906
- .kds-success-mark {
4907
- width: 64px;
4908
- height: 64px;
5646
+ .kds-fab {
5647
+ display: inline-flex;
5648
+ align-items: center;
5649
+ justify-content: center;
5650
+ width: var(--kds-spacing-5);
5651
+ height: var(--kds-spacing-5);
5652
+ padding: 0;
5653
+ border: none;
4909
5654
  border-radius: var(--kds-radius-full);
4910
- background: var(--kds-color-success-soft);
4911
- border: 2px solid var(--kds-color-success-main);
4912
- display: grid;
4913
- place-items: center;
4914
- color: var(--kds-color-success-main);
4915
- animation: kds-pop 0.45s ease-out;
4916
- margin: 0 auto;
5655
+ background: var(--kds-color-background-paper);
5656
+ color: var(--kds-color-text-primary);
5657
+ box-shadow: var(--kds-shadow-elevated);
5658
+ cursor: pointer;
5659
+ z-index: 100;
5660
+ /* Neutralize native button rendering so the pressed state doesn't flash a square. */
5661
+ -webkit-appearance: none;
5662
+ appearance: none;
5663
+ -webkit-tap-highlight-color: transparent;
5664
+ transition: opacity var(--kds-transition-short) ease, transform var(--kds-transition-short) ease,
5665
+ background-color var(--kds-transition-shorter) ease;
5666
+ }
5667
+
5668
+ /* Keep the circle in EVERY interaction state. Uses `button.kds-fab` (element + class) to
5669
+ out-specify BeerCSS's base `button`/`button:active` rules — same trick as `.kds-btn`. */
5670
+ button.kds-fab,
5671
+ button.kds-fab:hover,
5672
+ button.kds-fab:active,
5673
+ button.kds-fab:focus,
5674
+ button.kds-fab:focus-visible {
5675
+ border-radius: var(--kds-radius-full);
5676
+ background: var(--kds-color-background-paper);
4917
5677
  }
4918
5678
 
4919
- .kds-success-mark i {
4920
- font-size: 32px;
4921
- font-weight: 700;
5679
+ button.kds-fab:hover:not(:disabled) {
5680
+ background: var(--kds-color-background-muted);
4922
5681
  }
4923
5682
 
4924
- /* Error variant */
4925
- .kds-success-mark.error {
4926
- background: rgba(211, 47, 47, 0.08);
4927
- border-color: var(--kds-color-error-main);
4928
- color: var(--kds-color-error-main);
5683
+ /* Subtle press feedback that preserves the round shape. */
5684
+ button.kds-fab:active:not(:disabled) {
5685
+ transform: translateY(var(--kds-spacing-0-25));
4929
5686
  }
4930
5687
 
4931
- /* Warning variant */
4932
- .kds-success-mark.warning {
4933
- background: rgba(237, 108, 2, 0.08);
4934
- border-color: var(--kds-color-warning-main);
4935
- color: var(--kds-color-warning-main);
5688
+ button.kds-fab:focus-visible {
5689
+ outline: var(--kds-spacing-0-25) solid var(--kds-color-primary-main);
5690
+ outline-offset: var(--kds-spacing-0-25);
4936
5691
  }
4937
5692
 
4938
- @keyframes kds-pop {
4939
- 0% {
5693
+ .kds-fab > i.material-symbols-outlined {
5694
+ font-size: var(--kds-spacing-button-icon-size);
5695
+ line-height: 1;
5696
+ }
5697
+
5698
+ /* Pinned corners — fixed to the viewport (stays visible on scroll-up, iframe-friendly).
5699
+ Horizontally the top-right FAB hugs the right edge of the centered content column set via
5700
+ `--kds-fab-column-width` (default 100% → viewport edge). The consumer sets that var to its
5701
+ widget width so on desktop the FAB overlaps the header's top-right corner instead of drifting
5702
+ to the far viewport edge. `max(...)` keeps at least a token inset on narrow (mobile) viewports. */
5703
+ .kds-fab--top-right,
5704
+ .kds-fab--top-left,
5705
+ .kds-fab--bottom-right,
5706
+ .kds-fab--bottom-left {
5707
+ position: fixed;
5708
+ }
5709
+
5710
+ .kds-fab--top-right {
5711
+ top: var(--kds-spacing-2);
5712
+ right: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5713
+ }
5714
+
5715
+ .kds-fab--top-left {
5716
+ top: var(--kds-spacing-2);
5717
+ left: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5718
+ }
5719
+
5720
+ .kds-fab--bottom-right {
5721
+ bottom: var(--kds-spacing-2);
5722
+ right: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5723
+ }
5724
+
5725
+ .kds-fab--bottom-left {
5726
+ bottom: var(--kds-spacing-2);
5727
+ left: max(var(--kds-spacing-2), calc((100% - var(--kds-fab-column-width, 100%)) / 2 + var(--kds-spacing-2)));
5728
+ }
5729
+
5730
+ /* Desktop: nudge the top-right FAB up so it sits partially over the header's top edge. */
5731
+ @media (min-width: 768px) {
5732
+ .kds-fab--top-right {
5733
+ top: var(--kds-spacing-1);
5734
+ }
5735
+ }
5736
+
5737
+ /* Corner-overlap: mount the FAB centered OVER the top-right corner of the content column
5738
+ (`--kds-fab-column-width`), overlapping outward — vs `--top-right` which insets inside the
5739
+ column. Mobile keeps a small inset from the viewport via the `--kds-fab-inset` token. */
5740
+ .kds-fab--corner {
5741
+ --kds-fab-inset: 5px;
5742
+ position: fixed;
5743
+ top: var(--kds-fab-inset);
5744
+ right: var(--kds-fab-inset);
5745
+ }
5746
+
5747
+ @media (min-width: 768px) {
5748
+ .kds-fab--corner {
5749
+ right: max(
5750
+ var(--kds-fab-inset),
5751
+ calc((100% - var(--kds-fab-column-width, 100%)) / 2 - var(--kds-spacing-5) / 2)
5752
+ );
5753
+ }
5754
+ }
5755
+
5756
+ /* Hidden (scroll-away) state — fade + slide toward the nearest edge */
5757
+ .kds-fab--hidden {
5758
+ opacity: 0;
5759
+ transform: translateY(calc(-1 * var(--kds-spacing-1))) scale(0.9);
5760
+ pointer-events: none;
5761
+ }
5762
+
5763
+ .kds-fab--bottom-right.kds-fab--hidden,
5764
+ .kds-fab--bottom-left.kds-fab--hidden {
5765
+ transform: translateY(var(--kds-spacing-1)) scale(0.9);
5766
+ }
5767
+
5768
+ @media (prefers-reduced-motion: reduce) {
5769
+ .kds-fab {
5770
+ transition: opacity var(--kds-transition-short) ease;
5771
+ }
5772
+
5773
+ .kds-fab--hidden {
5774
+ transform: none;
5775
+ }
5776
+ }
5777
+
5778
+ /* ========================================
5779
+ 09 - SUCCESS MARK (.kds-success-mark)
5780
+ Large success icon for completion screens
5781
+ ======================================== */
5782
+
5783
+ .kds-success-mark {
5784
+ width: 64px;
5785
+ height: 64px;
5786
+ border-radius: var(--kds-radius-full);
5787
+ background: var(--kds-color-success-soft);
5788
+ border: 2px solid var(--kds-color-success-main);
5789
+ display: grid;
5790
+ place-items: center;
5791
+ color: var(--kds-color-success-main);
5792
+ animation: kds-pop 0.45s ease-out;
5793
+ margin: 0 auto;
5794
+ }
5795
+
5796
+ .kds-success-mark i {
5797
+ font-size: 32px;
5798
+ font-weight: 700;
5799
+ }
5800
+
5801
+ /* Error variant */
5802
+ .kds-success-mark.error {
5803
+ background: rgba(211, 47, 47, 0.08);
5804
+ border-color: var(--kds-color-error-main);
5805
+ color: var(--kds-color-error-main);
5806
+ }
5807
+
5808
+ /* Warning variant */
5809
+ .kds-success-mark.warning {
5810
+ background: rgba(237, 108, 2, 0.08);
5811
+ border-color: var(--kds-color-warning-main);
5812
+ color: var(--kds-color-warning-main);
5813
+ }
5814
+
5815
+ @keyframes kds-pop {
5816
+ 0% {
4940
5817
  transform: scale(0.6);
4941
5818
  opacity: 0;
4942
5819
  }
@@ -4977,22 +5854,22 @@ dialog#surveyModal button.circle {
4977
5854
  padding: var(--kds-spacing-1) 0;
4978
5855
  }
4979
5856
 
4980
- /* Desktop: footer inside card hidden; Mobile: footer outside card hidden */
5857
+ /* Footer SIEMPRE fuera del card body (desktop y mobile): el footer interno
5858
+ (variant="inside") queda oculto en todos los breakpoints; se muestra el
5859
+ externo, hermano directo del card bajo `.kds-screen`. */
4981
5860
  .kds-card-elevated > .kds-secure-footer {
4982
5861
  display: none;
4983
5862
  }
4984
5863
 
4985
- @media (max-width: 767px) {
4986
- .kds-card-elevated > .kds-secure-footer {
4987
- display: flex;
4988
- }
4989
- .kds-screen > .kds-secure-footer {
4990
- display: none;
4991
- }
5864
+ .kds-screen > form {
5865
+ margin-block-start: 0 !important;
5866
+ }
4992
5867
 
4993
- .kds-screen > form {
4994
- margin-block-start: 0 !important;
4995
- }
5868
+ /* Footer externo adyacente a la card: cancela el gap del .kds-screen para que
5869
+ quede pegado debajo de la card y no flotando lejos. Las dos cards
5870
+ (header/body) sí conservan su separación. */
5871
+ .kds-screen > .kds-secure-footer {
5872
+ margin-top: calc(-1 * var(--kds-spacing-3));
4996
5873
  }
4997
5874
 
4998
5875
  .kds-secure-footer-lock {
@@ -5014,6 +5891,32 @@ dialog#surveyModal button.circle {
5014
5891
  display: block;
5015
5892
  object-fit: contain;
5016
5893
  overflow: visible;
5894
+ /* Corrección óptica: la masa visible del wordmark (el cuerpo de "Khipu") queda sobre el
5895
+ centro geométrico de su viewBox (45x15) porque el descendente de la "p" ocupa la parte
5896
+ baja. Al centrar por caja (align-items:center) el logo se ve ~1px alto respecto al texto,
5897
+ así que se baja 0.75px para alinear el centro óptico. Alto fijo (11px) → nudge consistente. */
5898
+ position: relative;
5899
+ top: 0.75px;
5900
+ }
5901
+
5902
+ /* Divisor entre el logo de Khipu y el del PSP ("Khipu | klap") */
5903
+ .kds-secure-footer-sep {
5904
+ width: 1px;
5905
+ height: 0.85em;
5906
+ background: currentColor;
5907
+ opacity: 0.35;
5908
+ flex: 0 0 auto;
5909
+ }
5910
+
5911
+ /* Logo del PSP (proveedor de pagos): lo provee el consumidor, lo alineamos al mismo
5912
+ alto que el mark de Khipu. Sirve para <img> o un elemento con .kds-psp-mark. */
5913
+ .kds-secure-footer img,
5914
+ .kds-secure-footer .kds-psp-mark {
5915
+ height: 11px;
5916
+ width: auto;
5917
+ flex: 0 0 auto;
5918
+ display: block;
5919
+ object-fit: contain;
5017
5920
  }
5018
5921
 
5019
5922
  .kds-secure-footer-code {
@@ -5029,26 +5932,45 @@ dialog#surveyModal button.circle {
5029
5932
  background: none;
5030
5933
  border: 0;
5031
5934
  padding: 0;
5935
+ /* Reset del bare `button { height: 2.5rem }` de BeerCSS (scoped en .kds-theme-root):
5936
+ sin esto el toggle quedaba en una caja de 40px con el texto centrado → espacio
5937
+ irregular arriba (pegado al resumen) y abajo (~26px hasta el panel). Con height
5938
+ auto el botón ajusta a su contenido y el ritmo lo gobiernan los márgenes. */
5939
+ height: auto;
5032
5940
  color: var(--kds-color-primary-main);
5033
5941
  font-weight: var(--kds-font-weight-medium);
5034
5942
  font-size: var(--kds-font-size-sm);
5035
- padding-bottom: var(--kds-spacing-1-25);
5036
5943
  cursor: pointer;
5037
5944
  display: inline-flex;
5038
5945
  align-items: center;
5039
5946
  gap: 0;
5040
5947
  }
5041
5948
 
5042
- .kds-expand-toggle:hover {
5949
+ .kds-expand-toggle:hover,
5950
+ .kds-expand-toggle:focus,
5951
+ .kds-expand-toggle:active {
5043
5952
  background: transparent;
5953
+ outline: none;
5954
+ box-shadow: none;
5044
5955
  }
5045
5956
 
5046
- .kds-expand-toggle:hover span {
5957
+ .kds-expand-toggle:hover span,
5958
+ .kds-expand-toggle:focus span,
5959
+ .kds-expand-toggle:active span {
5047
5960
  text-decoration: underline;
5048
5961
  }
5049
5962
 
5050
5963
  .kds-expand-toggle i {
5051
5964
  font-size: var(--kds-font-size-base);
5965
+ /* BeerCSS estiliza el `i` bare como caja flex de 30px (height/width/min: 30px), que
5966
+ inflaba el toggle y dejaba aire vertical de más alrededor del label. La achicamos a
5967
+ 1.25em MANTENIENDO el centrado flex de BeerCSS (display:flex/align/justify) — así el
5968
+ caret queda compacto Y ópticamente centrado con el texto (no usar height:auto ni
5969
+ line-height:1: descentran el glifo). */
5970
+ width: 1.25em;
5971
+ height: 1.25em;
5972
+ min-width: 0;
5973
+ min-height: 0;
5052
5974
  transition: transform var(--kds-transition-shorter, 0.2s);
5053
5975
  }
5054
5976
 
@@ -5068,7 +5990,10 @@ dialog#surveyModal button.circle {
5068
5990
  }
5069
5991
 
5070
5992
  .kds-expand-panel.open {
5071
- max-height: 800px;
5993
+ /* Fallback cap for no-JS consumers. With JS (React useExpandToggle / vanilla
5994
+ initExpandToggle) the panel's inline max-height is set to its exact scrollHeight,
5995
+ which overrides this and prevents clipping regardless of content length. */
5996
+ max-height: 2000px;
5072
5997
  margin-top: 0;
5073
5998
  }
5074
5999
 
@@ -5186,13 +6111,17 @@ dialog#surveyModal button.circle {
5186
6111
 
5187
6112
  .kds-status-block {
5188
6113
  text-align: center;
5189
- padding: var(--kds-spacing-6) 0;
6114
+ /* Padding vertical estándar: spacing-2 (16px), el mismo rhythm inter-elementos
6115
+ que usan kds-btn-stack y kds-hr-dashed. NO usar spacing-6 (48px): genera
6116
+ demasiado espacio cuando el bloque se compone con header/divider alrededor. */
6117
+ padding: var(--kds-spacing-2) 0;
5190
6118
  }
5191
6119
 
5192
6120
  .kds-status-block-icon {
5193
6121
  width: var(--kds-status-icon-size);
5194
6122
  height: var(--kds-status-icon-size);
5195
- margin: 0 auto var(--kds-spacing-3);
6123
+ /* spacing-1 (8px) icono→título: elementos relacionados dentro del bloque. */
6124
+ margin: 0 auto var(--kds-spacing-1);
5196
6125
  border-radius: var(--kds-radius-full);
5197
6126
  display: grid;
5198
6127
  place-items: center;
@@ -5205,15 +6134,22 @@ dialog#surveyModal button.circle {
5205
6134
 
5206
6135
  .kds-status-block-title {
5207
6136
  font-size: var(--kds-font-size-xl);
5208
- font-weight: var(--kds-font-weight-bold);
6137
+ font-weight: var(--kds-font-weight-semibold);
5209
6138
  color: var(--kds-color-text-primary);
5210
6139
  margin: 0 0 var(--kds-spacing-1);
6140
+ /* El reset global :where(h2) usa estas vars con !important; así se overridea. */
6141
+ --kds-typography-h2-margin-block-end: var(--kds-spacing-1);
5211
6142
  }
5212
6143
 
5213
6144
  .kds-status-block-description {
5214
6145
  font-size: var(--kds-font-size-sm);
5215
- color: var(--kds-color-text-secondary);
6146
+ /* Mismo color que el título: título y subtítulo parejos en resultados. */
6147
+ color: var(--kds-color-text-primary);
5216
6148
  margin: 0;
6149
+ /* !important: anula el auto-espaciado de hermanos de BeerCSS
6150
+ (margin-block-start: 1rem, especificidad 0,5,1 imposible de igualar).
6151
+ La separación título→descripción la da el margin-bottom del título. */
6152
+ margin-top: 0 !important;
5217
6153
  }
5218
6154
 
5219
6155
  /* Variant: success */
@@ -5223,11 +6159,11 @@ dialog#surveyModal button.circle {
5223
6159
  color: var(--kds-color-success-main);
5224
6160
  }
5225
6161
 
5226
- /* Variant: pending (animated spinner) */
6162
+ /* Variant: pending (animated blue spinner, sin icono interno) */
5227
6163
  .kds-status-block[data-status="pending"] .kds-status-block-icon {
5228
6164
  background: transparent;
5229
6165
  border: 3px solid var(--kds-color-divider);
5230
- border-top-color: var(--kds-color-primary-main);
6166
+ border-top-color: var(--kds-color-info-main);
5231
6167
  animation: kds-spin 1s linear infinite;
5232
6168
  }
5233
6169
 
@@ -5245,10 +6181,12 @@ dialog#surveyModal button.circle {
5245
6181
  color: var(--kds-color-error-main);
5246
6182
  }
5247
6183
 
5248
- /* Variant: info — icon has its own circle, so no outer border/background */
6184
+ /* Variant: info — usar SIEMPRE con icon "info_i" (i minúscula sin glyph circular)
6185
+ para que solo se vea nuestro círculo decorativo. Iconos como "info" tienen
6186
+ su propio círculo built-in → causarían doble círculo. */
5249
6187
  .kds-status-block[data-status="info"] .kds-status-block-icon {
5250
- background: none;
5251
- border: none;
6188
+ background: var(--kds-color-info-soft);
6189
+ border: var(--kds-border-width-md) solid var(--kds-color-info-main);
5252
6190
  color: var(--kds-color-info-main);
5253
6191
  }
5254
6192
 
@@ -5257,7 +6195,7 @@ dialog#surveyModal button.circle {
5257
6195
  text-align: left;
5258
6196
  display: flex;
5259
6197
  align-items: center;
5260
- gap: var(--kds-spacing-3);
6198
+ gap: var(--kds-spacing-2);
5261
6199
  padding: var(--kds-spacing-1) 0;
5262
6200
  }
5263
6201
 
@@ -5299,6 +6237,9 @@ dialog#surveyModal button.circle {
5299
6237
  .kds-bottom-sheet {
5300
6238
  width: 100%;
5301
6239
  max-width: var(--kds-bottom-sheet-max-width);
6240
+ max-height: 90dvh;
6241
+ display: flex;
6242
+ flex-direction: column;
5302
6243
  background: var(--kds-color-background-paper);
5303
6244
  border-radius: var(--kds-radius-2xl) var(--kds-radius-2xl) 0 0;
5304
6245
  padding: var(--kds-spacing-3-5) var(--kds-spacing-3) var(--kds-spacing-3);
@@ -5319,6 +6260,42 @@ dialog#surveyModal button.circle {
5319
6260
  background: var(--kds-color-divider);
5320
6261
  }
5321
6262
 
6263
+ /* Close button — top-right discreto, NO usa kds-btn (rompía el flex layout) */
6264
+ .kds-bottom-sheet-close {
6265
+ position: absolute;
6266
+ top: var(--kds-spacing-1);
6267
+ right: var(--kds-spacing-1);
6268
+ width: 32px;
6269
+ height: 32px;
6270
+ display: inline-flex;
6271
+ align-items: center;
6272
+ justify-content: center;
6273
+ padding: 0;
6274
+ background: transparent;
6275
+ border: 0;
6276
+ border-radius: 50%;
6277
+ color: var(--kds-color-text-secondary);
6278
+ cursor: pointer;
6279
+ transition: background-color 0.15s ease;
6280
+ }
6281
+
6282
+ .kds-bottom-sheet-close:hover {
6283
+ background: rgba(0, 0, 0, 0.06);
6284
+ }
6285
+
6286
+ .kds-bottom-sheet-close i {
6287
+ font-size: 20px;
6288
+ line-height: 1;
6289
+ }
6290
+
6291
+ /* Body container — separa el content del title/actions */
6292
+ .kds-bottom-sheet-body {
6293
+ text-align: left;
6294
+ margin-top: var(--kds-spacing-1);
6295
+ overflow-y: auto;
6296
+ min-height: 0;
6297
+ }
6298
+
5322
6299
  .kds-bottom-sheet-icon {
5323
6300
  font-size: var(--kds-font-size-4xl);
5324
6301
  }
@@ -5365,6 +6342,19 @@ dialog#surveyModal button.circle {
5365
6342
  to { opacity: 1; }
5366
6343
  }
5367
6344
 
6345
+ /* Botón con llenado progresivo (feedback visual de auto-cierre).
6346
+ Duración parametrizable con --kds-fill-duration (default 12s). */
6347
+ .kds-btn-fill-progress {
6348
+ background-image: linear-gradient(to right, var(--kds-color-primary-dark), var(--kds-color-primary-dark));
6349
+ background-repeat: no-repeat;
6350
+ background-size: 0% 100%;
6351
+ animation: kds-btn-fill var(--kds-fill-duration, 12s) linear forwards;
6352
+ }
6353
+
6354
+ @keyframes kds-btn-fill {
6355
+ to { background-size: 100% 100%; }
6356
+ }
6357
+
5368
6358
  @keyframes kds-rise {
5369
6359
  from { transform: translateY(var(--kds-spacing-2-5)); opacity: 0.4; }
5370
6360
  to { transform: none; opacity: 1; }
@@ -5552,6 +6542,30 @@ dialog#surveyModal button.circle {
5552
6542
  /* No max-height — clip-path on parent handles visual collapse without layout changes */
5553
6543
  .kds-invoice-sticky .kds-invoice-collapsible {
5554
6544
  opacity: calc(1 - var(--collapse-progress) * 1.5);
6545
+
6546
+ /* Scroll interno discreto (mobile): cuando el detalle abierto excede el viewport, el
6547
+ collapsible scrollea internamente (monto/merchant quedan fijos arriba) para poder leer
6548
+ todo el detalle. Al tocar el fondo, `overscroll-behavior: auto` ENCADENA el gesto al
6549
+ scroll del body → dispara useStickyInvoiceCollapse → colapsa el header y aparece el form
6550
+ (flujo natural). Se auto-desactiva con el detalle cerrado (contenido más corto que el
6551
+ max-height → sin scroll ni efecto visual). */
6552
+ max-height: calc(100vh - var(--kds-spacing-12) - var(--kds-spacing-4));
6553
+ max-height: calc(100dvh - var(--kds-spacing-12) - var(--kds-spacing-4));
6554
+ overflow-y: auto;
6555
+ overflow-x: hidden;
6556
+ overscroll-behavior-y: auto;
6557
+ scrollbar-width: thin;
6558
+ scrollbar-color: var(--kds-color-gray-300) transparent;
6559
+ }
6560
+ .kds-invoice-sticky .kds-invoice-collapsible::-webkit-scrollbar {
6561
+ width: 4px;
6562
+ }
6563
+ .kds-invoice-sticky .kds-invoice-collapsible::-webkit-scrollbar-thumb {
6564
+ background: var(--kds-color-gray-300);
6565
+ border-radius: var(--kds-radius-full);
6566
+ }
6567
+ .kds-invoice-sticky .kds-invoice-collapsible::-webkit-scrollbar-track {
6568
+ background: transparent;
5555
6569
  }
5556
6570
 
5557
6571
  /* Amount: 30px → 24px (progressive) */
@@ -5623,6 +6637,14 @@ dialog#surveyModal button.circle {
5623
6637
  margin-top: var(--kds-spacing-1);
5624
6638
  }
5625
6639
 
6640
+ /* Ritmo uniforme alrededor del toggle: spacing-2 arriba (resumen↔"Ver detalle")
6641
+ iguala el padding-top spacing-2 que la .kds-detail-list da debajo
6642
+ ("Ver detalle"↔primer label del panel). Antes el alto fijo del bare button
6643
+ (40px) hacía que el espacio de arriba y de abajo fueran distintos. */
6644
+ .kds-invoice-collapsible > .kds-expand-toggle {
6645
+ margin-top: var(--kds-spacing-2);
6646
+ }
6647
+
5626
6648
  /* -- Invoice Summary -- */
5627
6649
  .kds-invoice-summary {
5628
6650
  display: flex;
@@ -5646,6 +6668,22 @@ div.kds-invoice-header,
5646
6668
  padding: 0;
5647
6669
  border-radius: 0;
5648
6670
  align-content: initial;
6671
+ /* Override BeerCSS `header { min-height: ... }` — el header debe ajustarse a su
6672
+ contenido (sigue el alto del merchant tile: 64px→50px al colapsar). Sin esto
6673
+ quedaba un min-height fijo de 64px → hueco muerto debajo al colapsar en mobile. */
6674
+ min-height: 0;
6675
+ }
6676
+
6677
+ /* Mobile: center-align el header (merchant tile vs bloque monto+código) tanto
6678
+ expandido como colapsado. Al quitar el logo del header, el bloque de texto quedaba
6679
+ más bajo que el merchant tile y con `flex-start` dejaba hueco abajo; centrado los
6680
+ alinea. CSS-only (no depende de la clase .is-collapsed, que el JS de collapse no setea). */
6681
+ @media (max-width: 767px) {
6682
+ header.kds-invoice-header,
6683
+ div.kds-invoice-header,
6684
+ .kds-invoice-header {
6685
+ align-items: center;
6686
+ }
5649
6687
  }
5650
6688
 
5651
6689
  /* Reset BeerCSS sibling margin on <p> inside invoice header — specificity (0,4,1) ties BeerCSS, wins by source order */
@@ -5655,7 +6693,7 @@ div.kds-invoice-header,
5655
6693
  }
5656
6694
 
5657
6695
  .kds-invoice-amount {
5658
- font-weight: var(--kds-font-weight-bold);
6696
+ font-weight: var(--kds-font-weight-semibold);
5659
6697
  font-size: var(--kds-font-size-3xl);
5660
6698
  line-height: var(--kds-line-height-tight);
5661
6699
  letter-spacing: var(--kds-letter-spacing-wide);
@@ -5677,12 +6715,16 @@ div.kds-invoice-header,
5677
6715
  text-transform: uppercase;
5678
6716
  margin: 0;
5679
6717
  margin-block: unset;
5680
- margin: var(--kds-spacing-1) 0;
6718
+ display: flex;
6719
+ gap: var(--kds-spacing-1-5);
5681
6720
  }
5682
6721
 
5683
6722
  .kds-invoice-code-value {
6723
+ color: var(--kds-color-gray-400);
6724
+ }
6725
+
6726
+ .kds-invoice-code-value--lowercase {
5684
6727
  text-transform: lowercase;
5685
- color: var(--kds-text-primary);
5686
6728
  }
5687
6729
 
5688
6730
  .kds-invoice-merchant {
@@ -5694,6 +6736,7 @@ div.kds-invoice-header,
5694
6736
  place-items: center;
5695
6737
  color: #fff;
5696
6738
  flex-shrink: 0;
6739
+ overflow: hidden;
5697
6740
  }
5698
6741
 
5699
6742
  .kds-invoice-merchant i {
@@ -5706,6 +6749,12 @@ div.kds-invoice-header,
5706
6749
  color: var(--kds-color-text-primary);
5707
6750
  }
5708
6751
 
6752
+ /* Neutro oscuro para logos claros (detección de luminancia — KTUF-204). */
6753
+ .kds-invoice-merchant-neutral.dark {
6754
+ background: var(--kds-color-gray-800);
6755
+ border-color: var(--kds-color-gray-700);
6756
+ }
6757
+
5709
6758
  .kds-invoice-merchant.initials {
5710
6759
  font-weight: 700;
5711
6760
  font-size: 11px;
@@ -5713,27 +6762,42 @@ div.kds-invoice-header,
5713
6762
  }
5714
6763
 
5715
6764
  .kds-invoice-merchant img {
6765
+ /* `contain` sobre el fondo neutro: el logo se muestra completo y las
6766
+ transparencias no quedan sobre el color de marca (KTUF-204). */
5716
6767
  width: 100%;
5717
6768
  height: 100%;
5718
- object-fit: cover;
5719
- border-radius: var(--kds-radius-md);
6769
+ object-fit: contain;
6770
+ padding: var(--kds-spacing-0-5);
5720
6771
  }
5721
6772
 
5722
6773
  /* -- Card Title -- */
5723
6774
  .kds-card-title {
5724
- font-weight: 700;
6775
+ font-weight: var(--kds-font-weight-semibold);
5725
6776
  font-size: var(--kds-font-size-base);
5726
6777
  line-height: 1.5;
5727
6778
  letter-spacing: -0.31px;
5728
6779
  color: var(--kds-color-text-primary);
5729
- margin-bottom: var(--kds-spacing-2) !important;
6780
+ /* sin !important: no hay regla de margin-bottom para h1 en BeerCSS que competir, y así un
6781
+ consumidor puede anularlo (p.ej. FormTitle dentro de un Stack que ya da el espacio). */
6782
+ margin-bottom: var(--kds-spacing-2);
6783
+ }
6784
+
6785
+ /* Opt-in size modifiers (additive — do NOT change default 16/600) */
6786
+ .kds-card-title--lg {
6787
+ font-size: var(--kds-font-size-xl); /* 20px */
6788
+ font-weight: var(--kds-font-weight-semibold);
6789
+ }
6790
+
6791
+ .kds-card-title--xl {
6792
+ font-size: var(--kds-font-size-2xl); /* 24px */
6793
+ font-weight: var(--kds-font-weight-semibold);
5730
6794
  }
5731
6795
 
5732
6796
  /* -- Key-Value Grid -- */
5733
6797
  .kds-kv {
5734
6798
  display: grid;
5735
6799
  grid-template-columns: auto 1fr;
5736
- column-gap: var(--kds-spacing-1-5);
6800
+ column-gap: var(--kds-spacing-1);
5737
6801
  align-items: baseline;
5738
6802
  }
5739
6803
 
@@ -5750,7 +6814,7 @@ div.kds-invoice-header,
5750
6814
  margin: 0;
5751
6815
  font-size: var(--kds-font-size-sm);
5752
6816
  line-height: var(--kds-line-height-relaxed);
5753
- font-weight: var(--kds-font-weight-bold);
6817
+ font-weight: var(--kds-font-weight-semibold);
5754
6818
  letter-spacing: normal;
5755
6819
  color: var(--kds-color-gray-800);
5756
6820
  min-width: 0;
@@ -5759,6 +6823,20 @@ div.kds-invoice-header,
5759
6823
  text-overflow: ellipsis;
5760
6824
  }
5761
6825
 
6826
+ /* -- Summary panel --
6827
+ Recuadro de datos del pago en pantallas de resultado: contenido en columna
6828
+ (gap spacing-2, típicamente pares kv) dentro de un borde sutil. */
6829
+ .kds-summary-panel {
6830
+ display: flex;
6831
+ flex-direction: column;
6832
+ gap: var(--kds-spacing-2);
6833
+ width: 100%;
6834
+ padding: var(--kds-spacing-2);
6835
+ border: var(--kds-border-width-sm) solid var(--kds-color-border-default);
6836
+ border-radius: var(--kds-radius-card);
6837
+ text-align: left;
6838
+ }
6839
+
5762
6840
  /* -- Dividers -- */
5763
6841
  .kds-hr {
5764
6842
  height: 1px;
@@ -5778,16 +6856,28 @@ div.kds-invoice-header,
5778
6856
  .kds-detail-list {
5779
6857
  display: flex;
5780
6858
  flex-direction: column;
5781
- gap: var(--kds-spacing-1-5);
6859
+ /* spacing-2 entre grupos del detalle (separación estándar entre piezas de info
6860
+ distintas, ej. "Emisor cobro" vs "Descripción"). El padding-top da la misma
6861
+ separación spacing-2 arriba del primer grupo (Asunto↔Emisor cobro). */
6862
+ gap: var(--kds-spacing-2);
5782
6863
  margin: 0;
5783
- padding: 0 0 var(--kds-spacing-2);
6864
+ padding: var(--kds-spacing-2) 0 0;
5784
6865
  }
5785
6866
 
5786
- .kds-detail-group {
5787
- margin-bottom: var(--kds-spacing-1-5);
6867
+ @media (max-width: 767px) {
6868
+ .kds-detail-list {
6869
+ padding-bottom: var(--kds-spacing-2);
6870
+ }
5788
6871
  }
5789
6872
 
5790
- .kds-detail-group:last-child {
6873
+ .kds-detail-group {
6874
+ /* El espacio ENTRE grupos lo da el `gap` de .kds-detail-list (spacing-2).
6875
+ Dentro del grupo, label↔value llevan un gap chico (spacing-0-5) para un
6876
+ ritmo parejo: antes el dt iba pegado al dd (0px) y se veía desigual frente
6877
+ a los 16px entre los demás elementos del panel. */
6878
+ display: flex;
6879
+ flex-direction: column;
6880
+ gap: var(--kds-spacing-0-5);
5791
6881
  margin-bottom: 0;
5792
6882
  }
5793
6883
 
@@ -5796,6 +6886,7 @@ div.kds-invoice-header,
5796
6886
  letter-spacing: var(--kds-letter-spacing-wide);
5797
6887
  color: var(--kds-color-text-hint);
5798
6888
  text-transform: uppercase;
6889
+ margin: 0;
5799
6890
  }
5800
6891
 
5801
6892
  .kds-detail-group dd {
@@ -5805,6 +6896,19 @@ div.kds-invoice-header,
5805
6896
  color: var(--kds-color-text-primary);
5806
6897
  }
5807
6898
 
6899
+ /* Imagen adjunta del cobro dentro del panel de detalle (ej. comprobante/producto).
6900
+ Reemplaza los inline styles del antiguo modal MerchantInfo: ancho contenido, borde
6901
+ y radio del DS. Va como un grupo más de la .kds-detail-list (hereda su gap). */
6902
+ .kds-detail-image {
6903
+ display: block;
6904
+ max-width: 100%;
6905
+ width: 160px;
6906
+ height: auto;
6907
+ object-fit: contain;
6908
+ border-radius: var(--kds-radius-md);
6909
+ border: 1px solid var(--kds-color-border);
6910
+ }
6911
+
5808
6912
  /* -- Amount Summary Row -- */
5809
6913
  .kds-amount-row {
5810
6914
  display: flex;
@@ -5864,16 +6968,16 @@ div.kds-invoice-header,
5864
6968
  font-size: var(--kds-font-size-sm);
5865
6969
  }
5866
6970
 
5867
- .kds-recap-list .k {
6971
+ .kds-recap-list .kds-key {
5868
6972
  color: var(--kds-color-text-secondary);
5869
6973
  }
5870
6974
 
5871
- .kds-recap-list .v {
6975
+ .kds-recap-list .kds-value {
5872
6976
  color: var(--kds-color-text-primary);
5873
6977
  font-weight: 500;
5874
6978
  }
5875
6979
 
5876
- .kds-recap-list .v.placeholder {
6980
+ .kds-recap-list .kds-value.placeholder {
5877
6981
  color: var(--kds-color-text-hint);
5878
6982
  }
5879
6983
 
@@ -5900,6 +7004,72 @@ a.kds-btn-success:disabled {
5900
7004
  box-shadow: none;
5901
7005
  }
5902
7006
 
7007
+ /* -- Button Warning (amber CTA) -- */
7008
+ button.kds-btn-warning,
7009
+ a.kds-btn-warning {
7010
+ background: var(--kds-color-warning-main);
7011
+ color: var(--kds-color-warning-contrast);
7012
+ border: none;
7013
+ }
7014
+
7015
+ button.kds-btn-warning:hover:not(:disabled),
7016
+ a.kds-btn-warning:hover:not(:disabled) {
7017
+ background: var(--kds-color-warning-dark);
7018
+ }
7019
+
7020
+ button.kds-btn-warning:active:not(:disabled),
7021
+ button.kds-btn-warning:focus-visible:not(:disabled),
7022
+ a.kds-btn-warning:active:not(:disabled),
7023
+ a.kds-btn-warning:focus-visible:not(:disabled) {
7024
+ background: var(--kds-color-warning-dark);
7025
+ outline: 2px solid var(--kds-color-warning-main);
7026
+ outline-offset: 2px;
7027
+ }
7028
+
7029
+ button.kds-btn-warning:disabled,
7030
+ a.kds-btn-warning:disabled {
7031
+ background-color: var(--kds-color-action-disabled-bg);
7032
+ color: var(--kds-color-action-disabled);
7033
+ box-shadow: none;
7034
+ }
7035
+
7036
+ button.kds-btn-warning::after {
7037
+ display: none;
7038
+ }
7039
+
7040
+ /* -- Button Error (red / destructive CTA) -- */
7041
+ button.kds-btn-error,
7042
+ a.kds-btn-error {
7043
+ background: var(--kds-color-error-main);
7044
+ color: var(--kds-color-error-contrast);
7045
+ border: none;
7046
+ }
7047
+
7048
+ button.kds-btn-error:hover:not(:disabled),
7049
+ a.kds-btn-error:hover:not(:disabled) {
7050
+ background: var(--kds-color-error-dark);
7051
+ }
7052
+
7053
+ button.kds-btn-error:active:not(:disabled),
7054
+ button.kds-btn-error:focus-visible:not(:disabled),
7055
+ a.kds-btn-error:active:not(:disabled),
7056
+ a.kds-btn-error:focus-visible:not(:disabled) {
7057
+ background: var(--kds-color-error-dark);
7058
+ outline: 2px solid var(--kds-color-error-main);
7059
+ outline-offset: 2px;
7060
+ }
7061
+
7062
+ button.kds-btn-error:disabled,
7063
+ a.kds-btn-error:disabled {
7064
+ background-color: var(--kds-color-action-disabled-bg);
7065
+ color: var(--kds-color-action-disabled);
7066
+ box-shadow: none;
7067
+ }
7068
+
7069
+ button.kds-btn-error::after {
7070
+ display: none;
7071
+ }
7072
+
5903
7073
  /* -- Field Helper Text -- */
5904
7074
  .kds-field-helper {
5905
7075
  font-size: var(--kds-font-size-xs);
@@ -5942,6 +7112,8 @@ button.kds-btn-success::after {
5942
7112
  /* -- Alert inline (borderless, used inside cards) -- */
5943
7113
  .kds-alert-inline {
5944
7114
  border: none;
7115
+ padding: var(--kds-spacing-1) var(--kds-spacing-1-5);
7116
+ margin-bottom: var(--kds-spacing-1-5);
5945
7117
  }
5946
7118
 
5947
7119
  /* -- Card dimmed (behind overlays) -- */
@@ -6010,6 +7182,25 @@ button.kds-btn-success::after {
6010
7182
  fill: none;
6011
7183
  }
6012
7184
 
7185
+ /* BeerCSS fuerza fill:currentcolor en todo svg, pisando el atributo de
7186
+ presentación; un SVG que declara fill="none" (ilustraciones de trazo)
7187
+ debe conservarlo. */
7188
+ svg[fill='none'] {
7189
+ fill: none;
7190
+ }
7191
+
7192
+ /* -- Bottom sheet centered content --
7193
+ Contenido escueto centrado verticalmente con altura mínima estable, para que
7194
+ el sheet no encoja cuando la vista tiene pocos elementos (p.ej. drawer de
7195
+ autorización: título + ilustración + timer). */
7196
+ .kds-bottom-sheet-centered-content {
7197
+ display: flex;
7198
+ flex-direction: column;
7199
+ align-items: center;
7200
+ justify-content: center;
7201
+ min-height: var(--kds-bottom-sheet-content-min-height, 21rem);
7202
+ }
7203
+
6013
7204
  /* -- Bottom sheet description (subtle / smaller) -- */
6014
7205
  .kds-bottom-sheet-description-subtle {
6015
7206
  color: var(--kds-color-text-secondary);
@@ -6043,17 +7234,42 @@ button.kds-btn-success::after {
6043
7234
  }
6044
7235
 
6045
7236
  .kds-bill-description-picture {
6046
- width: 120px;
6047
- height: 120px;
7237
+ max-width: 100px;
6048
7238
  object-fit: contain;
6049
7239
  background: var(--kds-color-background-paper);
6050
- padding: var(--kds-spacing-1-25);
6051
- border-radius: var(--kds-radius-md);
6052
- margin-top: var(--kds-spacing-1);
7240
+ margin-top: var(--kds-spacing-1-25);
6053
7241
  display: block;
6054
7242
  box-sizing: content-box;
6055
7243
  }
6056
7244
 
7245
+ /* -- Bill Attachments -- */
7246
+ .kds-bill-attachments {
7247
+ display: flex;
7248
+ flex-direction: column;
7249
+ gap: var(--kds-spacing-0-75);
7250
+ }
7251
+
7252
+ .kds-bill-attachment {
7253
+ display: inline-flex;
7254
+ align-items: center;
7255
+ justify-content: flex-start;
7256
+ width: fit-content;
7257
+ color: var(--kds-color-info-main);
7258
+ font-size: var(--kds-font-size-sm);
7259
+ font-weight: var(--kds-font-weight-medium);
7260
+ text-decoration: none;
7261
+ }
7262
+
7263
+ .kds-bill-attachment:hover span {
7264
+ text-decoration: underline;
7265
+ }
7266
+
7267
+ .kds-bill-attachment i {
7268
+ font-size: var(--kds-font-size-lg);
7269
+ min-width: unset;
7270
+ justify-content: flex-start;
7271
+ }
7272
+
6057
7273
  /* -- Share Card (mustContinue) -- */
6058
7274
  .kds-share-card {
6059
7275
  margin-top: var(--kds-spacing-2);
@@ -6163,8 +7379,10 @@ button.kds-btn-success::after {
6163
7379
  Desktop (min-width: 768px) restores padding + full border-radius. */
6164
7380
  .kds-payment-flow .kds-card-elevated {
6165
7381
  margin-top: 0;
6166
- padding-top: 0;
6167
- padding-bottom: 0;
7382
+ /* Vertical > lateral: la card del flujo respira arriba/abajo (spacing-3)
7383
+ manteniendo el padding lateral del base (spacing-2 / spacing-3 mobile). */
7384
+ padding-top: var(--kds-spacing-3);
7385
+ padding-bottom: var(--kds-spacing-3);
6168
7386
  }
6169
7387
 
6170
7388
  /* Reset BeerCSS sibling margin on form/section inside payment cards.
@@ -6179,12 +7397,43 @@ button.kds-btn-success::after {
6179
7397
  padding-bottom: 0;
6180
7398
  }
6181
7399
 
6182
- /* Payment stage full-viewport centered wrapper */
7400
+ /* Body card: alto mínimo estable para que NO salte entre estados de distinta altura
7401
+ (loader/progress ↔ formulario). Solo la body card = hijo directo de `.kds-screen`
7402
+ (los headers van dentro de `.kds-invoice-sticky-wrap`, no la afecta).
7403
+ Flex-column para que el contenido quede arriba y el footer interno (versión / secure
7404
+ footer) pueda pinearse al fondo con `margin-top: auto` aunque el contenido sea corto. */
7405
+ .kds-screen > .kds-card-elevated {
7406
+ min-height: 36rem;
7407
+ display: flex;
7408
+ flex-direction: column;
7409
+ /* mismo radio que el header (invoice-sticky usa radius-card); el base card-elevated
7410
+ es radius-md (8px) y quedaba distinto al header en desktop. */
7411
+ border-radius: var(--kds-radius-card);
7412
+ }
7413
+
7414
+ /* Variante sin radio superior: pantallas de resultado (éxito/fallo/timeout) que van
7415
+ SIN header arriba — la body card va sola y su tope queda plano (flush) en vez de
7416
+ con esquinas redondeadas sueltas. El padding del card sigue manejando el inset. */
7417
+ /* Tope plano SOLO en mobile (< 768px): la body card se pega al borde superior del widget
7418
+ (igual que el header sticky, que también aplana el tope solo en mobile). En desktop la card
7419
+ va centrada y separada, así que conserva el border-radius superior redondeado. */
7420
+ @media (max-width: 767px) {
7421
+ .kds-screen > .kds-card-elevated.kds-card-elevated--flush-top,
7422
+ .kds-card-elevated.kds-card-elevated--flush-top {
7423
+ border-top-left-radius: 0;
7424
+ border-top-right-radius: 0;
7425
+ }
7426
+ }
7427
+
7428
+ /* Payment stage — full-viewport centered wrapper.
7429
+ Fondo muted (gris) para que las cards blancas (header + body) y el gap entre
7430
+ ellas se distingan; sin esto, card blanca sobre fondo blanco se funden. */
6183
7431
  .kds-payment-stage {
6184
7432
  min-height: 100vh;
6185
7433
  display: flex;
6186
7434
  justify-content: center;
6187
7435
  padding: var(--kds-spacing-2-5) var(--kds-spacing-2) var(--kds-spacing-8);
7436
+ background: var(--kds-color-background-muted);
6188
7437
  }
6189
7438
 
6190
7439
  /* Payment flow — narrow column */
@@ -6218,23 +7467,23 @@ button.kds-btn-success::after {
6218
7467
  width: 100%;
6219
7468
  }
6220
7469
 
6221
- .kds-payment-flow .kds-card-elevated {
6222
- padding-top: var(--kds-spacing-2);
6223
- padding-bottom: var(--kds-spacing-2);
6224
- }
6225
-
6226
- /* Invoice sticky card: progressive padding-top (expanded 20px → collapsed 8px).
6227
- Overrides base rule at same specificity; source order wins here. */
7470
+ /* Invoice sticky card padding (mobile).
7471
+ Top: estático 12px. Bottom: progresivo 16px (expandido, = desktop) → 8px (colapsado).
7472
+ El padding-bottom animado se reduce al colapsar — sin depender de que el clip-path
7473
+ corte el padding abruptamente. */
6228
7474
  .kds-payment-flow .kds-card-elevated.kds-invoice-sticky {
6229
7475
  padding-top: var(--kds-spacing-1-5);
7476
+ padding-bottom: calc(
7477
+ var(--kds-spacing-2)
7478
+ - var(--kds-spacing-1) * var(--collapse-progress, 0)
7479
+ );
6230
7480
  }
6231
7481
 
6232
7482
 
6233
7483
  }
6234
7484
 
6235
- /* Desktop: restore card padding and full border-radius on invoice sticky */
7485
+ /* Desktop: restore sticky header padding and full border-radius on invoice sticky */
6236
7486
  @media (min-width: 768px) {
6237
- .kds-payment-flow .kds-card-elevated,
6238
7487
  .kds-payment-flow .kds-card-elevated.kds-invoice-sticky {
6239
7488
  padding-top: var(--kds-spacing-2);
6240
7489
  padding-bottom: var(--kds-spacing-2);
@@ -6538,11 +7787,8 @@ button.kds-btn-success::after {
6538
7787
  display: none;
6539
7788
  }
6540
7789
 
6541
- .kds-bank-modal-search {
6542
- padding: 0 var(--kds-spacing-2) var(--kds-spacing-1-5);
6543
- }
6544
-
6545
- .kds-bank-modal-search input {
7790
+ /* Search field reutilizable (standalone o dentro del KdsBankModal). */
7791
+ .kds-search-field {
6546
7792
  width: 100%;
6547
7793
  padding: var(--kds-spacing-1-25) var(--kds-spacing-1-5);
6548
7794
  border: 1px solid var(--kds-color-divider);
@@ -6554,15 +7800,57 @@ button.kds-btn-success::after {
6554
7800
  background: var(--kds-color-surface);
6555
7801
  }
6556
7802
 
6557
- .kds-bank-modal-search input::placeholder {
7803
+ .kds-search-field::placeholder {
6558
7804
  color: var(--kds-color-text-hint);
6559
7805
  }
6560
7806
 
6561
- .kds-bank-modal-search input:focus {
7807
+ .kds-search-field:focus {
6562
7808
  border-color: var(--kds-color-primary-main);
6563
7809
  box-shadow: 0 0 0 2px var(--kds-color-primary-faint);
6564
7810
  }
6565
7811
 
7812
+ /* Variante con ícono (withIcon): lupa posicionada DENTRO del input, a la derecha. */
7813
+ .kds-search-field-wrapper {
7814
+ position: relative;
7815
+ width: 100%;
7816
+ }
7817
+
7818
+ .kds-search-field-icon {
7819
+ position: absolute;
7820
+ right: var(--kds-spacing-1-5);
7821
+ top: 50%;
7822
+ transform: translateY(-50%);
7823
+ font-size: 20px;
7824
+ color: var(--kds-color-text-hint);
7825
+ pointer-events: none;
7826
+ }
7827
+
7828
+ /* Espacio a la derecha del texto para no solaparse con la lupa. */
7829
+ .kds-search-field-wrapper .kds-search-field {
7830
+ padding-right: calc(var(--kds-spacing-1-5) + var(--kds-spacing-3));
7831
+ }
7832
+
7833
+ /* Variante angosta del field (prop `narrow` de KdsTextField): ancho reducido y texto
7834
+ centrado, para inputs de pocos caracteres dispuestos en fila (ej. segmentos de
7835
+ coordenadas o código). No crece ni se encoge dentro de un flex row. */
7836
+ .field.kds-field--narrow {
7837
+ width: 6rem;
7838
+ flex: 0 0 auto;
7839
+ /* En fila horizontal no aplica el margin vertical que BeerCSS da a fields
7840
+ hermanos (regla de "flow" `... + :is(.field,...)`, specificity ~0,3,1);
7841
+ sin el reset los siguientes quedan desalineados hacia abajo. `!important`
7842
+ para ganarle a esa regla de framework. */
7843
+ margin-block: 0 !important;
7844
+ }
7845
+
7846
+ .field.kds-field--narrow > input {
7847
+ text-align: center;
7848
+ }
7849
+
7850
+ .kds-bank-modal-search {
7851
+ padding: 0 var(--kds-spacing-2) var(--kds-spacing-1-5);
7852
+ }
7853
+
6566
7854
  .kds-bank-modal-body {
6567
7855
  flex: 1;
6568
7856
  overflow-y: auto;
@@ -6660,7 +7948,7 @@ button.kds-btn-success::after {
6660
7948
  min-width: 0;
6661
7949
  }
6662
7950
 
6663
- .kds-qr-text .title {
7951
+ .kds-qr-text .kds-qr-title {
6664
7952
  font-family: var(--kds-font-family-primary);
6665
7953
  font-weight: 600;
6666
7954
  font-size: var(--kds-font-size-sm);
@@ -6668,10 +7956,15 @@ button.kds-btn-success::after {
6668
7956
  color: var(--kds-color-text-primary);
6669
7957
  }
6670
7958
 
6671
- .kds-qr-text .sub {
7959
+ .kds-qr-text .kds-qr-subtitle {
6672
7960
  font-family: var(--kds-font-family-primary);
6673
7961
  font-size: var(--kds-font-size-caption);
6674
7962
  color: var(--kds-color-text-secondary);
7963
+ /* Trunca con ellipsis en lugar de wrap a 2 líneas — evita apretar el row
7964
+ cuando el contenedor es angosto (mobile o decorator constrained). */
7965
+ overflow: hidden;
7966
+ text-overflow: ellipsis;
7967
+ white-space: nowrap;
6675
7968
  }
6676
7969
 
6677
7970
  /* QR Badge - "Rápido" indicator */
@@ -6694,46 +7987,26 @@ button.kds-btn-success::after {
6694
7987
  font-size: 20px;
6695
7988
  }
6696
7989
 
6697
- /* Mobile responsive: Ajustes para pantallas pequeñas */
7990
+ /* Mobile responsive (≤480px): respira más mantenemos padding/gap/avatar igual
7991
+ que desktop y solo agregamos truncation al subtitle y `flex-shrink: 0` en los
7992
+ ítems que deben mantener su tamaño (avatar, badge, chevron). */
6698
7993
  @media (max-width: 480px) {
6699
- .kds-qr-row {
6700
- gap: var(--kds-spacing-1-5);
6701
- padding: var(--kds-spacing-1-5);
6702
- }
6703
-
6704
7994
  .kds-qr-avatar {
6705
- width: var(--kds-spacing-4-5);
6706
- height: var(--kds-spacing-4-5);
6707
7995
  flex-shrink: 0;
6708
7996
  }
6709
7997
 
6710
- .kds-qr-avatar .material-symbols-outlined,
6711
- .kds-qr-avatar .material-icons-round {
6712
- font-size: var(--kds-font-size-lg);
6713
- }
6714
-
6715
- .kds-qr-text .title {
6716
- font-size: var(--kds-font-size-xs);
6717
- line-height: var(--kds-line-height-tight);
6718
- }
6719
-
6720
7998
  .kds-qr-text .sub {
6721
- font-size: var(--kds-font-size-caption);
6722
- line-height: var(--kds-line-height-tight);
6723
7999
  overflow: hidden;
6724
8000
  text-overflow: ellipsis;
6725
8001
  white-space: nowrap;
6726
8002
  }
6727
8003
 
6728
8004
  .kds-qr-badge {
6729
- font-size: var(--kds-font-size-caption);
6730
- padding: var(--kds-spacing-0-25) var(--kds-spacing-0-75);
6731
8005
  flex-shrink: 0;
6732
8006
  }
6733
8007
 
6734
8008
  .kds-qr-row .material-symbols-outlined:last-child,
6735
8009
  .kds-qr-row .material-icons-round:last-child {
6736
- font-size: var(--kds-font-size-base);
6737
8010
  flex-shrink: 0;
6738
8011
  }
6739
8012
  }
@@ -6762,7 +8035,11 @@ button.kds-btn-success::after {
6762
8035
  border-radius: var(--kds-spacing-0-75);
6763
8036
  font-size: var(--kds-font-size-sm);
6764
8037
  cursor: pointer;
6765
- transition: background 0.12s ease;
8038
+ /* Transición más amplia y suave: bg + color + border ease-out */
8039
+ transition:
8040
+ background-color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
8041
+ color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
8042
+ border-top-color 280ms ease-out;
6766
8043
  position: relative;
6767
8044
  user-select: none;
6768
8045
  }
@@ -6771,19 +8048,21 @@ button.kds-btn-success::after {
6771
8048
  border-top: 0;
6772
8049
  }
6773
8050
 
6774
- .kds-copyable-table-row:hover {
8051
+ /* Hover NO aplica mientras la row esté en `.copied` o `.settling`
8052
+ (evita el flicker del hover state al desaparecer el verde de "copiado") */
8053
+ .kds-copyable-table-row:not(.copied):not(.settling):hover {
6775
8054
  background: var(--kds-color-primary-faint);
6776
8055
  }
6777
8056
 
6778
- .kds-copyable-table-row:hover + .kds-copyable-table-row {
8057
+ .kds-copyable-table-row:not(.copied):not(.settling):hover + .kds-copyable-table-row {
6779
8058
  border-top-color: transparent;
6780
8059
  }
6781
8060
 
6782
- .kds-copyable-table-row:active {
8061
+ .kds-copyable-table-row:not(.copied):not(.settling):active {
6783
8062
  background: var(--kds-color-primary-selected);
6784
8063
  }
6785
8064
 
6786
- .kds-copyable-table-row .k {
8065
+ .kds-copyable-table-row .kds-key {
6787
8066
  color: var(--kds-color-text-secondary);
6788
8067
  font-size: var(--kds-font-size-caption);
6789
8068
  letter-spacing: 0.3px;
@@ -6792,7 +8071,7 @@ button.kds-btn-success::after {
6792
8071
  flex: 0 0 auto;
6793
8072
  }
6794
8073
 
6795
- .kds-copyable-table-row .v {
8074
+ .kds-copyable-table-row .kds-value {
6796
8075
  color: var(--kds-color-text-primary);
6797
8076
  font-family: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace;
6798
8077
  font-weight: var(--kds-font-weight-medium);
@@ -6808,17 +8087,18 @@ button.kds-btn-success::after {
6808
8087
  flex: 1 1 auto;
6809
8088
  }
6810
8089
 
6811
- .kds-copyable-table-row .v::after {
8090
+ .kds-copyable-table-row .kds-value::after {
6812
8091
  content: 'content_copy';
6813
8092
  font-family: 'Material Symbols Outlined';
6814
8093
  font-size: var(--kds-font-size-sm);
6815
8094
  color: var(--kds-color-primary-main);
6816
8095
  opacity: 0;
6817
- transition: opacity 0.12s ease;
8096
+ /* Transición coordinada con la row */
8097
+ transition: opacity 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
6818
8098
  flex: 0 0 auto;
6819
8099
  }
6820
8100
 
6821
- .kds-copyable-table-row:hover .v::after {
8101
+ .kds-copyable-table-row:not(.copied):not(.settling):hover .kds-value::after {
6822
8102
  opacity: 0.7;
6823
8103
  }
6824
8104
 
@@ -6826,22 +8106,76 @@ button.kds-btn-success::after {
6826
8106
  background: var(--kds-color-success-soft);
6827
8107
  }
6828
8108
 
6829
- .kds-copyable-table-row.copied .v {
8109
+ .kds-copyable-table-row.copied .kds-value {
6830
8110
  color: var(--kds-color-success-dark);
6831
8111
  }
6832
8112
 
6833
- .kds-copyable-table-row.copied .v::after {
8113
+ .kds-copyable-table-row.copied .kds-value::after {
6834
8114
  content: 'check';
6835
8115
  font-family: 'Material Symbols Outlined';
6836
8116
  color: var(--kds-color-success-dark);
6837
8117
  opacity: 1;
6838
8118
  }
6839
8119
 
8120
+ /* `.settling`: estado de "recién copiado" — la row vuelve al normal sin
8121
+ activar hover. Dura lo mismo que la transición (~300ms) y se aplica
8122
+ desde React tras quitar `.copied`. */
8123
+ .kds-copyable-table-row.settling .kds-value::after {
8124
+ /* Mantén el check con opacity 0 mientras settling, fade out suave */
8125
+ opacity: 0;
8126
+ }
8127
+
6840
8128
  /* Disable BeerCSS ripple on copyable table rows */
6841
8129
  .kds-copyable-table-row::after {
6842
8130
  display: none;
6843
8131
  }
6844
8132
 
8133
+ /* ========================================
8134
+ GRID VARIANT (.kds-copyable-table--grid)
8135
+ Read-only grid of N text cells per row. No copy,
8136
+ no role=button, no "copy all". Cells share the row
8137
+ width equally. Used inside radio options, etc.
8138
+ ======================================== */
8139
+
8140
+ /* La grilla es solo columnas de texto (como el DataTable original): sin caja,
8141
+ borde, fondo ni sombra del contenedor copyable. */
8142
+ .kds-copyable-table--grid {
8143
+ border: 0;
8144
+ border-radius: 0;
8145
+ background: none;
8146
+ padding: 0;
8147
+ box-shadow: none;
8148
+ }
8149
+
8150
+ .kds-copyable-table-row--grid {
8151
+ display: flex;
8152
+ align-items: center;
8153
+ gap: var(--kds-spacing-1-5);
8154
+ padding: 0;
8155
+ /* Sin el divisor border-top que trae la fila base del copyable. */
8156
+ border-top: 0;
8157
+ cursor: default;
8158
+ user-select: text;
8159
+ }
8160
+
8161
+ /* Separación entre filas de la grilla (sin divisores). */
8162
+ .kds-copyable-table-row--grid + .kds-copyable-table-row--grid {
8163
+ margin-top: var(--kds-spacing-0-5);
8164
+ }
8165
+
8166
+ .kds-grid-cell {
8167
+ flex: 1 1 0;
8168
+ min-width: 0;
8169
+ font-size: var(--kds-font-size-sm);
8170
+ font-weight: var(--kds-font-weight-medium);
8171
+ color: var(--kds-color-text-primary);
8172
+ word-break: break-word;
8173
+ }
8174
+
8175
+ .kds-grid-cell--disabled {
8176
+ color: var(--kds-color-text-disabled);
8177
+ }
8178
+
6845
8179
  /* ========================================
6846
8180
  COPY-ALL BUTTON (.kds-copy-all-btn)
6847
8181
  Modifier for kds-btn kds-btn-outlined that adds
@@ -7002,7 +8336,7 @@ a.kds-copy-all-btn.copied:hover {
7002
8336
  .kds-monto-row {
7003
8337
  display: flex;
7004
8338
  justify-content: space-between;
7005
- align-items: flex-end;
8339
+ align-items: flex-start;
7006
8340
  padding: var(--kds-spacing-1-75) 0 var(--kds-spacing-1);
7007
8341
  border-top: 1px dashed var(--kds-color-divider);
7008
8342
  margin-top: var(--kds-spacing-1-75);
@@ -7026,3 +8360,252 @@ a.kds-copy-all-btn.copied:hover {
7026
8360
  color: var(--kds-color-text-primary);
7027
8361
  }
7028
8362
 
8363
+ /* ========================================
8364
+ PAYMENT TOTAL (.kds-payment-total)
8365
+ Bloque "monto a pagar" para QR view y email templates.
8366
+ Portado desde paylink-ligopay → <kh:paymentTotal> + materialize-config.css.
8367
+ Variantes:
8368
+ - default: amount grande (3rem) en color primario Khipu.
8369
+ - email: amount compacto (1.5rem) en color texto primario.
8370
+ Responsive (default): mobile (≤ 1024px) centra y oculta titleMobile.
8371
+ ======================================== */
8372
+
8373
+ .kds-payment-total {
8374
+ /* Component-scoped tokens — overrideables sin tocar el CSS global. */
8375
+ --kds-payment-total-title-size: var(--kds-font-size-2xl); /* 24px */
8376
+ --kds-payment-total-label-size: var(--kds-font-size-xl); /* 20px */
8377
+ --kds-payment-amount-size: 3rem; /* 48px — destacado */
8378
+ --kds-payment-amount-line-height: var(--kds-line-height-snug);
8379
+ --kds-payment-amount-color: var(--kds-color-primary-main);
8380
+ --kds-payment-amount-weight: var(--kds-font-weight-medium);
8381
+
8382
+ text-align: left;
8383
+ }
8384
+
8385
+ .kds-payment-total-title,
8386
+ .kds-payment-total-title-mobile {
8387
+ font-size: var(--kds-payment-total-title-size);
8388
+ font-weight: var(--kds-font-weight-semibold);
8389
+ color: var(--kds-color-text-primary);
8390
+ margin-bottom: var(--kds-spacing-4);
8391
+ }
8392
+
8393
+ .kds-payment-total-title-mobile {
8394
+ display: none;
8395
+ }
8396
+
8397
+ .kds-payment-total .kds-payment-label {
8398
+ font-size: var(--kds-payment-total-label-size);
8399
+ font-weight: var(--kds-font-weight-semibold);
8400
+ color: var(--kds-color-text-primary);
8401
+ margin-bottom: var(--kds-spacing-1);
8402
+ padding-top: 0;
8403
+ }
8404
+
8405
+ .kds-payment-total .kds-payment-amount {
8406
+ font-size: var(--kds-payment-amount-size);
8407
+ font-weight: var(--kds-payment-amount-weight);
8408
+ line-height: var(--kds-payment-amount-line-height);
8409
+ color: var(--kds-payment-amount-color);
8410
+ margin-bottom: var(--kds-spacing-4);
8411
+ }
8412
+
8413
+ .kds-payment-total .kds-payment-amount .kds-payment-total-decimal-sup,
8414
+ .kds-invoice-amount .kds-payment-total-decimal-sup {
8415
+ font-size: var(--kds-font-size-decimal-sup);
8416
+ font-weight: var(--kds-font-weight-semibold);
8417
+ position: relative;
8418
+ top: 0;
8419
+ }
8420
+
8421
+ /* Variante email: amount compacto en color texto primario, alineación izquierda fija */
8422
+ .kds-payment-total--email {
8423
+ --kds-payment-amount-size: var(--kds-font-size-2xl); /* 24px */
8424
+ --kds-payment-amount-line-height: var(--kds-line-height-snug);
8425
+ --kds-payment-amount-color: var(--kds-color-text-primary);
8426
+ --kds-payment-amount-weight: var(--kds-font-weight-semibold);
8427
+ }
8428
+
8429
+ /* Tone modifier: swaps the amount color to the khipu-blue / LigoPay info blue.
8430
+ Combinable with --email or with the default variant. */
8431
+ .kds-payment-total--tone-info {
8432
+ --kds-payment-amount-color: var(--kds-color-info-blue); /* #5A5FE0 */
8433
+ }
8434
+
8435
+ /* Centered modifier: removes the asymmetric desktop padding (which exists for
8436
+ LigoPay QR view) and centers all internal text. Composable with --email and
8437
+ --tone-info. */
8438
+ .kds-payment-total--centered {
8439
+ padding-left: 0;
8440
+ padding-top: 0;
8441
+ text-align: center;
8442
+ }
8443
+ .kds-payment-total--centered .kds-payment-total-title,
8444
+ .kds-payment-total--centered .kds-payment-total-title-mobile,
8445
+ .kds-payment-total--centered .kds-payment-label,
8446
+ .kds-payment-total--centered .kds-payment-amount {
8447
+ text-align: center;
8448
+ }
8449
+
8450
+ /* Responsive: mobile ≤ 1024px — centra y conmuta los títulos (sólo variante default) */
8451
+ @media (max-width: 1024px) {
8452
+ .kds-payment-total {
8453
+ text-align: center;
8454
+ }
8455
+
8456
+ .kds-payment-total .kds-payment-total-title {
8457
+ display: none;
8458
+ }
8459
+
8460
+ .kds-payment-total .kds-payment-total-title-mobile {
8461
+ display: block;
8462
+ text-align: center;
8463
+ }
8464
+
8465
+ .kds-payment-total .kds-payment-label,
8466
+ .kds-payment-total .kds-payment-amount {
8467
+ text-align: center;
8468
+ }
8469
+
8470
+ /* Email mantiene alineación izquierda incluso en mobile (matchea email clients) */
8471
+ .kds-payment-total--email,
8472
+ .kds-payment-total--email .kds-payment-label,
8473
+ .kds-payment-total--email .kds-payment-amount {
8474
+ text-align: left;
8475
+ }
8476
+ }
8477
+
8478
+ /* ==========================================================================
8479
+ GRID UTILITIES — semantic aliases for BeerCSS .grid / .s* / .m* / .l*
8480
+
8481
+ Estas utilidades son ALIAS de las clases cortas de BeerCSS para que
8482
+ consumers (payment, LigoPay, Grails legacy) puedan escribir markup con
8483
+ nombres descriptivos sin renunciar al grid de 12 columnas de BeerCSS.
8484
+
8485
+ Convención (estilo Bootstrap responsive):
8486
+ - kds-grid → .grid (12-col CSS grid + 1rem gap)
8487
+ - kds-col-sm-{1..12} → .s{1..12} (mobile, siempre aplica)
8488
+ - kds-col-md-{1..12} → .m{1..12} (>=601px)
8489
+ - kds-col-lg-{1..12} → .l{1..12} (>=993px)
8490
+
8491
+ Las definiciones originales de BeerCSS NO se tocan; estas son aditivas.
8492
+ ========================================================================== */
8493
+
8494
+ .kds-grid {
8495
+ --_gap: 1rem;
8496
+ display: grid;
8497
+ grid-template-columns: repeat(12, 1fr);
8498
+ gap: var(--_gap);
8499
+ block-size: auto;
8500
+ }
8501
+
8502
+ .kds-grid.kds-grid-no-space { --_gap: 0rem; }
8503
+ .kds-grid.kds-grid-medium-space { --_gap: 1.5rem; }
8504
+ .kds-grid.kds-grid-large-space { --_gap: 2rem; }
8505
+
8506
+ .kds-grid > * { margin: 0; }
8507
+
8508
+ .kds-col-sm-1 { grid-area: auto/span 1; }
8509
+ .kds-col-sm-2 { grid-area: auto/span 2; }
8510
+ .kds-col-sm-3 { grid-area: auto/span 3; }
8511
+ .kds-col-sm-4 { grid-area: auto/span 4; }
8512
+ .kds-col-sm-5 { grid-area: auto/span 5; }
8513
+ .kds-col-sm-6 { grid-area: auto/span 6; }
8514
+ .kds-col-sm-7 { grid-area: auto/span 7; }
8515
+ .kds-col-sm-8 { grid-area: auto/span 8; }
8516
+ .kds-col-sm-9 { grid-area: auto/span 9; }
8517
+ .kds-col-sm-10 { grid-area: auto/span 10; }
8518
+ .kds-col-sm-11 { grid-area: auto/span 11; }
8519
+ .kds-col-sm-12 { grid-area: auto/span 12; }
8520
+
8521
+ @media only screen and (min-width: 601px) {
8522
+ .kds-col-md-1 { grid-area: auto/span 1; }
8523
+ .kds-col-md-2 { grid-area: auto/span 2; }
8524
+ .kds-col-md-3 { grid-area: auto/span 3; }
8525
+ .kds-col-md-4 { grid-area: auto/span 4; }
8526
+ .kds-col-md-5 { grid-area: auto/span 5; }
8527
+ .kds-col-md-6 { grid-area: auto/span 6; }
8528
+ .kds-col-md-7 { grid-area: auto/span 7; }
8529
+ .kds-col-md-8 { grid-area: auto/span 8; }
8530
+ .kds-col-md-9 { grid-area: auto/span 9; }
8531
+ .kds-col-md-10 { grid-area: auto/span 10; }
8532
+ .kds-col-md-11 { grid-area: auto/span 11; }
8533
+ .kds-col-md-12 { grid-area: auto/span 12; }
8534
+ }
8535
+
8536
+ @media only screen and (min-width: 993px) {
8537
+ .kds-col-lg-1 { grid-area: auto/span 1; }
8538
+ .kds-col-lg-2 { grid-area: auto/span 2; }
8539
+ .kds-col-lg-3 { grid-area: auto/span 3; }
8540
+ .kds-col-lg-4 { grid-area: auto/span 4; }
8541
+ .kds-col-lg-5 { grid-area: auto/span 5; }
8542
+ .kds-col-lg-6 { grid-area: auto/span 6; }
8543
+ .kds-col-lg-7 { grid-area: auto/span 7; }
8544
+ .kds-col-lg-8 { grid-area: auto/span 8; }
8545
+ .kds-col-lg-9 { grid-area: auto/span 9; }
8546
+ .kds-col-lg-10 { grid-area: auto/span 10; }
8547
+ .kds-col-lg-11 { grid-area: auto/span 11; }
8548
+ .kds-col-lg-12 { grid-area: auto/span 12; }
8549
+ }
8550
+
8551
+ /* === Form icon chip ================================================== */
8552
+ /* Chip cuadrado con el icono del formulario (SecureForm, headers OIDC). */
8553
+
8554
+ .kds-form-icon-container {
8555
+ align-items: center;
8556
+ align-self: stretch;
8557
+ display: flex;
8558
+ flex-direction: column;
8559
+ gap: var(--kds-spacing-1);
8560
+ justify-content: center;
8561
+ padding: 0 var(--kds-spacing-2);
8562
+ }
8563
+
8564
+ .kds-form-icon-box {
8565
+ align-items: center;
8566
+ background: var(--kds-color-background-brand-subtle, #f0f0fa);
8567
+ border-radius: var(--kds-radius-md);
8568
+ display: flex;
8569
+ height: 52px;
8570
+ justify-content: center;
8571
+ padding: var(--kds-spacing-1);
8572
+ width: 52px;
8573
+ }
8574
+
8575
+ .kds-form-icon-box .kds-form-icon,
8576
+ .kds-form-icon-box > img,
8577
+ .kds-form-icon-box > svg {
8578
+ aspect-ratio: 1 / 1;
8579
+ flex-shrink: 0;
8580
+ height: 32px;
8581
+ width: 32px;
8582
+ }
8583
+
8584
+ @media (min-width: 600px) {
8585
+ .kds-form-icon-box {
8586
+ height: 56px;
8587
+ width: 56px;
8588
+ }
8589
+
8590
+ .kds-form-icon-box .kds-form-icon,
8591
+ .kds-form-icon-box > img,
8592
+ .kds-form-icon-box > svg {
8593
+ height: 30px;
8594
+ width: 30px;
8595
+ }
8596
+ }
8597
+
8598
+ @media (min-width: 900px) {
8599
+ .kds-form-icon-box {
8600
+ height: 60px;
8601
+ width: 60px;
8602
+ }
8603
+
8604
+ .kds-form-icon-box .kds-form-icon,
8605
+ .kds-form-icon-box > img,
8606
+ .kds-form-icon-box > svg {
8607
+ height: 32px;
8608
+ width: 32px;
8609
+ }
8610
+ }
8611
+