@khipu/design-system 0.2.0-alpha.7 → 0.2.0-alpha.71

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-15T14:22:48.149Z
14
+ * Generated: 2026-06-25T17:30:27.483Z
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;
@@ -134,6 +140,8 @@
134
140
  --kds-font-weight-bold: 700;
135
141
 
136
142
  /* Font sizes (base scale xs–4xl: see responsive section below) */
143
+ --kds-font-size-decimal-sup: 0.5em;
144
+
137
145
  /* Line heights */
138
146
  --kds-line-height-tight: 1.2;
139
147
  --kds-line-height-snug: 1.375;
@@ -846,7 +854,10 @@ a.kds-btn {
846
854
 
847
855
  /* Interaction */
848
856
  cursor: pointer;
849
- transition: background .15s, box-shadow .15s, transform .05s;
857
+ transition: background-color var(--kds-transition-shorter) var(--kds-easing-standard),
858
+ color var(--kds-transition-shorter) var(--kds-easing-standard),
859
+ box-shadow var(--kds-transition-shorter) var(--kds-easing-standard),
860
+ transform var(--kds-transition-shortest) var(--kds-easing-standard);
850
861
  box-sizing: border-box;
851
862
  vertical-align: middle;
852
863
  }
@@ -978,7 +989,7 @@ a.kds-btn-text {
978
989
 
979
990
  button.kds-btn-text:hover:not(:disabled),
980
991
  a.kds-btn-text:hover:not(:disabled) {
981
- background: var(--kds-color-primary-hover); /* rgba(131, 71, 173, 0.04) */
992
+ color: var(--kds-color-primary-dark);
982
993
  }
983
994
 
984
995
  button.kds-btn-text:disabled,
@@ -988,6 +999,30 @@ a.kds-btn-text:disabled {
988
999
  box-shadow: none;
989
1000
  }
990
1001
 
1002
+ /* Error text (destructive, ghost) — red text, no fill/border. Para acciones
1003
+ destructivas secundarias que no deben competir con el CTA primario. */
1004
+ button.kds-btn-error-text,
1005
+ a.kds-btn-error-text {
1006
+ background: transparent;
1007
+ color: var(--kds-color-error-main);
1008
+ border: none;
1009
+ padding: 6px var(--kds-spacing-2);
1010
+ min-height: 32px;
1011
+ box-shadow: none;
1012
+ }
1013
+
1014
+ button.kds-btn-error-text:hover:not(:disabled),
1015
+ a.kds-btn-error-text:hover:not(:disabled) {
1016
+ color: var(--kds-color-error-dark);
1017
+ }
1018
+
1019
+ button.kds-btn-error-text:disabled,
1020
+ a.kds-btn-error-text:disabled {
1021
+ background: transparent;
1022
+ color: var(--kds-color-action-disabled);
1023
+ box-shadow: none;
1024
+ }
1025
+
991
1026
  /* Icon wrapper - control size via span container */
992
1027
  button.kds-btn > .kds-icon,
993
1028
  a.kds-btn > .kds-icon {
@@ -1073,63 +1108,90 @@ a.kds-btn.kds-btn-md {
1073
1108
  }
1074
1109
  }
1075
1110
 
1076
- /* Selection card */
1111
+ /* Selection card.
1112
+ IMPORTANTE: este componente se renderiza como `<button>`. BeerCSS aplica al
1113
+ `button` base: `display: inline-flex; align-items: center; justify-content: center;
1114
+ block-size: 2.5rem; padding: 0 1rem; background: var(--primary); color: on-primary`.
1115
+ Todas esas reglas hay que sobreescribirlas para que el card-selector funcione como
1116
+ un contenedor flex column de altura variable y alineado a la izquierda.
1117
+
1118
+ Convención del DS: spacing entre hijos via `gap` del flex padre + padding.
1119
+ Los elementos internos (.kds-card-selector-icon/-title/-description) NO usan margin. */
1077
1120
  .kds-card-selector {
1121
+ /* Reset BeerCSS button */
1122
+ display: flex;
1123
+ flex-direction: column;
1124
+ align-items: stretch;
1125
+ justify-content: flex-start;
1126
+ block-size: auto;
1127
+ inline-size: 100%;
1128
+ text-align: left;
1129
+ line-height: 1.5;
1130
+ color: var(--kds-color-text-primary);
1131
+ /* Estilos propios del card-selector */
1078
1132
  padding: var(--kds-spacing-3);
1133
+ gap: var(--kds-spacing-1-5);
1079
1134
  border-radius: var(--kds-radius-md);
1080
- border: 2px solid var(--kds-border-light);
1135
+ border: var(--kds-border-width-md) solid var(--kds-border-light);
1081
1136
  background: var(--kds-color-background-paper);
1082
1137
  transition: all 0.3s ease;
1083
- text-align: left;
1084
1138
  cursor: pointer;
1085
- display: flex;
1086
- flex-direction: column;
1087
1139
  }
1088
1140
 
1089
- .kds-card-selector:hover {
1090
- border-color: #D1D5DB; /* gray-300 */
1141
+ .kds-card-selector:hover:not(.selected) {
1142
+ border-color: var(--kds-color-primary-light);
1143
+ background: var(--kds-color-primary-hover);
1144
+ }
1145
+
1146
+ /* Override del ripple/overlay default de BeerCSS:
1147
+ `:is(.wave,.chip,.button,button,nav.tabbed>a,...):not([class*=ripple])::after`
1148
+ tiene specificity (0,2,4) según DevTools (Chrome cuenta cada selector dentro
1149
+ de :is() individualmente para algunos motores). Usamos !important — consistente
1150
+ con cómo se overridean otros estilos de BeerCSS en este archivo (67 usos previos).
1151
+ Antes pintaba negro porque `currentColor` resolvía a text-primary del card. */
1152
+ .kds-card-selector::after {
1153
+ background-image: radial-gradient(circle, var(--kds-color-primary-main) 1%, transparent 1%) !important;
1091
1154
  }
1092
1155
 
1093
1156
  .kds-card-selector.selected {
1094
- border-color: #3B82F6; /* blue-600 */
1095
- background: #EFF6FF; /* blue-50 */
1157
+ border-color: var(--kds-color-primary-main);
1158
+ background: var(--kds-color-primary-faint);
1096
1159
  box-shadow: var(--kds-shadow-md);
1097
1160
  }
1098
1161
 
1099
- /* Icon container */
1162
+ /* Icon container — spacing manejado por gap del padre, no margin */
1100
1163
  .kds-card-selector-icon {
1101
- width: 48px;
1102
- height: 48px;
1103
- background: #DBEAFE; /* blue-100 */
1104
- border-radius: 8px;
1164
+ width: var(--kds-spacing-6);
1165
+ height: var(--kds-spacing-6);
1166
+ background: var(--kds-color-primary-focus);
1167
+ border-radius: var(--kds-radius-sm);
1105
1168
  display: flex;
1106
1169
  align-items: center;
1107
1170
  justify-content: center;
1108
- margin-bottom: 16px;
1109
1171
  }
1110
1172
 
1111
1173
  .kds-card-selector-icon i,
1112
1174
  .kds-card-selector-icon svg {
1113
- width: 24px;
1114
- height: 24px;
1115
- min-width: 24px;
1116
- min-height: 24px;
1117
- color: #3B82F6; /* blue-600 */
1175
+ width: var(--kds-spacing-3);
1176
+ height: var(--kds-spacing-3);
1177
+ min-width: var(--kds-spacing-3);
1178
+ min-height: var(--kds-spacing-3);
1179
+ font-size: var(--kds-spacing-3);
1180
+ color: var(--kds-color-primary-main);
1118
1181
  }
1119
1182
 
1120
- /* Title */
1183
+ /* Title — spacing manejado por gap del padre, no margin */
1121
1184
  .kds-card-selector-title {
1122
- font-weight: 600;
1185
+ font-weight: var(--kds-font-weight-semibold);
1123
1186
  color: var(--kds-color-text-primary);
1124
- margin-bottom: 8px;
1125
- font-size: 16px;
1187
+ font-size: var(--kds-font-size-lg);
1126
1188
  }
1127
1189
 
1128
1190
  /* Description */
1129
1191
  .kds-card-selector-description {
1130
- font-size: 14px;
1131
- color: #4B5563; /* gray-600 */
1132
- line-height: 1.5;
1192
+ font-size: var(--kds-font-size-sm);
1193
+ color: var(--kds-color-text-secondary);
1194
+ line-height: var(--kds-line-height-normal);
1133
1195
  }
1134
1196
 
1135
1197
  /* Selected state - visual feedback via border only */
@@ -1141,14 +1203,22 @@ a.kds-btn.kds-btn-md {
1141
1203
  display: flex;
1142
1204
  flex-direction: column;
1143
1205
  gap: var(--kds-spacing-2);
1144
- padding: var(--kds-spacing-4);
1206
+ padding: var(--kds-spacing-2);
1145
1207
  border-radius: var(--kds-radius-lg);
1146
1208
  border: 2px solid var(--kds-border-medium);
1147
- max-width: 400px; /* Increased from 365px for better text spacing */
1209
+ /* Ancho mínimo aplicado a TODOS los planes así un plan sin badge en una
1210
+ grilla con un plan recomendado mantiene la misma anchura, y el badge nunca
1211
+ se superpone al título por estrechez del card. */
1212
+ min-width: 260px;
1213
+ max-width: 400px;
1148
1214
  background: var(--kds-surface-base);
1149
1215
  transition: all 0.3s ease;
1150
1216
  cursor: pointer;
1151
- height: 100%; /* Ensure cards fill grid height */
1217
+ /* Alto fijo: el card se estira al alto de su row del grid (align-items stretch
1218
+ es el default) — todas las cards de la misma fila quedan a la misma altura
1219
+ sin importar el contenido. `align-self: stretch` lo hace explícito. */
1220
+ height: 100%;
1221
+ align-self: stretch;
1152
1222
  }
1153
1223
 
1154
1224
  .kds-card-plan:hover {
@@ -1168,18 +1238,19 @@ a.kds-btn.kds-btn-md {
1168
1238
  box-shadow: var(--kds-shadow-elevation-4);
1169
1239
  }
1170
1240
 
1171
- /* Recommended Badge */
1241
+ /* Recommended Badge — inline dentro del card (no flotante).
1242
+ Es el primer hijo del .kds-card-plan, así que aparece arriba de todo
1243
+ el contenido, alineado a la izquierda. */
1172
1244
  .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);
1245
+ align-self: flex-start;
1246
+ padding: var(--kds-spacing-0-5) var(--kds-spacing-1-5);
1177
1247
  background: var(--primary);
1178
1248
  color: white;
1179
- font-size: var(--kds-font-size-sm);
1249
+ font-size: var(--kds-font-size-xs);
1180
1250
  font-weight: var(--kds-font-weight-semibold);
1251
+ line-height: 1;
1181
1252
  border-radius: var(--kds-radius-full);
1182
- box-shadow: var(--kds-shadow-elevation-1);
1253
+ white-space: nowrap;
1183
1254
  }
1184
1255
 
1185
1256
  /* Plan Header */
@@ -1207,13 +1278,11 @@ a.kds-btn.kds-btn-md {
1207
1278
  display: flex;
1208
1279
  align-items: baseline;
1209
1280
  gap: var(--kds-spacing-2);
1210
- padding: var(--kds-spacing-4) 0;
1211
1281
  border-bottom: 1px solid var(--kds-border-light);
1212
- min-height: 88px; /* Standardize price area height */
1213
1282
  }
1214
1283
 
1215
1284
  .kds-price {
1216
- font-size: 42px;
1285
+ font-size: var(--kds-font-size-4xl);
1217
1286
  font-weight: var(--kds-font-weight-bold);
1218
1287
  color: var(--primary);
1219
1288
  line-height: 1.1;
@@ -1732,9 +1801,6 @@ a.kds-btn.kds-btn-md {
1732
1801
 
1733
1802
  .snackbar {
1734
1803
  position: fixed;
1735
- bottom: var(--kds-spacing-3);
1736
- left: 50%;
1737
- transform: translateX(-50%);
1738
1804
  z-index: var(--kds-z-index-snackbar);
1739
1805
  min-width: 344px;
1740
1806
  max-width: var(--kds-snackbar-max-width);
@@ -2032,6 +2098,221 @@ a.kds-btn-google:disabled {
2032
2098
  height: var(--kds-spacing-button-icon-size);
2033
2099
  }
2034
2100
 
2101
+ /* ========================================
2102
+ KDS LINEAR PROGRESS
2103
+ Native <progress> (KdsLinearProgress). Additive over BeerCSS `progress`,
2104
+ scoped to .kds-progress so other consumers are unaffected.
2105
+ ======================================== */
2106
+
2107
+ /* `progress` is inline-block by default → leaves a baseline (descender) gap
2108
+ below the bar. Block removes that gap so it sits flush with siblings. */
2109
+ .kds-progress {
2110
+ display: block;
2111
+ }
2112
+
2113
+ /* Animate the filled value when it changes (e.g. advancing a step). BeerCSS
2114
+ sets the value background but no transition, so the width jumps abruptly. */
2115
+ .kds-progress::-webkit-progress-value {
2116
+ transition: width var(--kds-transition-standard) var(--kds-easing-standard);
2117
+ }
2118
+
2119
+ .kds-progress::-moz-progress-bar {
2120
+ transition: width var(--kds-transition-standard) var(--kds-easing-standard);
2121
+ }
2122
+
2123
+ /* ========================================
2124
+ KDS SECURE LOADER
2125
+ Loader de espera: anillo circular + candado centrado + frases opcionales.
2126
+ El anillo reutiliza el spinner circular de BeerCSS, escalado.
2127
+ ======================================== */
2128
+
2129
+ .kds-secure-loader {
2130
+ display: flex;
2131
+ flex-direction: column;
2132
+ align-items: center;
2133
+ justify-content: center;
2134
+ gap: var(--kds-spacing-4);
2135
+ text-align: center;
2136
+ /* Llena y centra dentro de contenedores flex (pantalla de carga); en flujo
2137
+ normal (contenedor no-flex) se reduce a su contenido. */
2138
+ flex: 1 1 auto;
2139
+ }
2140
+
2141
+ .kds-secure-loader-text {
2142
+ display: flex;
2143
+ flex-direction: column;
2144
+ gap: var(--kds-spacing-0-25);
2145
+ }
2146
+
2147
+ .kds-secure-loader-title {
2148
+ margin: 0;
2149
+ font-family: var(--kds-font-family-primary);
2150
+ font-size: var(--kds-font-size-h6);
2151
+ font-weight: var(--kds-font-weight-semibold);
2152
+ line-height: var(--kds-line-height-snug);
2153
+ color: var(--kds-color-text-primary);
2154
+ }
2155
+
2156
+ .kds-secure-loader-message {
2157
+ margin: 0;
2158
+ font-family: var(--kds-font-family-secondary);
2159
+ font-size: var(--kds-font-size-body1);
2160
+ line-height: var(--kds-line-height-normal);
2161
+ color: var(--kds-color-primary-main);
2162
+ }
2163
+
2164
+ /* Caja del spinner con tamaño fijo: la animación no altera el layout.
2165
+ 6.25rem (100px) = tamaño del loader original (CircularProgress size=100). */
2166
+ .kds-secure-loader-spinner {
2167
+ position: relative;
2168
+ display: inline-grid;
2169
+ place-items: center;
2170
+ inline-size: var(--kds-secure-loader-size, 6.25rem);
2171
+ block-size: var(--kds-secure-loader-size, 6.25rem);
2172
+ }
2173
+
2174
+ /* Anillo: SVG nativo con arco vía stroke-dasharray, rotando. Replica el
2175
+ CircularProgress original (viewBox 44u, thickness 2, arco ~63%, disableShrink). */
2176
+ .kds-secure-loader-ring {
2177
+ inline-size: var(--kds-secure-loader-size, 6.25rem);
2178
+ block-size: var(--kds-secure-loader-size, 6.25rem);
2179
+ animation: kds-secure-loader-spin 1.2s linear infinite;
2180
+ }
2181
+
2182
+ .kds-secure-loader-ring circle {
2183
+ fill: none;
2184
+ stroke: var(--kds-color-primary-main);
2185
+ stroke-width: 2;
2186
+ stroke-linecap: round;
2187
+ /* circunferencia ≈ 2π·20.2 ≈ 127; arco visible ≈ 80 (~63%) */
2188
+ stroke-dasharray: 80 127;
2189
+ }
2190
+
2191
+ @keyframes kds-secure-loader-spin {
2192
+ to {
2193
+ transform: rotate(360deg);
2194
+ }
2195
+ }
2196
+
2197
+ /* Candado centrado sobre el anillo (~0.3 del diámetro). Centrado explícito
2198
+ (top/left 50% + translate) para que no dependa del grid ni se recorte. */
2199
+ .kds-secure-loader-lock {
2200
+ position: absolute;
2201
+ top: 50%;
2202
+ left: 50%;
2203
+ transform: translate(-50%, -50%);
2204
+ color: var(--kds-color-text-secondary);
2205
+ font-size: calc(var(--kds-secure-loader-size, 6.25rem) * 0.3);
2206
+ line-height: 1;
2207
+ pointer-events: none;
2208
+ }
2209
+
2210
+ /* ========================================
2211
+ KDS COPY BUTTON
2212
+ Chip compacto que muestra un valor + icono copy y lo copia al click.
2213
+ Acción inline (distinto de KdsCopyRow). Look del copy button de khenshin.
2214
+ ======================================== */
2215
+
2216
+ .kds-copy-button {
2217
+ display: inline-flex;
2218
+ align-items: center;
2219
+ gap: var(--kds-spacing-1);
2220
+ padding: var(--kds-spacing-0-25) var(--kds-spacing-1-5);
2221
+ /* No usar el alto de botón táctil de BeerCSS (~44px): es un chip compacto,
2222
+ su alto lo define el contenido + padding. */
2223
+ block-size: auto;
2224
+ min-block-size: 0;
2225
+ border: none;
2226
+ border-radius: var(--kds-radius-button);
2227
+ background: var(--kds-alert-info-bg);
2228
+ color: var(--kds-color-info-dark);
2229
+ font-family: var(--kds-font-family-secondary);
2230
+ font-size: var(--kds-font-size-sm);
2231
+ font-weight: var(--kds-font-weight-medium);
2232
+ line-height: var(--kds-line-height-normal);
2233
+ cursor: pointer;
2234
+ transition: background-color var(--kds-transition-shorter) var(--kds-easing-standard),
2235
+ color var(--kds-transition-shorter) var(--kds-easing-standard);
2236
+ }
2237
+
2238
+ /* active = hover: sin el aro de focus/active (outline morado de BeerCSS). */
2239
+ .kds-copy-button:focus,
2240
+ .kds-copy-button:focus-visible,
2241
+ .kds-copy-button:active {
2242
+ outline: none;
2243
+ }
2244
+
2245
+ /* value y copiedText se apilan en la MISMA celda de grid: la celda toma el
2246
+ ancho del texto más largo, por lo que el botón conserva su ancho al alternar
2247
+ entre "valor" y "copiado" (sin reflow). */
2248
+ .kds-copy-button-label {
2249
+ display: inline-grid;
2250
+ }
2251
+
2252
+ .kds-copy-button-value,
2253
+ .kds-copy-button-copied {
2254
+ grid-area: 1 / 1;
2255
+ white-space: nowrap;
2256
+ }
2257
+
2258
+ /* Estado por defecto: visible el valor, oculto (pero ocupando espacio) el copiado */
2259
+ .kds-copy-button-copied {
2260
+ visibility: hidden;
2261
+ }
2262
+
2263
+ /* Al copiar se invierte la visibilidad; el ancho no cambia */
2264
+ .kds-copy-button.copied .kds-copy-button-value {
2265
+ visibility: hidden;
2266
+ }
2267
+
2268
+ .kds-copy-button.copied .kds-copy-button-copied {
2269
+ visibility: visible;
2270
+ }
2271
+
2272
+ .kds-copy-button .material-symbols-outlined {
2273
+ font-size: 1rem;
2274
+ color: var(--kds-color-info-main);
2275
+ flex-shrink: 0;
2276
+ }
2277
+
2278
+ .kds-copy-button.copied {
2279
+ background: var(--kds-alert-success-bg);
2280
+ color: var(--kds-alert-success-text);
2281
+ animation: kds-copy-button-pulse var(--kds-transition-short) var(--kds-easing-standard);
2282
+ }
2283
+
2284
+ .kds-copy-button.copied .material-symbols-outlined {
2285
+ color: var(--kds-color-success-main);
2286
+ /* el check entra con un pop al copiar */
2287
+ animation: kds-copy-button-pop var(--kds-transition-short) var(--kds-easing-standard);
2288
+ }
2289
+
2290
+ @keyframes kds-copy-button-pulse {
2291
+ 0% {
2292
+ transform: scale(1);
2293
+ }
2294
+ 50% {
2295
+ transform: scale(1.04);
2296
+ }
2297
+ 100% {
2298
+ transform: scale(1);
2299
+ }
2300
+ }
2301
+
2302
+ @keyframes kds-copy-button-pop {
2303
+ 0% {
2304
+ transform: scale(0.3);
2305
+ opacity: 0;
2306
+ }
2307
+ 60% {
2308
+ transform: scale(1.25);
2309
+ opacity: 1;
2310
+ }
2311
+ 100% {
2312
+ transform: scale(1);
2313
+ }
2314
+ }
2315
+
2035
2316
  /* ========================================
2036
2317
  Link Styles
2037
2318
  ======================================== */
@@ -2164,6 +2445,17 @@ body.dark {
2164
2445
  transition: border-color 0.2s, box-shadow 0.2s, outline-color 0.2s;
2165
2446
  }
2166
2447
 
2448
+ /* === TEXTAREA FIX === */
2449
+ /* BeerCSS base sets minimal block padding; add breathing room for textarea */
2450
+ .field > textarea {
2451
+ padding-block: 0.75rem;
2452
+ resize: vertical;
2453
+ }
2454
+
2455
+ .field.label > textarea {
2456
+ padding-block-start: 1.5rem;
2457
+ }
2458
+
2167
2459
  /* ==========================================
2168
2460
  NOTCH VISIBILITY (opacity)
2169
2461
  ========================================== */
@@ -2285,6 +2577,23 @@ body.dark {
2285
2577
  color: var(--error); /* Rojo error */
2286
2578
  }
2287
2579
 
2580
+ /* ==========================================
2581
+ PASSWORD REVEAL TOGGLE (KdsTextField `revealable`)
2582
+ El <a role="button"> reusa el posicionamiento de icono de BeerCSS
2583
+ (.field > a, pointer-events: all). Aquí solo: color del icono
2584
+ (on-surface-variant) y un focus ring accesible para el toggle
2585
+ navegable por teclado (BeerCSS hace `outline: inherit` en <a>).
2586
+ ========================================== */
2587
+ .field > a.kds-field-reveal {
2588
+ color: var(--on-surface-variant);
2589
+ }
2590
+
2591
+ .field > a.kds-field-reveal:focus-visible {
2592
+ outline: 2px solid var(--primary);
2593
+ outline-offset: 2px;
2594
+ border-radius: 50%;
2595
+ }
2596
+
2288
2597
  /* ==========================================
2289
2598
  LABEL COLOR
2290
2599
  Mantener sincronizado con border
@@ -2392,6 +2701,71 @@ body.dark {
2392
2701
  display: inline-flex;
2393
2702
  }
2394
2703
 
2704
+ /* ========================================
2705
+ Radix Tooltip (.kds-tooltip)
2706
+ Espejo de `.tooltip` pero para popovers de Radix:
2707
+ bg oscuro, texto blanco, sombra + animación fade/slide direccional.
2708
+ ======================================== */
2709
+
2710
+ .kds-tooltip {
2711
+ background-color: var(--kds-color-text-primary);
2712
+ color: var(--kds-color-background-paper);
2713
+ font-family: var(--kds-font-family-primary);
2714
+ font-size: var(--kds-font-size-xs);
2715
+ font-weight: var(--kds-font-weight-medium);
2716
+ line-height: var(--kds-line-height-normal);
2717
+ border-radius: var(--kds-radius-sm);
2718
+ padding: var(--kds-spacing-0-75) var(--kds-spacing-1-5);
2719
+ box-shadow: var(--kds-shadow-4);
2720
+ max-width: 280px;
2721
+ z-index: var(--kds-z-index-tooltip, 1500);
2722
+ user-select: none;
2723
+ /* Animación direccional según Radix data-side — coordinada con copy-row
2724
+ (cubic-bezier 0.2, 0.8, 0.2, 1) para un feel consistente del DS. */
2725
+ animation-duration: 240ms;
2726
+ animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
2727
+ will-change: transform, opacity;
2728
+ }
2729
+
2730
+ .kds-tooltip[data-state='closed'] {
2731
+ animation-duration: 140ms;
2732
+ animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
2733
+ }
2734
+
2735
+ /* Direccional según data-side (Radix añade el attr en runtime).
2736
+ Cada lado entra desde su dirección con ~8px de offset (más visible que 4px). */
2737
+ .kds-tooltip[data-side='top'][data-state='delayed-open'],
2738
+ .kds-tooltip[data-side='top'][data-state='instant-open'] { animation-name: kds-tooltip-in-top; }
2739
+ .kds-tooltip[data-side='bottom'][data-state='delayed-open'],
2740
+ .kds-tooltip[data-side='bottom'][data-state='instant-open'] { animation-name: kds-tooltip-in-bottom; }
2741
+ .kds-tooltip[data-side='left'][data-state='delayed-open'],
2742
+ .kds-tooltip[data-side='left'][data-state='instant-open'] { animation-name: kds-tooltip-in-left; }
2743
+ .kds-tooltip[data-side='right'][data-state='delayed-open'],
2744
+ .kds-tooltip[data-side='right'][data-state='instant-open'] { animation-name: kds-tooltip-in-right; }
2745
+
2746
+ /* Fallback cuando no hay data-side resuelto aún */
2747
+ .kds-tooltip[data-state='delayed-open']:not([data-side]),
2748
+ .kds-tooltip[data-state='instant-open']:not([data-side]) {
2749
+ animation-name: kds-tooltip-in-top;
2750
+ }
2751
+
2752
+ .kds-tooltip[data-state='closed'] { animation-name: kds-tooltip-out; }
2753
+
2754
+ @keyframes kds-tooltip-in-top { from { opacity: 0; transform: translateY(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2755
+ @keyframes kds-tooltip-in-bottom { from { opacity: 0; transform: translateY(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2756
+ @keyframes kds-tooltip-in-left { from { opacity: 0; transform: translateX(8px) scale(0.96); } to { opacity: 1; transform: none; } }
2757
+ @keyframes kds-tooltip-in-right { from { opacity: 0; transform: translateX(-8px) scale(0.96); } to { opacity: 1; transform: none; } }
2758
+
2759
+ @keyframes kds-tooltip-out {
2760
+ from { opacity: 1; transform: none; }
2761
+ to { opacity: 0; transform: scale(0.96); }
2762
+ }
2763
+
2764
+ /* Arrow (SVG path generado por Radix) */
2765
+ .kds-tooltip-arrow {
2766
+ fill: var(--kds-color-text-primary);
2767
+ }
2768
+
2395
2769
  /* ========================================
2396
2770
  Material Symbols Icon Sizing
2397
2771
  ======================================== */
@@ -2426,6 +2800,16 @@ body.dark {
2426
2800
  width: 100%;
2427
2801
  }
2428
2802
 
2803
+ /* Truncado en una línea con ellipsis. Incluye min-width:0 para que funcione
2804
+ dentro de contenedores flex/grid (el ítem puede encogerse por debajo de su
2805
+ contenido). Útil para nombres/asuntos largos en headers y filas. */
2806
+ .kds-truncate {
2807
+ min-width: 0;
2808
+ overflow: hidden;
2809
+ text-overflow: ellipsis;
2810
+ white-space: nowrap;
2811
+ }
2812
+
2429
2813
  .kds-max-w-sm {
2430
2814
  max-width: 400px;
2431
2815
  }
@@ -2469,6 +2853,11 @@ body.dark {
2469
2853
  display: flex;
2470
2854
  flex-direction: column;
2471
2855
  gap: var(--kds-spacing-3);
2856
+ /* Reset del fieldset nativo: sin borde/padding/margin por defecto del navegador. */
2857
+ margin: 0;
2858
+ padding: 0;
2859
+ border: 0;
2860
+ min-inline-size: 0;
2472
2861
  }
2473
2862
 
2474
2863
  /* Checkbox Label - BeerCSS override */
@@ -2519,21 +2908,57 @@ label.radio:has(input:disabled) {
2519
2908
  }
2520
2909
 
2521
2910
  /* ========================================
2522
- ONBOARDING COMPONENTS
2523
- Multi-stage onboarding flow with form validation
2911
+ RADIO GROUP — variante card (.kds-radio-group--card)
2912
+ Cada opción como fila con borde (estilo selección de banco/cuenta),
2913
+ manteniendo el control radio. Hover + opción seleccionada resaltada.
2524
2914
  ======================================== */
2915
+ .kds-radio-group--card {
2916
+ gap: var(--kds-spacing-2);
2917
+ }
2525
2918
 
2526
- /* Stage Layout - Individual stage wrapper */
2527
- .kds-stage {
2528
- max-width: var(--kds-onboarding-max-width);
2529
- margin: 0 auto;
2530
- width: 100%;
2919
+ .kds-radio-group--card label.radio {
2920
+ gap: var(--kds-spacing-1-5);
2921
+ /* Vertical con un poco más de aire; horizontal reducido para pegar el radio a la izquierda. */
2922
+ padding: var(--kds-spacing-2) var(--kds-spacing-1-5);
2923
+ /* Bordes con los valores del bank selector. */
2924
+ border: 1px solid var(--kds-color-border-subtle);
2925
+ border-radius: var(--kds-radius-card);
2926
+ background: var(--kds-color-surface);
2927
+ transition: border-color 0.2s, background 0.2s;
2531
2928
  }
2532
2929
 
2533
- /* Stage Header - Title and subtitle */
2534
- .kds-stage-header {
2535
- display: flex;
2536
- flex-direction: column;
2930
+ /* Leve separación extra entre el radio y el texto de la opción. */
2931
+ .kds-radio-group--card label.radio span {
2932
+ margin-left: var(--kds-spacing-0-5);
2933
+ }
2934
+
2935
+ .kds-radio-group--card label.radio:hover {
2936
+ border-color: var(--kds-color-border-default);
2937
+ }
2938
+
2939
+ /* Seleccionada: poco color primario — solo un fondo faint sutil + borde gris
2940
+ (el punto del radio ya comunica la selección). */
2941
+ .kds-radio-group--card label.radio:has(input:checked) {
2942
+ border-color: var(--kds-color-border-default);
2943
+ background: var(--kds-color-primary-faint);
2944
+ }
2945
+
2946
+ /* ========================================
2947
+ ONBOARDING COMPONENTS
2948
+ Multi-stage onboarding flow with form validation
2949
+ ======================================== */
2950
+
2951
+ /* Stage Layout - Individual stage wrapper */
2952
+ .kds-stage {
2953
+ max-width: var(--kds-onboarding-max-width);
2954
+ margin: 0 auto;
2955
+ width: 100%;
2956
+ }
2957
+
2958
+ /* Stage Header - Title and subtitle */
2959
+ .kds-stage-header {
2960
+ display: flex;
2961
+ flex-direction: column;
2537
2962
  align-items: flex-start;
2538
2963
  gap: var(--kds-spacing-1);
2539
2964
  margin-bottom: var(--kds-spacing-2);
@@ -3015,7 +3440,8 @@ footer > .kds-container-center {
3015
3440
  display: flex;
3016
3441
  align-items: center;
3017
3442
  gap: var(--kds-spacing-1);
3018
- padding: var(--kds-spacing-2);
3443
+ /* Padding compacto: vertical spacing-1 (8px), horizontal spacing-2 (16px). */
3444
+ padding: var(--kds-spacing-1) var(--kds-spacing-2);
3019
3445
  border-radius: var(--kds-radius-md);
3020
3446
  border: 1px solid;
3021
3447
  font-family: var(--kds-font-family-primary);
@@ -3025,7 +3451,7 @@ footer > .kds-container-center {
3025
3451
 
3026
3452
  @media (min-width: 768px) {
3027
3453
  .kds-alert {
3028
- padding: var(--kds-spacing-2);
3454
+ padding: var(--kds-spacing-1) var(--kds-spacing-2);
3029
3455
  flex: 1 1 auto;
3030
3456
  }
3031
3457
  }
@@ -3053,7 +3479,9 @@ footer > .kds-container-center {
3053
3479
  font-size: var(--kds-font-size-sm);
3054
3480
  font-weight: var(--kds-font-weight-semibold);
3055
3481
  line-height: var(--kds-line-height-normal);
3056
- margin-bottom: var(--kds-spacing-0-5);
3482
+ /* Solo margin-bottom: el padding del alert da el espaciado. Reset del resto para
3483
+ evitar el margin-block que BeerCSS aplica a <p> dentro del scope. */
3484
+ margin: 0 0 var(--kds-spacing-0-5);
3057
3485
  word-break: normal;
3058
3486
  overflow-wrap: break-word;
3059
3487
  }
@@ -3063,6 +3491,9 @@ footer > .kds-container-center {
3063
3491
  font-size: var(--kds-font-size-sm);
3064
3492
  font-weight: var(--kds-font-weight-regular);
3065
3493
  line-height: var(--kds-line-height-relaxed);
3494
+ /* Sin margen propio: el padding del alert es el único espaciado (evita el
3495
+ margin-block de <p> de BeerCSS dentro del scope). */
3496
+ margin: 0;
3066
3497
  word-break: normal;
3067
3498
  overflow-wrap: break-word;
3068
3499
  }
@@ -3108,6 +3539,32 @@ footer > .kds-container-center {
3108
3539
  color: var(--kds-color-error-dark);
3109
3540
  }
3110
3541
 
3542
+ /* Close button — icon-only, discreto, no usa kds-btn para no romper el flex layout del alert */
3543
+ .kds-alert-close {
3544
+ flex-shrink: 0;
3545
+ display: inline-flex;
3546
+ align-items: center;
3547
+ justify-content: center;
3548
+ width: 28px;
3549
+ height: 28px;
3550
+ padding: 0;
3551
+ background: transparent;
3552
+ border: 0;
3553
+ border-radius: 50%;
3554
+ color: inherit;
3555
+ cursor: pointer;
3556
+ transition: background-color 0.15s ease;
3557
+ }
3558
+
3559
+ .kds-alert-close:hover {
3560
+ background: rgba(0, 0, 0, 0.06);
3561
+ }
3562
+
3563
+ .kds-alert-close i {
3564
+ font-size: 18px;
3565
+ line-height: 1;
3566
+ }
3567
+
3111
3568
  /* Lists inside alerts */
3112
3569
  .kds-alert ul {
3113
3570
  padding-left: var(--kds-spacing-2);
@@ -4104,6 +4561,14 @@ dialog#surveyModal button.circle {
4104
4561
  text-align: center;
4105
4562
  }
4106
4563
 
4564
+ .kds-text-left {
4565
+ text-align: left;
4566
+ }
4567
+
4568
+ .kds-text-right {
4569
+ text-align: right;
4570
+ }
4571
+
4107
4572
  .kds-text-underline {
4108
4573
  text-decoration: underline;
4109
4574
  }
@@ -4120,6 +4585,54 @@ dialog#surveyModal button.circle {
4120
4585
  font-size: var(--kds-font-size-sm);
4121
4586
  }
4122
4587
 
4588
+ /* ── Font-size scale utilities (additive — opt-in companions to .kds-text-sm) ── */
4589
+ .kds-text-base {
4590
+ font-size: var(--kds-font-size-base);
4591
+ }
4592
+
4593
+ .kds-text-lg {
4594
+ font-size: var(--kds-font-size-lg);
4595
+ }
4596
+
4597
+ .kds-text-xl {
4598
+ font-size: var(--kds-font-size-xl);
4599
+ }
4600
+
4601
+ .kds-text-2xl {
4602
+ font-size: var(--kds-font-size-2xl);
4603
+ }
4604
+
4605
+ /* ── Font-weight utilities ── */
4606
+ .kds-fw-regular {
4607
+ font-weight: var(--kds-font-weight-regular);
4608
+ }
4609
+
4610
+ .kds-fw-medium {
4611
+ font-weight: var(--kds-font-weight-medium);
4612
+ }
4613
+
4614
+ .kds-fw-semibold {
4615
+ font-weight: var(--kds-font-weight-semibold);
4616
+ }
4617
+
4618
+ .kds-fw-bold {
4619
+ font-weight: var(--kds-font-weight-bold);
4620
+ }
4621
+
4622
+ /* ── Text-transform utilities ── */
4623
+ .kds-text-transform-none {
4624
+ text-transform: none;
4625
+ }
4626
+
4627
+ /* ── Soft background utilities (semantic muted backgrounds for callouts) ── */
4628
+ .kds-bg-warning-soft {
4629
+ background-color: var(--kds-color-warning-soft);
4630
+ }
4631
+
4632
+ .kds-bg-info-soft {
4633
+ background-color: var(--kds-color-info-soft);
4634
+ }
4635
+
4123
4636
  /* ── Typography variants ── */
4124
4637
  .kds-text-display1 {
4125
4638
  font-family: var(--kds-font-family-primary, 'Public Sans', sans-serif);
@@ -4210,6 +4723,12 @@ dialog#surveyModal button.circle {
4210
4723
  color: var(--kds-color-primary-dark, #5B3179);
4211
4724
  }
4212
4725
 
4726
+ /* Inline emphasis: bold weight only, inherits size/color/family from context so it
4727
+ works as a highlighted fragment inside any other variant (body, heading, etc.). */
4728
+ .kds-text-strong {
4729
+ font-weight: var(--kds-font-weight-bold, 700);
4730
+ }
4731
+
4213
4732
  /* Display utilities */
4214
4733
  .kds-hidden {
4215
4734
  display: none;
@@ -4330,7 +4849,9 @@ dialog#surveyModal button.circle {
4330
4849
  ======================================== */
4331
4850
 
4332
4851
  .kds-badge {
4333
- display: inline-block;
4852
+ display: inline-flex;
4853
+ align-items: center;
4854
+ gap: 4px;
4334
4855
  padding: 2px 8px;
4335
4856
  border-radius: var(--kds-radius-sm);
4336
4857
  font-size: var(--kds-font-size-xs);
@@ -4338,6 +4859,40 @@ dialog#surveyModal button.circle {
4338
4859
  line-height: 1.5;
4339
4860
  }
4340
4861
 
4862
+ /* Icon prefix inside chip — small inline icon */
4863
+ .kds-badge > i.material-symbols-outlined {
4864
+ font-size: 14px;
4865
+ line-height: 1;
4866
+ }
4867
+
4868
+ /* Deletable chip close button — discreto, sin kds-btn (eso lo agrandaba ridículo) */
4869
+ .kds-badge-close {
4870
+ display: inline-flex;
4871
+ align-items: center;
4872
+ justify-content: center;
4873
+ width: 16px;
4874
+ height: 16px;
4875
+ margin-right: -2px;
4876
+ padding: 0;
4877
+ background: transparent;
4878
+ border: 0;
4879
+ border-radius: 50%;
4880
+ color: inherit;
4881
+ cursor: pointer;
4882
+ opacity: 0.7;
4883
+ transition: opacity 0.15s, background-color 0.15s;
4884
+ }
4885
+
4886
+ .kds-badge-close:hover {
4887
+ opacity: 1;
4888
+ background: rgba(0, 0, 0, 0.1);
4889
+ }
4890
+
4891
+ .kds-badge-close i {
4892
+ font-size: 14px;
4893
+ line-height: 1;
4894
+ }
4895
+
4341
4896
  .kds-badge.success {
4342
4897
  background-color: var(--kds-color-success-container);
4343
4898
  color: var(--kds-color-success-dark);
@@ -4549,16 +5104,24 @@ dialog#surveyModal button.circle {
4549
5104
  flex-shrink: 0;
4550
5105
  }
4551
5106
 
4552
- /* Merchant tile with logo variant */
5107
+ /* Merchant tile with logo variant — el logo (avatar del comercio) llena TODO el tile.
5108
+ `display: block` evita el desborde del auto-grid; `overflow: hidden` recorta la imagen
5109
+ a las esquinas redondeadas del tile. La imagen va CUADRADA (sin border-radius propio):
5110
+ solo el contenedor recorta, evitando el hairline sub-pixel del doble redondeo. El fondo
5111
+ se deja transparente bajo el logo como respaldo (no debe verse púrpura en los bordes). */
4553
5112
  .kds-merchant-tile.logo {
4554
- padding: var(--kds-spacing-0-5);
5113
+ padding: 0;
5114
+ display: block;
5115
+ overflow: hidden;
5116
+ background: transparent;
4555
5117
  }
4556
5118
 
4557
5119
  .kds-merchant-tile.logo img {
4558
5120
  width: 100%;
4559
5121
  height: 100%;
4560
5122
  object-fit: cover;
4561
- border-radius: var(--kds-radius-md);
5123
+ border-radius: 0;
5124
+ display: block;
4562
5125
  }
4563
5126
 
4564
5127
  .kds-merchant-meta {
@@ -4616,6 +5179,11 @@ dialog#surveyModal button.circle {
4616
5179
  color: var(--kds-color-text-primary);
4617
5180
  }
4618
5181
 
5182
+ /* Opt-in color modifier — switches the value to the LigoPay/khipu-blue tone */
5183
+ .kds-amount-value--info {
5184
+ color: var(--kds-color-info-blue); /* #5A5FE0 */
5185
+ }
5186
+
4619
5187
  .kds-amount-value small {
4620
5188
  font-size: 18px;
4621
5189
  font-weight: 500;
@@ -4973,7 +5541,7 @@ dialog#surveyModal button.circle {
4973
5541
  display: flex;
4974
5542
  align-items: center;
4975
5543
  justify-content: center;
4976
- gap: var(--kds-spacing-1);
5544
+ gap: var(--kds-spacing-0-5);
4977
5545
  color: var(--kds-color-gray-400);
4978
5546
  font-size: var(--kds-font-size-xs);
4979
5547
  letter-spacing: var(--kds-letter-spacing-wide);
@@ -4985,6 +5553,17 @@ dialog#surveyModal button.circle {
4985
5553
  display: none;
4986
5554
  }
4987
5555
 
5556
+ .kds-screen > form {
5557
+ margin-block-start: 0 !important;
5558
+ }
5559
+
5560
+ /* Footer externo (desktop) adyacente a la card: cancela el gap del .kds-screen
5561
+ para que quede pegado debajo de la card y no flotando lejos. Las dos cards
5562
+ (header/body) sí conservan su separación. */
5563
+ .kds-screen > .kds-secure-footer {
5564
+ margin-top: calc(-1 * var(--kds-spacing-3));
5565
+ }
5566
+
4988
5567
  @media (max-width: 767px) {
4989
5568
  .kds-card-elevated > .kds-secure-footer {
4990
5569
  display: flex;
@@ -4992,10 +5571,6 @@ dialog#surveyModal button.circle {
4992
5571
  .kds-screen > .kds-secure-footer {
4993
5572
  display: none;
4994
5573
  }
4995
-
4996
- .kds-screen > form {
4997
- margin-block-start: 0 !important;
4998
- }
4999
5574
  }
5000
5575
 
5001
5576
  .kds-secure-footer-lock {
@@ -5017,6 +5592,30 @@ dialog#surveyModal button.circle {
5017
5592
  display: block;
5018
5593
  object-fit: contain;
5019
5594
  overflow: visible;
5595
+ /* Nudge óptico: la tinta del wordmark queda ~1px alta dentro de su viewBox (45x15),
5596
+ así que al centrar por caja se ve desalineada respecto a la baseline del texto. */
5597
+ position: relative;
5598
+ top: 1px;
5599
+ }
5600
+
5601
+ /* Divisor entre el logo de Khipu y el del PSP ("Khipu | klap") */
5602
+ .kds-secure-footer-sep {
5603
+ width: 1px;
5604
+ height: 0.85em;
5605
+ background: currentColor;
5606
+ opacity: 0.35;
5607
+ flex: 0 0 auto;
5608
+ }
5609
+
5610
+ /* Logo del PSP (proveedor de pagos): lo provee el consumidor, lo alineamos al mismo
5611
+ alto que el mark de Khipu. Sirve para <img> o un elemento con .kds-psp-mark. */
5612
+ .kds-secure-footer img,
5613
+ .kds-secure-footer .kds-psp-mark {
5614
+ height: 11px;
5615
+ width: auto;
5616
+ flex: 0 0 auto;
5617
+ display: block;
5618
+ object-fit: contain;
5020
5619
  }
5021
5620
 
5022
5621
  .kds-secure-footer-code {
@@ -5038,14 +5637,20 @@ dialog#surveyModal button.circle {
5038
5637
  cursor: pointer;
5039
5638
  display: inline-flex;
5040
5639
  align-items: center;
5041
- gap: var(--kds-spacing-0-75);
5640
+ gap: 0;
5042
5641
  }
5043
5642
 
5044
- .kds-expand-toggle:hover {
5643
+ .kds-expand-toggle:hover,
5644
+ .kds-expand-toggle:focus,
5645
+ .kds-expand-toggle:active {
5045
5646
  background: transparent;
5647
+ outline: none;
5648
+ box-shadow: none;
5046
5649
  }
5047
5650
 
5048
- .kds-expand-toggle:hover span {
5651
+ .kds-expand-toggle:hover span,
5652
+ .kds-expand-toggle:focus span,
5653
+ .kds-expand-toggle:active span {
5049
5654
  text-decoration: underline;
5050
5655
  }
5051
5656
 
@@ -5188,13 +5793,17 @@ dialog#surveyModal button.circle {
5188
5793
 
5189
5794
  .kds-status-block {
5190
5795
  text-align: center;
5191
- padding: var(--kds-spacing-6) 0;
5796
+ /* Padding vertical estándar: spacing-2 (16px), el mismo rhythm inter-elementos
5797
+ que usan kds-btn-stack y kds-hr-dashed. NO usar spacing-6 (48px): genera
5798
+ demasiado espacio cuando el bloque se compone con header/divider alrededor. */
5799
+ padding: var(--kds-spacing-2) 0;
5192
5800
  }
5193
5801
 
5194
5802
  .kds-status-block-icon {
5195
5803
  width: var(--kds-status-icon-size);
5196
5804
  height: var(--kds-status-icon-size);
5197
- margin: 0 auto var(--kds-spacing-3);
5805
+ /* spacing-2 (16px) icono→título: rhythm estándar inter-elementos. */
5806
+ margin: 0 auto var(--kds-spacing-2);
5198
5807
  border-radius: var(--kds-radius-full);
5199
5808
  display: grid;
5200
5809
  place-items: center;
@@ -5225,11 +5834,11 @@ dialog#surveyModal button.circle {
5225
5834
  color: var(--kds-color-success-main);
5226
5835
  }
5227
5836
 
5228
- /* Variant: pending (animated spinner) */
5837
+ /* Variant: pending (animated blue spinner, sin icono interno) */
5229
5838
  .kds-status-block[data-status="pending"] .kds-status-block-icon {
5230
5839
  background: transparent;
5231
5840
  border: 3px solid var(--kds-color-divider);
5232
- border-top-color: var(--kds-color-primary-main);
5841
+ border-top-color: var(--kds-color-info-main);
5233
5842
  animation: kds-spin 1s linear infinite;
5234
5843
  }
5235
5844
 
@@ -5247,12 +5856,21 @@ dialog#surveyModal button.circle {
5247
5856
  color: var(--kds-color-error-main);
5248
5857
  }
5249
5858
 
5859
+ /* Variant: info — usar SIEMPRE con icon "info_i" (i minúscula sin glyph circular)
5860
+ para que solo se vea nuestro círculo decorativo. Iconos como "info" tienen
5861
+ su propio círculo built-in → causarían doble círculo. */
5862
+ .kds-status-block[data-status="info"] .kds-status-block-icon {
5863
+ background: var(--kds-color-info-soft);
5864
+ border: var(--kds-border-width-md) solid var(--kds-color-info-main);
5865
+ color: var(--kds-color-info-main);
5866
+ }
5867
+
5250
5868
  /* Inline variant: icon left + text right */
5251
5869
  .kds-status-block.inline {
5252
5870
  text-align: left;
5253
5871
  display: flex;
5254
5872
  align-items: center;
5255
- gap: var(--kds-spacing-3);
5873
+ gap: var(--kds-spacing-2);
5256
5874
  padding: var(--kds-spacing-1) 0;
5257
5875
  }
5258
5876
 
@@ -5314,6 +5932,40 @@ dialog#surveyModal button.circle {
5314
5932
  background: var(--kds-color-divider);
5315
5933
  }
5316
5934
 
5935
+ /* Close button — top-right discreto, NO usa kds-btn (rompía el flex layout) */
5936
+ .kds-bottom-sheet-close {
5937
+ position: absolute;
5938
+ top: var(--kds-spacing-1);
5939
+ right: var(--kds-spacing-1);
5940
+ width: 32px;
5941
+ height: 32px;
5942
+ display: inline-flex;
5943
+ align-items: center;
5944
+ justify-content: center;
5945
+ padding: 0;
5946
+ background: transparent;
5947
+ border: 0;
5948
+ border-radius: 50%;
5949
+ color: var(--kds-color-text-secondary);
5950
+ cursor: pointer;
5951
+ transition: background-color 0.15s ease;
5952
+ }
5953
+
5954
+ .kds-bottom-sheet-close:hover {
5955
+ background: rgba(0, 0, 0, 0.06);
5956
+ }
5957
+
5958
+ .kds-bottom-sheet-close i {
5959
+ font-size: 20px;
5960
+ line-height: 1;
5961
+ }
5962
+
5963
+ /* Body container — separa el content del title/actions */
5964
+ .kds-bottom-sheet-body {
5965
+ text-align: left;
5966
+ margin-top: var(--kds-spacing-1);
5967
+ }
5968
+
5317
5969
  .kds-bottom-sheet-icon {
5318
5970
  font-size: var(--kds-font-size-4xl);
5319
5971
  }
@@ -5641,6 +6293,22 @@ div.kds-invoice-header,
5641
6293
  padding: 0;
5642
6294
  border-radius: 0;
5643
6295
  align-content: initial;
6296
+ /* Override BeerCSS `header { min-height: ... }` — el header debe ajustarse a su
6297
+ contenido (sigue el alto del merchant tile: 64px→50px al colapsar). Sin esto
6298
+ quedaba un min-height fijo de 64px → hueco muerto debajo al colapsar en mobile. */
6299
+ min-height: 0;
6300
+ }
6301
+
6302
+ /* Mobile: center-align el header (merchant tile vs bloque monto+código) tanto
6303
+ expandido como colapsado. Al quitar el logo del header, el bloque de texto quedaba
6304
+ más bajo que el merchant tile y con `flex-start` dejaba hueco abajo; centrado los
6305
+ alinea. CSS-only (no depende de la clase .is-collapsed, que el JS de collapse no setea). */
6306
+ @media (max-width: 767px) {
6307
+ header.kds-invoice-header,
6308
+ div.kds-invoice-header,
6309
+ .kds-invoice-header {
6310
+ align-items: center;
6311
+ }
5644
6312
  }
5645
6313
 
5646
6314
  /* Reset BeerCSS sibling margin on <p> inside invoice header — specificity (0,4,1) ties BeerCSS, wins by source order */
@@ -5650,7 +6318,7 @@ div.kds-invoice-header,
5650
6318
  }
5651
6319
 
5652
6320
  .kds-invoice-amount {
5653
- font-weight: var(--kds-font-weight-bold);
6321
+ font-weight: var(--kds-font-weight-semibold);
5654
6322
  font-size: var(--kds-font-size-3xl);
5655
6323
  line-height: var(--kds-line-height-tight);
5656
6324
  letter-spacing: var(--kds-letter-spacing-wide);
@@ -5671,10 +6339,16 @@ div.kds-invoice-header,
5671
6339
  color: var(--kds-color-gray-400);
5672
6340
  text-transform: uppercase;
5673
6341
  margin: 0;
5674
- margin-top: var(--kds-spacing-1);
6342
+ margin-block: unset;
6343
+ display: flex;
6344
+ gap: var(--kds-spacing-1-5);
5675
6345
  }
5676
6346
 
5677
6347
  .kds-invoice-code-value {
6348
+ color: var(--kds-color-gray-400);
6349
+ }
6350
+
6351
+ .kds-invoice-code-value--lowercase {
5678
6352
  text-transform: lowercase;
5679
6353
  }
5680
6354
 
@@ -5687,6 +6361,9 @@ div.kds-invoice-header,
5687
6361
  place-items: center;
5688
6362
  color: #fff;
5689
6363
  flex-shrink: 0;
6364
+ /* Clip the slightly-oversized logo (see `.kds-invoice-merchant img`) to the
6365
+ rounded square so it can fully cover the deep-purple background. */
6366
+ overflow: hidden;
5690
6367
  }
5691
6368
 
5692
6369
  .kds-invoice-merchant i {
@@ -5706,15 +6383,18 @@ div.kds-invoice-header,
5706
6383
  }
5707
6384
 
5708
6385
  .kds-invoice-merchant img {
5709
- width: 100%;
5710
- height: 100%;
6386
+ /* Slightly larger than the container (+2px, centered by the grid) so the
6387
+ logo overflows under the parent's rounded clip and the deep-purple
6388
+ background never peeks through at the corners when the logo shrinks. */
6389
+ width: calc(100% + 2px);
6390
+ height: calc(100% + 2px);
5711
6391
  object-fit: cover;
5712
6392
  border-radius: var(--kds-radius-md);
5713
6393
  }
5714
6394
 
5715
6395
  /* -- Card Title -- */
5716
6396
  .kds-card-title {
5717
- font-weight: 700;
6397
+ font-weight: var(--kds-font-weight-semibold);
5718
6398
  font-size: var(--kds-font-size-base);
5719
6399
  line-height: 1.5;
5720
6400
  letter-spacing: -0.31px;
@@ -5722,12 +6402,22 @@ div.kds-invoice-header,
5722
6402
  margin-bottom: var(--kds-spacing-2) !important;
5723
6403
  }
5724
6404
 
6405
+ /* Opt-in size modifiers (additive — do NOT change default 16/600) */
6406
+ .kds-card-title--lg {
6407
+ font-size: var(--kds-font-size-xl); /* 20px */
6408
+ font-weight: var(--kds-font-weight-semibold);
6409
+ }
6410
+
6411
+ .kds-card-title--xl {
6412
+ font-size: var(--kds-font-size-2xl); /* 24px */
6413
+ font-weight: var(--kds-font-weight-semibold);
6414
+ }
6415
+
5725
6416
  /* -- Key-Value Grid -- */
5726
6417
  .kds-kv {
5727
6418
  display: grid;
5728
6419
  grid-template-columns: auto 1fr;
5729
- row-gap: var(--kds-spacing-1);
5730
- column-gap: var(--kds-spacing-1-5);
6420
+ column-gap: var(--kds-spacing-1);
5731
6421
  align-items: baseline;
5732
6422
  }
5733
6423
 
@@ -5744,7 +6434,7 @@ div.kds-invoice-header,
5744
6434
  margin: 0;
5745
6435
  font-size: var(--kds-font-size-sm);
5746
6436
  line-height: var(--kds-line-height-relaxed);
5747
- font-weight: var(--kds-font-weight-bold);
6437
+ font-weight: var(--kds-font-weight-semibold);
5748
6438
  letter-spacing: normal;
5749
6439
  color: var(--kds-color-gray-800);
5750
6440
  min-width: 0;
@@ -5772,16 +6462,24 @@ div.kds-invoice-header,
5772
6462
  .kds-detail-list {
5773
6463
  display: flex;
5774
6464
  flex-direction: column;
5775
- gap: var(--kds-spacing-1-5);
6465
+ /* spacing-2 entre grupos del detalle (separación estándar entre piezas de info
6466
+ distintas, ej. "Emisor cobro" vs "Descripción"). El padding-top da la misma
6467
+ separación spacing-2 arriba del primer grupo (Asunto↔Emisor cobro). */
6468
+ gap: var(--kds-spacing-2);
5776
6469
  margin: 0;
5777
- padding: 0 0 var(--kds-spacing-1);
6470
+ padding: var(--kds-spacing-2) 0 0;
5778
6471
  }
5779
6472
 
5780
- .kds-detail-group {
5781
- margin-bottom: var(--kds-spacing-1-5);
6473
+ @media (max-width: 767px) {
6474
+ .kds-detail-list {
6475
+ padding-bottom: var(--kds-spacing-2);
6476
+ }
5782
6477
  }
5783
6478
 
5784
- .kds-detail-group:last-child {
6479
+ .kds-detail-group {
6480
+ /* El espacio entre grupos lo da el `gap` de .kds-detail-list (spacing-1-5).
6481
+ No agregar margin-bottom acá: se sumaba al gap → doble espacio entre grupos
6482
+ (p. ej. entre "Emisor cobro" y "Descripción"). */
5785
6483
  margin-bottom: 0;
5786
6484
  }
5787
6485
 
@@ -5790,7 +6488,6 @@ div.kds-invoice-header,
5790
6488
  letter-spacing: var(--kds-letter-spacing-wide);
5791
6489
  color: var(--kds-color-text-hint);
5792
6490
  text-transform: uppercase;
5793
- margin: 0 0 var(--kds-spacing-0-5);
5794
6491
  }
5795
6492
 
5796
6493
  .kds-detail-group dd {
@@ -5859,16 +6556,16 @@ div.kds-invoice-header,
5859
6556
  font-size: var(--kds-font-size-sm);
5860
6557
  }
5861
6558
 
5862
- .kds-recap-list .k {
6559
+ .kds-recap-list .kds-key {
5863
6560
  color: var(--kds-color-text-secondary);
5864
6561
  }
5865
6562
 
5866
- .kds-recap-list .v {
6563
+ .kds-recap-list .kds-value {
5867
6564
  color: var(--kds-color-text-primary);
5868
6565
  font-weight: 500;
5869
6566
  }
5870
6567
 
5871
- .kds-recap-list .v.placeholder {
6568
+ .kds-recap-list .kds-value.placeholder {
5872
6569
  color: var(--kds-color-text-hint);
5873
6570
  }
5874
6571
 
@@ -5895,6 +6592,72 @@ a.kds-btn-success:disabled {
5895
6592
  box-shadow: none;
5896
6593
  }
5897
6594
 
6595
+ /* -- Button Warning (amber CTA) -- */
6596
+ button.kds-btn-warning,
6597
+ a.kds-btn-warning {
6598
+ background: var(--kds-color-warning-main);
6599
+ color: var(--kds-color-warning-contrast);
6600
+ border: none;
6601
+ }
6602
+
6603
+ button.kds-btn-warning:hover:not(:disabled),
6604
+ a.kds-btn-warning:hover:not(:disabled) {
6605
+ background: var(--kds-color-warning-dark);
6606
+ }
6607
+
6608
+ button.kds-btn-warning:active:not(:disabled),
6609
+ button.kds-btn-warning:focus-visible:not(:disabled),
6610
+ a.kds-btn-warning:active:not(:disabled),
6611
+ a.kds-btn-warning:focus-visible:not(:disabled) {
6612
+ background: var(--kds-color-warning-dark);
6613
+ outline: 2px solid var(--kds-color-warning-main);
6614
+ outline-offset: 2px;
6615
+ }
6616
+
6617
+ button.kds-btn-warning:disabled,
6618
+ a.kds-btn-warning:disabled {
6619
+ background-color: var(--kds-color-action-disabled-bg);
6620
+ color: var(--kds-color-action-disabled);
6621
+ box-shadow: none;
6622
+ }
6623
+
6624
+ button.kds-btn-warning::after {
6625
+ display: none;
6626
+ }
6627
+
6628
+ /* -- Button Error (red / destructive CTA) -- */
6629
+ button.kds-btn-error,
6630
+ a.kds-btn-error {
6631
+ background: var(--kds-color-error-main);
6632
+ color: var(--kds-color-error-contrast);
6633
+ border: none;
6634
+ }
6635
+
6636
+ button.kds-btn-error:hover:not(:disabled),
6637
+ a.kds-btn-error:hover:not(:disabled) {
6638
+ background: var(--kds-color-error-dark);
6639
+ }
6640
+
6641
+ button.kds-btn-error:active:not(:disabled),
6642
+ button.kds-btn-error:focus-visible:not(:disabled),
6643
+ a.kds-btn-error:active:not(:disabled),
6644
+ a.kds-btn-error:focus-visible:not(:disabled) {
6645
+ background: var(--kds-color-error-dark);
6646
+ outline: 2px solid var(--kds-color-error-main);
6647
+ outline-offset: 2px;
6648
+ }
6649
+
6650
+ button.kds-btn-error:disabled,
6651
+ a.kds-btn-error:disabled {
6652
+ background-color: var(--kds-color-action-disabled-bg);
6653
+ color: var(--kds-color-action-disabled);
6654
+ box-shadow: none;
6655
+ }
6656
+
6657
+ button.kds-btn-error::after {
6658
+ display: none;
6659
+ }
6660
+
5898
6661
  /* -- Field Helper Text -- */
5899
6662
  .kds-field-helper {
5900
6663
  font-size: var(--kds-font-size-xs);
@@ -5937,6 +6700,8 @@ button.kds-btn-success::after {
5937
6700
  /* -- Alert inline (borderless, used inside cards) -- */
5938
6701
  .kds-alert-inline {
5939
6702
  border: none;
6703
+ padding: var(--kds-spacing-1) var(--kds-spacing-1-5);
6704
+ margin-bottom: var(--kds-spacing-1-5);
5940
6705
  }
5941
6706
 
5942
6707
  /* -- Card dimmed (behind overlays) -- */
@@ -6038,17 +6803,42 @@ button.kds-btn-success::after {
6038
6803
  }
6039
6804
 
6040
6805
  .kds-bill-description-picture {
6041
- width: 120px;
6042
- height: 120px;
6806
+ max-width: 100px;
6043
6807
  object-fit: contain;
6044
6808
  background: var(--kds-color-background-paper);
6045
- padding: var(--kds-spacing-1-25);
6046
- border-radius: var(--kds-radius-md);
6047
- margin-top: var(--kds-spacing-1);
6809
+ margin-top: var(--kds-spacing-1-25);
6048
6810
  display: block;
6049
6811
  box-sizing: content-box;
6050
6812
  }
6051
6813
 
6814
+ /* -- Bill Attachments -- */
6815
+ .kds-bill-attachments {
6816
+ display: flex;
6817
+ flex-direction: column;
6818
+ gap: var(--kds-spacing-0-75);
6819
+ }
6820
+
6821
+ .kds-bill-attachment {
6822
+ display: inline-flex;
6823
+ align-items: center;
6824
+ justify-content: flex-start;
6825
+ width: fit-content;
6826
+ color: var(--kds-color-info-main);
6827
+ font-size: var(--kds-font-size-sm);
6828
+ font-weight: var(--kds-font-weight-medium);
6829
+ text-decoration: none;
6830
+ }
6831
+
6832
+ .kds-bill-attachment:hover span {
6833
+ text-decoration: underline;
6834
+ }
6835
+
6836
+ .kds-bill-attachment i {
6837
+ font-size: var(--kds-font-size-lg);
6838
+ min-width: unset;
6839
+ justify-content: flex-start;
6840
+ }
6841
+
6052
6842
  /* -- Share Card (mustContinue) -- */
6053
6843
  .kds-share-card {
6054
6844
  margin-top: var(--kds-spacing-2);
@@ -6174,12 +6964,15 @@ button.kds-btn-success::after {
6174
6964
  padding-bottom: 0;
6175
6965
  }
6176
6966
 
6177
- /* Payment stage — full-viewport centered wrapper */
6967
+ /* Payment stage — full-viewport centered wrapper.
6968
+ Fondo muted (gris) para que las cards blancas (header + body) y el gap entre
6969
+ ellas se distingan; sin esto, card blanca sobre fondo blanco se funden. */
6178
6970
  .kds-payment-stage {
6179
6971
  min-height: 100vh;
6180
6972
  display: flex;
6181
6973
  justify-content: center;
6182
6974
  padding: var(--kds-spacing-2-5) var(--kds-spacing-2) var(--kds-spacing-8);
6975
+ background: var(--kds-color-background-muted);
6183
6976
  }
6184
6977
 
6185
6978
  /* Payment flow — narrow column */
@@ -6218,10 +7011,17 @@ button.kds-btn-success::after {
6218
7011
  padding-bottom: var(--kds-spacing-2);
6219
7012
  }
6220
7013
 
6221
- /* Invoice sticky card: progressive padding-top (expanded 20px → collapsed 8px).
6222
- Overrides base rule at same specificity; source order wins here. */
7014
+ /* Invoice sticky card padding (mobile).
7015
+ Top: estático 12px. Bottom: progresivo 20px (expandido) 8px (colapsado).
7016
+ El padding-bottom animado da breathing room natural cuando expandido y se
7017
+ reduce convencionalmente al colapsar — sin depender de que el clip-path
7018
+ corte el padding abruptamente. */
6223
7019
  .kds-payment-flow .kds-card-elevated.kds-invoice-sticky {
6224
7020
  padding-top: var(--kds-spacing-1-5);
7021
+ padding-bottom: calc(
7022
+ var(--kds-spacing-2-5)
7023
+ - var(--kds-spacing-1-5) * var(--collapse-progress, 0)
7024
+ );
6225
7025
  }
6226
7026
 
6227
7027
 
@@ -6480,7 +7280,7 @@ button.kds-btn-success::after {
6480
7280
  inset: 0;
6481
7281
  background: var(--kds-modal-backdrop);
6482
7282
  display: none;
6483
- align-items: center;
7283
+ align-items: flex-start;
6484
7284
  justify-content: center;
6485
7285
  z-index: var(--kds-z-index-modal, 50);
6486
7286
  animation: kds-fade 0.2s ease both;
@@ -6508,7 +7308,7 @@ button.kds-btn-success::after {
6508
7308
  display: flex;
6509
7309
  align-items: center;
6510
7310
  justify-content: space-between;
6511
- padding: var(--kds-spacing-2) var(--kds-spacing-2) var(--kds-spacing-1);
7311
+ padding: var(--kds-spacing-1) var(--kds-spacing-2) var(--kds-spacing-1);
6512
7312
  }
6513
7313
 
6514
7314
  .kds-bank-modal-header h3 {
@@ -6533,11 +7333,8 @@ button.kds-btn-success::after {
6533
7333
  display: none;
6534
7334
  }
6535
7335
 
6536
- .kds-bank-modal-search {
6537
- padding: 0 var(--kds-spacing-2) var(--kds-spacing-1-5);
6538
- }
6539
-
6540
- .kds-bank-modal-search input {
7336
+ /* Search field reutilizable (standalone o dentro del KdsBankModal). */
7337
+ .kds-search-field {
6541
7338
  width: 100%;
6542
7339
  padding: var(--kds-spacing-1-25) var(--kds-spacing-1-5);
6543
7340
  border: 1px solid var(--kds-color-divider);
@@ -6549,15 +7346,57 @@ button.kds-btn-success::after {
6549
7346
  background: var(--kds-color-surface);
6550
7347
  }
6551
7348
 
6552
- .kds-bank-modal-search input::placeholder {
7349
+ .kds-search-field::placeholder {
6553
7350
  color: var(--kds-color-text-hint);
6554
7351
  }
6555
7352
 
6556
- .kds-bank-modal-search input:focus {
7353
+ .kds-search-field:focus {
6557
7354
  border-color: var(--kds-color-primary-main);
6558
7355
  box-shadow: 0 0 0 2px var(--kds-color-primary-faint);
6559
7356
  }
6560
7357
 
7358
+ /* Variante con ícono (withIcon): lupa posicionada DENTRO del input, a la derecha. */
7359
+ .kds-search-field-wrapper {
7360
+ position: relative;
7361
+ width: 100%;
7362
+ }
7363
+
7364
+ .kds-search-field-icon {
7365
+ position: absolute;
7366
+ right: var(--kds-spacing-1-5);
7367
+ top: 50%;
7368
+ transform: translateY(-50%);
7369
+ font-size: 20px;
7370
+ color: var(--kds-color-text-hint);
7371
+ pointer-events: none;
7372
+ }
7373
+
7374
+ /* Espacio a la derecha del texto para no solaparse con la lupa. */
7375
+ .kds-search-field-wrapper .kds-search-field {
7376
+ padding-right: calc(var(--kds-spacing-1-5) + var(--kds-spacing-3));
7377
+ }
7378
+
7379
+ /* Variante angosta del field (prop `narrow` de KdsTextField): ancho reducido y texto
7380
+ centrado, para inputs de pocos caracteres dispuestos en fila (ej. segmentos de
7381
+ coordenadas o código). No crece ni se encoge dentro de un flex row. */
7382
+ .field.kds-field--narrow {
7383
+ width: 6rem;
7384
+ flex: 0 0 auto;
7385
+ /* En fila horizontal no aplica el margin vertical que BeerCSS da a fields
7386
+ hermanos (regla de "flow" `... + :is(.field,...)`, specificity ~0,3,1);
7387
+ sin el reset los siguientes quedan desalineados hacia abajo. `!important`
7388
+ para ganarle a esa regla de framework. */
7389
+ margin-block: 0 !important;
7390
+ }
7391
+
7392
+ .field.kds-field--narrow > input {
7393
+ text-align: center;
7394
+ }
7395
+
7396
+ .kds-bank-modal-search {
7397
+ padding: 0 var(--kds-spacing-2) var(--kds-spacing-1-5);
7398
+ }
7399
+
6561
7400
  .kds-bank-modal-body {
6562
7401
  flex: 1;
6563
7402
  overflow-y: auto;
@@ -6655,7 +7494,7 @@ button.kds-btn-success::after {
6655
7494
  min-width: 0;
6656
7495
  }
6657
7496
 
6658
- .kds-qr-text .title {
7497
+ .kds-qr-text .kds-qr-title {
6659
7498
  font-family: var(--kds-font-family-primary);
6660
7499
  font-weight: 600;
6661
7500
  font-size: var(--kds-font-size-sm);
@@ -6663,10 +7502,15 @@ button.kds-btn-success::after {
6663
7502
  color: var(--kds-color-text-primary);
6664
7503
  }
6665
7504
 
6666
- .kds-qr-text .sub {
7505
+ .kds-qr-text .kds-qr-subtitle {
6667
7506
  font-family: var(--kds-font-family-primary);
6668
7507
  font-size: var(--kds-font-size-caption);
6669
7508
  color: var(--kds-color-text-secondary);
7509
+ /* Trunca con ellipsis en lugar de wrap a 2 líneas — evita apretar el row
7510
+ cuando el contenedor es angosto (mobile o decorator constrained). */
7511
+ overflow: hidden;
7512
+ text-overflow: ellipsis;
7513
+ white-space: nowrap;
6670
7514
  }
6671
7515
 
6672
7516
  /* QR Badge - "Rápido" indicator */
@@ -6689,46 +7533,26 @@ button.kds-btn-success::after {
6689
7533
  font-size: 20px;
6690
7534
  }
6691
7535
 
6692
- /* Mobile responsive: Ajustes para pantallas pequeñas */
7536
+ /* Mobile responsive (≤480px): respira más mantenemos padding/gap/avatar igual
7537
+ que desktop y solo agregamos truncation al subtitle y `flex-shrink: 0` en los
7538
+ ítems que deben mantener su tamaño (avatar, badge, chevron). */
6693
7539
  @media (max-width: 480px) {
6694
- .kds-qr-row {
6695
- gap: var(--kds-spacing-1-5);
6696
- padding: var(--kds-spacing-1-5);
6697
- }
6698
-
6699
7540
  .kds-qr-avatar {
6700
- width: var(--kds-spacing-4-5);
6701
- height: var(--kds-spacing-4-5);
6702
7541
  flex-shrink: 0;
6703
7542
  }
6704
7543
 
6705
- .kds-qr-avatar .material-symbols-outlined,
6706
- .kds-qr-avatar .material-icons-round {
6707
- font-size: var(--kds-font-size-lg);
6708
- }
6709
-
6710
- .kds-qr-text .title {
6711
- font-size: var(--kds-font-size-xs);
6712
- line-height: var(--kds-line-height-tight);
6713
- }
6714
-
6715
7544
  .kds-qr-text .sub {
6716
- font-size: var(--kds-font-size-caption);
6717
- line-height: var(--kds-line-height-tight);
6718
7545
  overflow: hidden;
6719
7546
  text-overflow: ellipsis;
6720
7547
  white-space: nowrap;
6721
7548
  }
6722
7549
 
6723
7550
  .kds-qr-badge {
6724
- font-size: var(--kds-font-size-caption);
6725
- padding: var(--kds-spacing-0-25) var(--kds-spacing-0-75);
6726
7551
  flex-shrink: 0;
6727
7552
  }
6728
7553
 
6729
7554
  .kds-qr-row .material-symbols-outlined:last-child,
6730
7555
  .kds-qr-row .material-icons-round:last-child {
6731
- font-size: var(--kds-font-size-base);
6732
7556
  flex-shrink: 0;
6733
7557
  }
6734
7558
  }
@@ -6757,7 +7581,11 @@ button.kds-btn-success::after {
6757
7581
  border-radius: var(--kds-spacing-0-75);
6758
7582
  font-size: var(--kds-font-size-sm);
6759
7583
  cursor: pointer;
6760
- transition: background 0.12s ease;
7584
+ /* Transición más amplia y suave: bg + color + border ease-out */
7585
+ transition:
7586
+ background-color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
7587
+ color 280ms cubic-bezier(0.2, 0.8, 0.2, 1),
7588
+ border-top-color 280ms ease-out;
6761
7589
  position: relative;
6762
7590
  user-select: none;
6763
7591
  }
@@ -6766,19 +7594,21 @@ button.kds-btn-success::after {
6766
7594
  border-top: 0;
6767
7595
  }
6768
7596
 
6769
- .kds-copyable-table-row:hover {
7597
+ /* Hover NO aplica mientras la row esté en `.copied` o `.settling`
7598
+ (evita el flicker del hover state al desaparecer el verde de "copiado") */
7599
+ .kds-copyable-table-row:not(.copied):not(.settling):hover {
6770
7600
  background: var(--kds-color-primary-faint);
6771
7601
  }
6772
7602
 
6773
- .kds-copyable-table-row:hover + .kds-copyable-table-row {
7603
+ .kds-copyable-table-row:not(.copied):not(.settling):hover + .kds-copyable-table-row {
6774
7604
  border-top-color: transparent;
6775
7605
  }
6776
7606
 
6777
- .kds-copyable-table-row:active {
7607
+ .kds-copyable-table-row:not(.copied):not(.settling):active {
6778
7608
  background: var(--kds-color-primary-selected);
6779
7609
  }
6780
7610
 
6781
- .kds-copyable-table-row .k {
7611
+ .kds-copyable-table-row .kds-key {
6782
7612
  color: var(--kds-color-text-secondary);
6783
7613
  font-size: var(--kds-font-size-caption);
6784
7614
  letter-spacing: 0.3px;
@@ -6787,7 +7617,7 @@ button.kds-btn-success::after {
6787
7617
  flex: 0 0 auto;
6788
7618
  }
6789
7619
 
6790
- .kds-copyable-table-row .v {
7620
+ .kds-copyable-table-row .kds-value {
6791
7621
  color: var(--kds-color-text-primary);
6792
7622
  font-family: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace;
6793
7623
  font-weight: var(--kds-font-weight-medium);
@@ -6803,17 +7633,18 @@ button.kds-btn-success::after {
6803
7633
  flex: 1 1 auto;
6804
7634
  }
6805
7635
 
6806
- .kds-copyable-table-row .v::after {
7636
+ .kds-copyable-table-row .kds-value::after {
6807
7637
  content: 'content_copy';
6808
7638
  font-family: 'Material Symbols Outlined';
6809
7639
  font-size: var(--kds-font-size-sm);
6810
7640
  color: var(--kds-color-primary-main);
6811
7641
  opacity: 0;
6812
- transition: opacity 0.12s ease;
7642
+ /* Transición coordinada con la row */
7643
+ transition: opacity 280ms cubic-bezier(0.2, 0.8, 0.2, 1);
6813
7644
  flex: 0 0 auto;
6814
7645
  }
6815
7646
 
6816
- .kds-copyable-table-row:hover .v::after {
7647
+ .kds-copyable-table-row:not(.copied):not(.settling):hover .kds-value::after {
6817
7648
  opacity: 0.7;
6818
7649
  }
6819
7650
 
@@ -6821,22 +7652,76 @@ button.kds-btn-success::after {
6821
7652
  background: var(--kds-color-success-soft);
6822
7653
  }
6823
7654
 
6824
- .kds-copyable-table-row.copied .v {
7655
+ .kds-copyable-table-row.copied .kds-value {
6825
7656
  color: var(--kds-color-success-dark);
6826
7657
  }
6827
7658
 
6828
- .kds-copyable-table-row.copied .v::after {
7659
+ .kds-copyable-table-row.copied .kds-value::after {
6829
7660
  content: 'check';
6830
7661
  font-family: 'Material Symbols Outlined';
6831
7662
  color: var(--kds-color-success-dark);
6832
7663
  opacity: 1;
6833
7664
  }
6834
7665
 
7666
+ /* `.settling`: estado de "recién copiado" — la row vuelve al normal sin
7667
+ activar hover. Dura lo mismo que la transición (~300ms) y se aplica
7668
+ desde React tras quitar `.copied`. */
7669
+ .kds-copyable-table-row.settling .kds-value::after {
7670
+ /* Mantén el check con opacity 0 mientras settling, fade out suave */
7671
+ opacity: 0;
7672
+ }
7673
+
6835
7674
  /* Disable BeerCSS ripple on copyable table rows */
6836
7675
  .kds-copyable-table-row::after {
6837
7676
  display: none;
6838
7677
  }
6839
7678
 
7679
+ /* ========================================
7680
+ GRID VARIANT (.kds-copyable-table--grid)
7681
+ Read-only grid of N text cells per row. No copy,
7682
+ no role=button, no "copy all". Cells share the row
7683
+ width equally. Used inside radio options, etc.
7684
+ ======================================== */
7685
+
7686
+ /* La grilla es solo columnas de texto (como el DataTable original): sin caja,
7687
+ borde, fondo ni sombra del contenedor copyable. */
7688
+ .kds-copyable-table--grid {
7689
+ border: 0;
7690
+ border-radius: 0;
7691
+ background: none;
7692
+ padding: 0;
7693
+ box-shadow: none;
7694
+ }
7695
+
7696
+ .kds-copyable-table-row--grid {
7697
+ display: flex;
7698
+ align-items: center;
7699
+ gap: var(--kds-spacing-1-5);
7700
+ padding: 0;
7701
+ /* Sin el divisor border-top que trae la fila base del copyable. */
7702
+ border-top: 0;
7703
+ cursor: default;
7704
+ user-select: text;
7705
+ }
7706
+
7707
+ /* Separación entre filas de la grilla (sin divisores). */
7708
+ .kds-copyable-table-row--grid + .kds-copyable-table-row--grid {
7709
+ margin-top: var(--kds-spacing-0-5);
7710
+ }
7711
+
7712
+ .kds-grid-cell {
7713
+ flex: 1 1 0;
7714
+ min-width: 0;
7715
+ font-size: var(--kds-font-size-sm);
7716
+ font-weight: var(--kds-font-weight-medium);
7717
+ color: var(--kds-color-text-primary);
7718
+ word-break: break-word;
7719
+ }
7720
+
7721
+ .kds-grid-cell--disabled {
7722
+ color: var(--kds-color-text-disabled);
7723
+ }
7724
+
6840
7725
  /* ========================================
6841
7726
  COPY-ALL BUTTON (.kds-copy-all-btn)
6842
7727
  Modifier for kds-btn kds-btn-outlined that adds
@@ -6894,6 +7779,14 @@ a.kds-copy-all-btn.copied:hover {
6894
7779
  min-height: unset;
6895
7780
  }
6896
7781
 
7782
+ /* Severity variants — default stays warning (backward-compatible) */
7783
+ .kds-section-note.kds-info { color: var(--kds-color-info-dark); }
7784
+ .kds-section-note.kds-info > i { color: var(--kds-color-info-dark); }
7785
+ .kds-section-note.kds-success { color: var(--kds-color-success-dark); }
7786
+ .kds-section-note.kds-success > i { color: var(--kds-color-success-dark); }
7787
+ .kds-section-note.kds-error { color: var(--kds-color-error-dark); }
7788
+ .kds-section-note.kds-error > i { color: var(--kds-color-error-dark); }
7789
+
6897
7790
  /* ========================================
6898
7791
  INFO TOOLTIP (.kds-info-tip)
6899
7792
  Inline info button with hover/click tooltip bubble.
@@ -6989,7 +7882,7 @@ a.kds-copy-all-btn.copied:hover {
6989
7882
  .kds-monto-row {
6990
7883
  display: flex;
6991
7884
  justify-content: space-between;
6992
- align-items: flex-end;
7885
+ align-items: flex-start;
6993
7886
  padding: var(--kds-spacing-1-75) 0 var(--kds-spacing-1);
6994
7887
  border-top: 1px dashed var(--kds-color-divider);
6995
7888
  margin-top: var(--kds-spacing-1-75);
@@ -7013,3 +7906,191 @@ a.kds-copy-all-btn.copied:hover {
7013
7906
  color: var(--kds-color-text-primary);
7014
7907
  }
7015
7908
 
7909
+ /* ========================================
7910
+ PAYMENT TOTAL (.kds-payment-total)
7911
+ Bloque "monto a pagar" para QR view y email templates.
7912
+ Portado desde paylink-ligopay → <kh:paymentTotal> + materialize-config.css.
7913
+ Variantes:
7914
+ - default: amount grande (3rem) en color primario Khipu.
7915
+ - email: amount compacto (1.5rem) en color texto primario.
7916
+ Responsive (default): mobile (≤ 1024px) centra y oculta titleMobile.
7917
+ ======================================== */
7918
+
7919
+ .kds-payment-total {
7920
+ /* Component-scoped tokens — overrideables sin tocar el CSS global. */
7921
+ --kds-payment-total-title-size: var(--kds-font-size-2xl); /* 24px */
7922
+ --kds-payment-total-label-size: var(--kds-font-size-xl); /* 20px */
7923
+ --kds-payment-amount-size: 3rem; /* 48px — destacado */
7924
+ --kds-payment-amount-line-height: var(--kds-line-height-snug);
7925
+ --kds-payment-amount-color: var(--kds-color-primary-main);
7926
+ --kds-payment-amount-weight: var(--kds-font-weight-medium);
7927
+
7928
+ text-align: left;
7929
+ }
7930
+
7931
+ .kds-payment-total-title,
7932
+ .kds-payment-total-title-mobile {
7933
+ font-size: var(--kds-payment-total-title-size);
7934
+ font-weight: var(--kds-font-weight-semibold);
7935
+ color: var(--kds-color-text-primary);
7936
+ margin-bottom: var(--kds-spacing-4);
7937
+ }
7938
+
7939
+ .kds-payment-total-title-mobile {
7940
+ display: none;
7941
+ }
7942
+
7943
+ .kds-payment-total .kds-payment-label {
7944
+ font-size: var(--kds-payment-total-label-size);
7945
+ font-weight: var(--kds-font-weight-semibold);
7946
+ color: var(--kds-color-text-primary);
7947
+ margin-bottom: var(--kds-spacing-1);
7948
+ padding-top: 0;
7949
+ }
7950
+
7951
+ .kds-payment-total .kds-payment-amount {
7952
+ font-size: var(--kds-payment-amount-size);
7953
+ font-weight: var(--kds-payment-amount-weight);
7954
+ line-height: var(--kds-payment-amount-line-height);
7955
+ color: var(--kds-payment-amount-color);
7956
+ margin-bottom: var(--kds-spacing-4);
7957
+ }
7958
+
7959
+ .kds-payment-total .kds-payment-amount .kds-payment-total-decimal-sup,
7960
+ .kds-invoice-amount .kds-payment-total-decimal-sup {
7961
+ font-size: var(--kds-font-size-decimal-sup);
7962
+ font-weight: var(--kds-font-weight-semibold);
7963
+ position: relative;
7964
+ top: 0;
7965
+ }
7966
+
7967
+ /* Variante email: amount compacto en color texto primario, alineación izquierda fija */
7968
+ .kds-payment-total--email {
7969
+ --kds-payment-amount-size: var(--kds-font-size-2xl); /* 24px */
7970
+ --kds-payment-amount-line-height: var(--kds-line-height-snug);
7971
+ --kds-payment-amount-color: var(--kds-color-text-primary);
7972
+ --kds-payment-amount-weight: var(--kds-font-weight-semibold);
7973
+ }
7974
+
7975
+ /* Tone modifier: swaps the amount color to the khipu-blue / LigoPay info blue.
7976
+ Combinable with --email or with the default variant. */
7977
+ .kds-payment-total--tone-info {
7978
+ --kds-payment-amount-color: var(--kds-color-info-blue); /* #5A5FE0 */
7979
+ }
7980
+
7981
+ /* Centered modifier: removes the asymmetric desktop padding (which exists for
7982
+ LigoPay QR view) and centers all internal text. Composable with --email and
7983
+ --tone-info. */
7984
+ .kds-payment-total--centered {
7985
+ padding-left: 0;
7986
+ padding-top: 0;
7987
+ text-align: center;
7988
+ }
7989
+ .kds-payment-total--centered .kds-payment-total-title,
7990
+ .kds-payment-total--centered .kds-payment-total-title-mobile,
7991
+ .kds-payment-total--centered .kds-payment-label,
7992
+ .kds-payment-total--centered .kds-payment-amount {
7993
+ text-align: center;
7994
+ }
7995
+
7996
+ /* Responsive: mobile ≤ 1024px — centra y conmuta los títulos (sólo variante default) */
7997
+ @media (max-width: 1024px) {
7998
+ .kds-payment-total {
7999
+ text-align: center;
8000
+ }
8001
+
8002
+ .kds-payment-total .kds-payment-total-title {
8003
+ display: none;
8004
+ }
8005
+
8006
+ .kds-payment-total .kds-payment-total-title-mobile {
8007
+ display: block;
8008
+ text-align: center;
8009
+ }
8010
+
8011
+ .kds-payment-total .kds-payment-label,
8012
+ .kds-payment-total .kds-payment-amount {
8013
+ text-align: center;
8014
+ }
8015
+
8016
+ /* Email mantiene alineación izquierda incluso en mobile (matchea email clients) */
8017
+ .kds-payment-total--email,
8018
+ .kds-payment-total--email .kds-payment-label,
8019
+ .kds-payment-total--email .kds-payment-amount {
8020
+ text-align: left;
8021
+ }
8022
+ }
8023
+
8024
+ /* ==========================================================================
8025
+ GRID UTILITIES — semantic aliases for BeerCSS .grid / .s* / .m* / .l*
8026
+
8027
+ Estas utilidades son ALIAS de las clases cortas de BeerCSS para que
8028
+ consumers (payment, LigoPay, Grails legacy) puedan escribir markup con
8029
+ nombres descriptivos sin renunciar al grid de 12 columnas de BeerCSS.
8030
+
8031
+ Convención (estilo Bootstrap responsive):
8032
+ - kds-grid → .grid (12-col CSS grid + 1rem gap)
8033
+ - kds-col-sm-{1..12} → .s{1..12} (mobile, siempre aplica)
8034
+ - kds-col-md-{1..12} → .m{1..12} (>=601px)
8035
+ - kds-col-lg-{1..12} → .l{1..12} (>=993px)
8036
+
8037
+ Las definiciones originales de BeerCSS NO se tocan; estas son aditivas.
8038
+ ========================================================================== */
8039
+
8040
+ .kds-grid {
8041
+ --_gap: 1rem;
8042
+ display: grid;
8043
+ grid-template-columns: repeat(12, 1fr);
8044
+ gap: var(--_gap);
8045
+ block-size: auto;
8046
+ }
8047
+
8048
+ .kds-grid.kds-grid-no-space { --_gap: 0rem; }
8049
+ .kds-grid.kds-grid-medium-space { --_gap: 1.5rem; }
8050
+ .kds-grid.kds-grid-large-space { --_gap: 2rem; }
8051
+
8052
+ .kds-grid > * { margin: 0; }
8053
+
8054
+ .kds-col-sm-1 { grid-area: auto/span 1; }
8055
+ .kds-col-sm-2 { grid-area: auto/span 2; }
8056
+ .kds-col-sm-3 { grid-area: auto/span 3; }
8057
+ .kds-col-sm-4 { grid-area: auto/span 4; }
8058
+ .kds-col-sm-5 { grid-area: auto/span 5; }
8059
+ .kds-col-sm-6 { grid-area: auto/span 6; }
8060
+ .kds-col-sm-7 { grid-area: auto/span 7; }
8061
+ .kds-col-sm-8 { grid-area: auto/span 8; }
8062
+ .kds-col-sm-9 { grid-area: auto/span 9; }
8063
+ .kds-col-sm-10 { grid-area: auto/span 10; }
8064
+ .kds-col-sm-11 { grid-area: auto/span 11; }
8065
+ .kds-col-sm-12 { grid-area: auto/span 12; }
8066
+
8067
+ @media only screen and (min-width: 601px) {
8068
+ .kds-col-md-1 { grid-area: auto/span 1; }
8069
+ .kds-col-md-2 { grid-area: auto/span 2; }
8070
+ .kds-col-md-3 { grid-area: auto/span 3; }
8071
+ .kds-col-md-4 { grid-area: auto/span 4; }
8072
+ .kds-col-md-5 { grid-area: auto/span 5; }
8073
+ .kds-col-md-6 { grid-area: auto/span 6; }
8074
+ .kds-col-md-7 { grid-area: auto/span 7; }
8075
+ .kds-col-md-8 { grid-area: auto/span 8; }
8076
+ .kds-col-md-9 { grid-area: auto/span 9; }
8077
+ .kds-col-md-10 { grid-area: auto/span 10; }
8078
+ .kds-col-md-11 { grid-area: auto/span 11; }
8079
+ .kds-col-md-12 { grid-area: auto/span 12; }
8080
+ }
8081
+
8082
+ @media only screen and (min-width: 993px) {
8083
+ .kds-col-lg-1 { grid-area: auto/span 1; }
8084
+ .kds-col-lg-2 { grid-area: auto/span 2; }
8085
+ .kds-col-lg-3 { grid-area: auto/span 3; }
8086
+ .kds-col-lg-4 { grid-area: auto/span 4; }
8087
+ .kds-col-lg-5 { grid-area: auto/span 5; }
8088
+ .kds-col-lg-6 { grid-area: auto/span 6; }
8089
+ .kds-col-lg-7 { grid-area: auto/span 7; }
8090
+ .kds-col-lg-8 { grid-area: auto/span 8; }
8091
+ .kds-col-lg-9 { grid-area: auto/span 9; }
8092
+ .kds-col-lg-10 { grid-area: auto/span 10; }
8093
+ .kds-col-lg-11 { grid-area: auto/span 11; }
8094
+ .kds-col-lg-12 { grid-area: auto/span 12; }
8095
+ }
8096
+