@khipu/design-system 0.3.5-alpha.35 → 0.3.5-alpha.37

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.
@@ -15,7 +15,7 @@
15
15
  *
16
16
  * AUTO-GENERATED FILE - DO NOT EDIT MANUALLY
17
17
  * Source: design-system/src/tokens/tokens.json
18
- * Generated: 2026-10-09T18:13:29.633Z
18
+ * Generated: 2026-10-27T18:34:57.467Z
19
19
  *
20
20
  * To regenerate:
21
21
  * cd design-system && npm run tokens:generate
@@ -1487,6 +1487,118 @@
1487
1487
  line-height: var(--kds-line-height-normal);
1488
1488
  }
1489
1489
 
1490
+ /* Extra content under the description (e.g. a "Necesitarás" list). */
1491
+ .kds-theme-root .kds-card-selector-details {
1492
+ font-size: var(--kds-font-size-sm);
1493
+ color: var(--kds-color-text-primary);
1494
+ line-height: var(--kds-line-height-normal);
1495
+ }
1496
+
1497
+ /* !important on the top margin: BeerCSS adds 1rem to a list after a sibling with a higher
1498
+ specificity (same approach as .kds-card-plan ul). */
1499
+ .kds-theme-root .kds-card-selector-details :is(ul, ol) {
1500
+ margin: 0;
1501
+ margin-block-start: var(--kds-spacing-1) !important;
1502
+ padding-inline-start: var(--kds-spacing-2-5);
1503
+ }
1504
+
1505
+ /* Small section label inside the details, e.g. "Necesitarás". */
1506
+ .kds-theme-root .kds-card-selector-eyebrow {
1507
+ display: block;
1508
+ font-size: var(--kds-font-size-xs);
1509
+ font-weight: var(--kds-font-weight-bold);
1510
+ letter-spacing: var(--kds-letter-spacing-wide);
1511
+ text-transform: uppercase;
1512
+ color: var(--primary);
1513
+ }
1514
+
1515
+ /* Radio option (.kds-card-selector--radio): a <div> card with a native radio top-right
1516
+ and the title <label> stretched over the card, so any click selects it and cards
1517
+ sharing a `name` behave as one radio group (arrow keys, form submit) without JS.
1518
+ Same pattern as .kds-card-plan--selectable. */
1519
+ .kds-theme-root .kds-card-selector--radio {
1520
+ position: relative;
1521
+ padding: var(--kds-spacing-2-5);
1522
+ gap: var(--kds-spacing-1);
1523
+ }
1524
+
1525
+ /* Icon tile tinted from --primary (follows the merchant's brand; the base tile uses the
1526
+ fixed --kds-color-primary-focus). Base button-mode cards keep their tile. */
1527
+ .kds-theme-root .kds-card-selector--radio .kds-card-selector-icon {
1528
+ background: color-mix(in srgb, var(--primary) 12%, transparent);
1529
+ border-radius: var(--kds-radius-md);
1530
+ }
1531
+
1532
+ /* Selector group (KdsCardSelectorGroup): columns by the group's own width, like
1533
+ .kds-card-plan-group. */
1534
+ .kds-theme-root .kds-card-selector-group {
1535
+ display: grid;
1536
+ grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
1537
+ gap: var(--kds-spacing-2);
1538
+ align-items: stretch;
1539
+ }
1540
+
1541
+ .kds-theme-root .kds-card-selector-radio {
1542
+ position: absolute;
1543
+ top: var(--kds-spacing-2);
1544
+ right: var(--kds-spacing-2);
1545
+ z-index: 2;
1546
+ width: var(--kds-spacing-2-5);
1547
+ height: var(--kds-spacing-2-5);
1548
+ margin: 0;
1549
+ accent-color: var(--primary);
1550
+ cursor: pointer;
1551
+ }
1552
+
1553
+ /* BeerCSS positions and sizes bare <label>s; the title keeps its own type styles and
1554
+ must stay static so its ::after resolves against the card. */
1555
+ .kds-theme-root .kds-card-selector--radio label.kds-card-selector-title {
1556
+ position: static;
1557
+ padding-inline-end: var(--kds-spacing-4);
1558
+ cursor: pointer;
1559
+ }
1560
+
1561
+ .kds-theme-root .kds-card-selector--radio label.kds-card-selector-title::after {
1562
+ content: "";
1563
+ position: absolute;
1564
+ inset: 0;
1565
+ z-index: 1;
1566
+ border-radius: var(--kds-radius-md);
1567
+ }
1568
+
1569
+ /* Interactive content inside the card stays above the stretched label. */
1570
+ .kds-theme-root .kds-card-selector--radio :is(a, button, input:not(.kds-card-selector-radio), select, textarea, summary, [tabindex]) {
1571
+ position: relative;
1572
+ z-index: 2;
1573
+ }
1574
+
1575
+ /* Hover must not look like the checked state: neutral, darker border. Same specificity as
1576
+ the base `.kds-card-selector:hover:not(.selected)` (primary tint) and later, so it wins. */
1577
+ .kds-theme-root .kds-card-selector.kds-card-selector--radio:hover:not(.selected) {
1578
+ border-color: var(--kds-border-dark);
1579
+ background: var(--kds-color-background-paper);
1580
+ }
1581
+
1582
+ /* Checked and focus need :has. Without it the radio keeps its native look and focus
1583
+ ring, so the choice and the focus stay visible in older browsers. */
1584
+ @supports selector(:has(*)) {
1585
+ /* Same brand tint as the selected plan card (follows the merchant's --primary).
1586
+ Doubled class so it outranks the neutral hover above and stays selected on hover. */
1587
+ .kds-theme-root .kds-card-selector.kds-card-selector--radio:has(.kds-card-selector-radio:checked) {
1588
+ border-color: var(--primary);
1589
+ background: color-mix(in srgb, var(--primary) 5%, var(--kds-surface-base));
1590
+ }
1591
+
1592
+ .kds-theme-root .kds-card-selector--radio:has(.kds-card-selector-radio:focus-visible) {
1593
+ outline: 2px solid var(--primary);
1594
+ outline-offset: 2px;
1595
+ }
1596
+
1597
+ .kds-theme-root .kds-card-selector-radio:focus-visible {
1598
+ outline: none;
1599
+ }
1600
+ }
1601
+
1490
1602
  /* Selected state - visual feedback via border only */
1491
1603
 
1492
1604
  /* Pricing/Plan card */
@@ -1531,9 +1643,190 @@
1531
1643
  box-shadow: var(--kds-shadow-elevation-4);
1532
1644
  }
1533
1645
 
1534
- /* Recommended Badge — inline dentro del card (no flotante).
1535
- Es el primer hijo del .kds-card-plan, así que aparece arriba de todo
1536
- el contenido, alineado a la izquierda. */
1646
+ /* Selectable plan (.kds-card-plan--selectable): a native radio sits top-right and the
1647
+ title <label> is stretched over the whole card, so any click selects it and cards
1648
+ sharing a `name` behave as one radio group (arrow keys, form submit) without JS. */
1649
+ .kds-theme-root .kds-card-plan-radio {
1650
+ position: absolute;
1651
+ top: var(--kds-spacing-2);
1652
+ right: var(--kds-spacing-2);
1653
+ z-index: 2;
1654
+ width: var(--kds-spacing-2-5);
1655
+ height: var(--kds-spacing-2-5);
1656
+ margin: 0;
1657
+ accent-color: var(--primary);
1658
+ cursor: pointer;
1659
+ }
1660
+
1661
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-header {
1662
+ padding-inline-end: var(--kds-spacing-4);
1663
+ }
1664
+
1665
+ /* BeerCSS makes header, h3 and label `position: relative`; they must stay static so the
1666
+ label's ::after resolves against the card, not against the label itself. */
1667
+ .kds-theme-root .kds-card-plan--selectable :is(.kds-card-plan-header, .kds-card-plan-header h3, .kds-card-plan-header label) {
1668
+ position: static;
1669
+ }
1670
+
1671
+ /* BeerCSS sizes bare <label>s; the title label must look like the h3 it lives in. */
1672
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-header label {
1673
+ font: inherit;
1674
+ color: inherit;
1675
+ cursor: pointer;
1676
+ }
1677
+
1678
+ /* Above the (BeerCSS-positioned) feature items, below the radio and actions. */
1679
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-header label::after {
1680
+ content: "";
1681
+ position: absolute;
1682
+ inset: 0;
1683
+ z-index: 1;
1684
+ border-radius: var(--kds-radius-lg);
1685
+ }
1686
+
1687
+ /* Interactive content inside the card stays above the stretched label, so it remains
1688
+ clickable (features may come as raw HTML from the consumer). */
1689
+ .kds-theme-root .kds-card-plan--selectable :is(a, button, input:not(.kds-card-plan-radio), select, textarea, summary, [tabindex]) {
1690
+ position: relative;
1691
+ z-index: 2;
1692
+ }
1693
+
1694
+ /* Optional plan description (KdsCardPlan `description`) — a <div>, so BeerCSS's sibling
1695
+ margin on <p> does not apply. */
1696
+ .kds-theme-root .kds-card-plan-description {
1697
+ font-size: var(--kds-font-size-sm);
1698
+ line-height: var(--kds-line-height-normal);
1699
+ color: var(--kds-color-text-secondary);
1700
+ }
1701
+
1702
+ /* Optional check per feature (KdsCardPlan `checkFeatures`), in the brand color. */
1703
+ .kds-theme-root .kds-card-plan-features--check li {
1704
+ display: flex;
1705
+ align-items: flex-start;
1706
+ gap: var(--kds-spacing-1);
1707
+ }
1708
+
1709
+ .kds-theme-root .kds-card-plan-features--check li > i {
1710
+ flex: none;
1711
+ margin-top: 2px;
1712
+ font-size: var(--kds-font-size-base);
1713
+ color: var(--primary);
1714
+ }
1715
+
1716
+ /* Selectable plan cards (new, onboarding): compact like the plan screen — badge on top,
1717
+ smaller title and price, and the divider above the feature list instead of under a big
1718
+ price. Plain .kds-card-plan (marketing/billing) keeps its larger layout. */
1719
+ .kds-theme-root .kds-card-plan--selectable {
1720
+ gap: var(--kds-spacing-1);
1721
+ }
1722
+
1723
+ /* Badge as a soft tag (not the solid pill of marketing plan cards), so it doesn't compete
1724
+ with the selected border. */
1725
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-badge {
1726
+ order: -1;
1727
+ padding: var(--kds-spacing-0-25) var(--kds-spacing-1);
1728
+ background: color-mix(in srgb, var(--primary) 12%, var(--kds-surface-base));
1729
+ color: var(--primary);
1730
+ font-weight: var(--kds-font-weight-medium);
1731
+ line-height: var(--kds-line-height-normal);
1732
+ border-radius: var(--kds-radius-sm);
1733
+ }
1734
+
1735
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-header h3 {
1736
+ font-size: var(--kds-font-size-lg);
1737
+ }
1738
+
1739
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-price {
1740
+ gap: var(--kds-spacing-0-5);
1741
+ border-bottom: 0;
1742
+ }
1743
+
1744
+ .kds-theme-root .kds-card-plan--selectable .kds-price {
1745
+ font-size: var(--kds-font-size-sm);
1746
+ font-weight: var(--kds-font-weight-medium);
1747
+ line-height: var(--kds-line-height-normal);
1748
+ }
1749
+
1750
+ .kds-theme-root .kds-card-plan--selectable .kds-price-period {
1751
+ font-size: var(--kds-font-size-sm);
1752
+ }
1753
+
1754
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-features {
1755
+ gap: var(--kds-spacing-0-75);
1756
+ margin-top: var(--kds-spacing-0-5);
1757
+ padding-top: var(--kds-spacing-1-5);
1758
+ border-top: 1px solid var(--kds-border-light);
1759
+ font-size: var(--kds-font-size-sm);
1760
+ line-height: var(--kds-line-height-snug);
1761
+ }
1762
+
1763
+ .kds-theme-root .kds-card-plan--selectable .kds-card-plan-features--check li > i {
1764
+ font-size: var(--kds-font-size-sm);
1765
+ margin-top: 3px;
1766
+ }
1767
+
1768
+ /* Plan group (KdsCardPlanGroup): as many columns as fit in the group's own width, so it
1769
+ also works in a narrow card next to the panel sidebar (a viewport breakpoint would put
1770
+ two 260px cards in a 300px card and overflow). Inside the group the cards fill their
1771
+ column; min(…, 100%) keeps a single column from overflowing very narrow containers. */
1772
+ .kds-theme-root .kds-card-plan-group {
1773
+ display: grid;
1774
+ grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
1775
+ gap: var(--kds-spacing-2);
1776
+ align-items: stretch;
1777
+ }
1778
+
1779
+ .kds-theme-root .kds-card-plan-group > .kds-card-plan {
1780
+ min-width: 0;
1781
+ max-width: none;
1782
+ }
1783
+
1784
+ /* In a selection the border signals the choice, so `recommended` keeps only its badge. */
1785
+ .kds-theme-root .kds-card-plan--selectable.recommended {
1786
+ background: var(--kds-surface-base);
1787
+ box-shadow: none;
1788
+ }
1789
+
1790
+ /* Unselected border matches the sibling selector cards (border-light), lighter than the
1791
+ plain plan card's border-medium. Before the hover rule so hover still wins. */
1792
+ .kds-theme-root .kds-card-plan--selectable,
1793
+ .kds-theme-root .kds-card-plan--selectable.recommended {
1794
+ border-color: var(--kds-border-light);
1795
+ }
1796
+
1797
+ /* Hover must not look like the selected state (primary border): neutral, darker border.
1798
+ The selected card keeps its primary border on hover (the :checked rule outranks this). */
1799
+ .kds-theme-root .kds-card-plan--selectable:hover,
1800
+ .kds-theme-root .kds-card-plan--selectable.recommended:hover {
1801
+ border-color: var(--kds-border-dark);
1802
+ }
1803
+
1804
+ .kds-theme-root .kds-card-plan--selectable.recommended:hover {
1805
+ box-shadow: var(--kds-shadow-2);
1806
+ }
1807
+
1808
+ /* Selected and focus states need :has. Without it the radio keeps its native look and
1809
+ focus ring, so the choice and the focus stay visible in older browsers. */
1810
+ @supports selector(:has(*)) {
1811
+ .kds-theme-root .kds-card-plan--selectable:has(.kds-card-plan-radio:checked) {
1812
+ border-color: var(--primary);
1813
+ background: color-mix(in srgb, var(--primary) 5%, var(--kds-surface-base));
1814
+ }
1815
+
1816
+ /* Focus is shown on the whole card; the radio's own ring would draw a second one. */
1817
+ .kds-theme-root .kds-card-plan--selectable:has(.kds-card-plan-radio:focus-visible) {
1818
+ outline: 2px solid var(--primary);
1819
+ outline-offset: 2px;
1820
+ }
1821
+
1822
+ .kds-theme-root .kds-card-plan-radio:focus-visible {
1823
+ outline: none;
1824
+ }
1825
+ }
1826
+
1827
+ /* Recommended Badge — inline dentro del card (no flotante), alineado a la izquierda.
1828
+ KdsCardPlan lo renderiza después del precio; en las cards seleccionables
1829
+ (.kds-card-plan--selectable) `order: -1` lo sube arriba del título. */
1537
1830
  .kds-theme-root .kds-card-plan-badge {
1538
1831
  align-self: flex-start;
1539
1832
  padding: var(--kds-spacing-0-5) var(--kds-spacing-1-5);
@@ -2153,6 +2446,154 @@
2153
2446
  }
2154
2447
  }
2155
2448
 
2449
+ /* Stepper modifiers (additive: the base markup above, e.g. payment's mat:stepper,
2450
+ renders exactly as before without them). */
2451
+
2452
+ /* --numbered: step number inside the indicator. Bold 20px is "large text", so the
2453
+ white number on the info indicator (3.8:1) still meets AA. Completed steps hide the
2454
+ number and keep the ::after check. */
2455
+ .kds-theme-root .kds-stepper--numbered .kds-step-indicator {
2456
+ font-size: var(--kds-font-size-2xl);
2457
+ font-weight: var(--kds-font-weight-bold);
2458
+ line-height: 1;
2459
+ }
2460
+
2461
+ .kds-theme-root .kds-stepper--numbered .kds-step.current .kds-step-indicator {
2462
+ color: var(--kds-color-info-contrast);
2463
+ }
2464
+
2465
+ /* --on-primary follows the merchant's brand (KdsThemeProvider computes it from --primary). */
2466
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step.current .kds-step-indicator {
2467
+ color: var(--on-primary);
2468
+ }
2469
+
2470
+ .kds-theme-root .kds-stepper--numbered .kds-step.completed .kds-step-indicator {
2471
+ font-size: 0;
2472
+ }
2473
+
2474
+ /* --primary: current step in the brand color instead of info. */
2475
+ .kds-theme-root .kds-stepper--primary .kds-step.current .kds-step-indicator {
2476
+ background: var(--primary);
2477
+ box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary) 15%, transparent);
2478
+ }
2479
+
2480
+ /* --numbered: pending steps and the connector must be visible on a white card (the base
2481
+ background-elevated #fafafa is ~1.04:1 against white). */
2482
+ .kds-theme-root .kds-stepper--numbered::before {
2483
+ background: var(--kds-color-gray-300);
2484
+ }
2485
+
2486
+ .kds-theme-root .kds-stepper--numbered .kds-step:not(.completed):not(.current) .kds-step-indicator {
2487
+ background: var(--kds-color-gray-200);
2488
+ box-shadow: none;
2489
+ }
2490
+
2491
+ /* --numbered + --primary (onboarding): compact 28px dots, small bold number (white on the
2492
+ brand color is 6:1, so it does not need large text), small labels, and a progress line
2493
+ per segment: green up to the current step, grey after it. */
2494
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary::before {
2495
+ display: none;
2496
+ }
2497
+
2498
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step-indicator {
2499
+ width: var(--kds-spacing-3-5);
2500
+ height: var(--kds-spacing-3-5);
2501
+ font-size: var(--kds-font-size-sm);
2502
+ }
2503
+
2504
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step.completed .kds-step-indicator {
2505
+ font-size: 0;
2506
+ }
2507
+
2508
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step.completed .kds-step-indicator::after {
2509
+ font-size: var(--kds-font-size-lg);
2510
+ }
2511
+
2512
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step:not(:first-child)::before {
2513
+ content: "";
2514
+ position: absolute;
2515
+ top: calc(var(--kds-spacing-3-5) / 2 - 1px);
2516
+ left: -50%;
2517
+ right: 50%;
2518
+ height: 2px;
2519
+ background: var(--kds-color-gray-300);
2520
+ z-index: 0;
2521
+ }
2522
+
2523
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step:is(.completed, .current)::before {
2524
+ background: var(--kds-color-success-main);
2525
+ }
2526
+
2527
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step-label {
2528
+ margin-top: var(--kds-spacing-0-75);
2529
+ font-size: var(--kds-font-size-xs);
2530
+ }
2531
+
2532
+ .kds-theme-root .kds-stepper--numbered.kds-stepper--primary .kds-step.current .kds-step-label {
2533
+ font-weight: var(--kds-font-weight-bold);
2534
+ }
2535
+
2536
+ /* --current-label: when the stepper itself is narrow (≤ 560px of available width, e.g. a
2537
+ card next to the panel sidebar, or a phone) only the current step keeps a visible label;
2538
+ the others are visually hidden but still read by screen readers. The first/last current
2539
+ label hugs its edge so it is not cut. It is a container query so it reacts to the space
2540
+ the stepper gets, not to the viewport; browsers without container queries fall back to
2541
+ the viewport width. */
2542
+ /* Size containment drops the intrinsic width: without an explicit width the stepper would
2543
+ collapse to 0px inside content-sized parents (centered flex columns, inline-block). */
2544
+ .kds-theme-root .kds-stepper--current-label {
2545
+ container-type: inline-size;
2546
+ inline-size: 100%;
2547
+ }
2548
+
2549
+ @container (max-width: 560px) {
2550
+ .kds-theme-root .kds-stepper--current-label .kds-step:not(.current) .kds-step-label {
2551
+ position: absolute;
2552
+ width: 1px;
2553
+ height: 1px;
2554
+ overflow: hidden;
2555
+ clip-path: inset(50%);
2556
+ white-space: nowrap;
2557
+ }
2558
+
2559
+ .kds-theme-root .kds-stepper--current-label .kds-step.current .kds-step-label {
2560
+ white-space: nowrap;
2561
+ }
2562
+
2563
+ .kds-theme-root .kds-stepper--current-label .kds-step.current:first-child .kds-step-label {
2564
+ align-self: flex-start;
2565
+ text-align: start;
2566
+ }
2567
+
2568
+ .kds-theme-root .kds-stepper--current-label .kds-step.current:last-child .kds-step-label {
2569
+ align-self: flex-end;
2570
+ text-align: end;
2571
+ }
2572
+ }
2573
+
2574
+ @supports not (container-type: inline-size) {
2575
+ @media (max-width: 560px) {
2576
+ .kds-theme-root .kds-stepper--current-label .kds-step:not(.current) .kds-step-label {
2577
+ position: absolute;
2578
+ width: 1px;
2579
+ height: 1px;
2580
+ overflow: hidden;
2581
+ clip-path: inset(50%);
2582
+ white-space: nowrap;
2583
+ }
2584
+
2585
+ .kds-theme-root .kds-stepper--current-label .kds-step.current .kds-step-label {
2586
+ white-space: nowrap;
2587
+ }
2588
+ }
2589
+ }
2590
+
2591
+ /* Safety net for any stepper in a narrow box: a long word breaks inside its column
2592
+ instead of overlapping the next label. No effect where the words already fit. */
2593
+ .kds-theme-root .kds-step-label {
2594
+ overflow-wrap: break-word;
2595
+ }
2596
+
2156
2597
  /* ========================================
2157
2598
  Snackbar Positioning & Styling
2158
2599
  ======================================== */
@@ -3347,6 +3788,14 @@
3347
3788
  cursor: pointer;
3348
3789
  }
3349
3790
 
3791
+ /* BeerCSS sets white-space: nowrap on the label, so a label longer than its container ran
3792
+ past it (e.g. on phones). Let the text wrap; labels that fit render as before. */
3793
+ .kds-theme-root label.checkbox > span,
3794
+ .kds-theme-root label.radio > span {
3795
+ white-space: normal;
3796
+ min-width: 0;
3797
+ }
3798
+
3350
3799
  /* Checked state.
3351
3800
  accent-color aplica al input nativo, que BeerCSS deja con opacity 0: no se ve.
3352
3801
  Se mantiene igual por si algun consumidor no usa el markup de BeerCSS. */
@@ -4208,6 +4657,47 @@
4208
4657
  transform: translateY(0);
4209
4658
  }
4210
4659
 
4660
+ /* Menu toggle (KdsSidebar with a menu): a real <button> holding avatar, text and arrow,
4661
+ with the dropdown as its sibling — never links inside a button. It looks like the plain
4662
+ header content, so BeerCSS's button styles (fill, size, radius, ripple) are reset. The
4663
+ vanilla markup (sidebar.js) keeps the click handler on the header itself. */
4664
+ .kds-theme-root .kds-sidebar-header > .kds-sidebar-header-toggle {
4665
+ display: flex;
4666
+ flex: 1;
4667
+ min-width: 0;
4668
+ align-items: center;
4669
+ justify-content: flex-start;
4670
+ gap: var(--kds-spacing-3);
4671
+ block-size: auto;
4672
+ margin: 0;
4673
+ padding: 0;
4674
+ border: 0;
4675
+ border-radius: 0;
4676
+ background: transparent;
4677
+ box-shadow: none;
4678
+ color: inherit;
4679
+ font: inherit;
4680
+ letter-spacing: inherit;
4681
+ text-align: start;
4682
+ text-transform: none;
4683
+ cursor: pointer;
4684
+ }
4685
+
4686
+ /* Outranks BeerCSS's `:is(…, button):not([class*=ripple])::after` ripple (0,2,1), which
4687
+ would otherwise cover the whole header (the button is not positioned). */
4688
+ .kds-theme-root .kds-sidebar .kds-sidebar-header > .kds-sidebar-header-toggle::after {
4689
+ content: none;
4690
+ }
4691
+
4692
+ .kds-theme-root .kds-sidebar-header > .kds-sidebar-header-toggle:focus-visible {
4693
+ outline: 2px solid var(--primary);
4694
+ outline-offset: 2px;
4695
+ }
4696
+
4697
+ .kds-theme-root .kds-sidebar-header-toggle[aria-expanded="true"] .kds-sidebar-dropdown-icon {
4698
+ transform: rotate(180deg);
4699
+ }
4700
+
4211
4701
  /* Navigation */
4212
4702
  .kds-theme-root .kds-sidebar-nav {
4213
4703
  padding: var(--kds-spacing-2) 0;
@@ -4371,6 +4861,10 @@
4371
4861
  transition: transform var(--kds-transition-standard) var(--kds-easing-ease-out);
4372
4862
  z-index: var(--kds-z-index-drawer);
4373
4863
  border-radius: 0;
4864
+ /* Full-height fixed drawer: scroll instead of cutting off items below the fold
4865
+ (long menus, short screens in landscape). */
4866
+ overflow-y: auto;
4867
+ overscroll-behavior: contain;
4374
4868
  }
4375
4869
 
4376
4870
  /* Barra superior mobile visible */
@@ -4965,6 +5459,46 @@
4965
5459
  overflow-y: auto;
4966
5460
  }
4967
5461
 
5462
+ /* Read-to-accept contract (.kds-contract): content + acceptance checkbox + hint. The
5463
+ checkbox stays disabled until the content is scrolled to the end (KdsContract, or
5464
+ [data-kds-contract] with Khipu.initContract in the BeerCSS bundle). */
5465
+ .kds-theme-root .kds-contract {
5466
+ display: flex;
5467
+ flex-direction: column;
5468
+ gap: var(--kds-spacing-2);
5469
+ }
5470
+
5471
+ /* Inside the read-to-accept block the box is denser and shorter than the standalone
5472
+ contract page (.kds-contract-content alone keeps its 48px padding / 400px height). */
5473
+ .kds-theme-root .kds-contract > .kds-contract-content {
5474
+ padding: var(--kds-spacing-2);
5475
+ max-height: 240px;
5476
+ }
5477
+
5478
+ /* Denser paragraphs in the read-to-accept box (BeerCSS gives <p> 0.5rem + 1rem siblings). */
5479
+ .kds-theme-root .kds-contract > .kds-contract-content p {
5480
+ margin: 0 0 var(--kds-spacing-1) !important;
5481
+ }
5482
+
5483
+ /* The content is focusable so it can be scrolled with the keyboard. */
5484
+ .kds-theme-root .kds-contract-content:focus-visible {
5485
+ outline: 2px solid var(--primary);
5486
+ outline-offset: 2px;
5487
+ }
5488
+
5489
+ /* BeerCSS pads label.checkbox; the gap of .kds-contract spaces the parts and the hint
5490
+ (a <div>: BeerCSS adds a 1rem top margin to a <p> after a sibling) sits close to the
5491
+ checkbox it explains. */
5492
+ .kds-theme-root .kds-contract > .kds-contract-accept {
5493
+ padding-block: 0;
5494
+ }
5495
+
5496
+ .kds-theme-root .kds-contract > .kds-contract-hint {
5497
+ margin: calc(var(--kds-spacing-1) * -1) 0 0;
5498
+ font-size: var(--kds-font-size-sm);
5499
+ color: var(--kds-color-text-secondary);
5500
+ }
5501
+
4968
5502
  .kds-theme-root .kds-contract-content details {
4969
5503
  margin-bottom: var(--kds-spacing-4);
4970
5504
  }
@@ -5888,7 +6422,9 @@
5888
6422
 
5889
6423
  /* ========================================
5890
6424
  05 - LOCKED FIELD (.field.locked)
5891
- Read-only field with lock icon
6425
+ Read-only field with lock icon.
6426
+ Value and label use text-secondary (not text-disabled): unlike a disabled
6427
+ field, the user still has to read a locked value, so it must meet AA contrast.
5892
6428
  ======================================== */
5893
6429
 
5894
6430
  .kds-theme-root .field.locked {
@@ -5897,39 +6433,57 @@
5897
6433
 
5898
6434
  .kds-theme-root .field.locked > input,
5899
6435
  .kds-theme-root .field.locked > textarea {
5900
- color: var(--kds-color-text-disabled);
6436
+ color: var(--kds-color-text-secondary);
5901
6437
  cursor: default;
5902
6438
  pointer-events: none;
5903
6439
  }
5904
6440
 
5905
6441
  .kds-theme-root .field.locked > label {
5906
- color: var(--kds-color-text-disabled);
6442
+ color: var(--kds-color-text-secondary);
5907
6443
  }
5908
6444
 
5909
- /* Locked: suppress all hover/focus visual changes */
5910
- .kds-theme-root .field.label.border:not(.fill).locked:hover:not(:focus-within) > label::after,
5911
- .kds-theme-root .field.label.border:not(.fill).locked:focus-within > label::after {
6445
+ /* Locked: no editable hover. */
6446
+ .kds-theme-root .field.label.border:not(.fill).locked:hover:not(:focus-within) > label::after {
5912
6447
  border-block-start-color: var(--outline);
5913
6448
  }
5914
- .kds-theme-root .field.label.border:not(.fill).locked:hover:not(:focus-within) > :is(input, textarea, select), .kds-theme-root .field.label.border:not(.fill).locked:focus-within > :is(input, textarea, select) {
6449
+ .kds-theme-root .field.label.border:not(.fill).locked:hover:not(:focus-within) > :is(input, textarea, select) {
5915
6450
  border-color: var(--outline);
5916
6451
  }
5917
6452
  .kds-theme-root .field.label.locked:hover:not(:focus-within) > label {
5918
- color: var(--kds-color-text-disabled);
6453
+ color: var(--kds-color-text-secondary);
6454
+ }
6455
+
6456
+ /* Locked focus: a locked field stays reachable with Tab, so it needs a visible focus
6457
+ indicator (WCAG 2.4.7), but not the primary-colored one of an editable field.
6458
+ BeerCSS's 2px focus border is kept (its padding already compensates it) in the
6459
+ neutral text-secondary color, and the label does not turn primary. */
6460
+ .kds-theme-root .field.label.border:not(.fill).locked:focus-within > label::after {
6461
+ border-block-start-color: var(--kds-color-text-secondary);
6462
+ }
6463
+ .kds-theme-root .field.label.border:not(.fill).locked:focus-within > :is(input, textarea, select) {
6464
+ border-color: var(--kds-color-text-secondary);
6465
+ }
6466
+ .kds-theme-root .field.label.locked > :focus + label {
6467
+ color: var(--kds-color-text-secondary);
5919
6468
  }
5920
6469
 
5921
- .kds-theme-root .field.locked > i {
6470
+ /* Lock icon only: a leading .prefix icon is the first child and keeps its place.
6471
+ text-secondary, not text-disabled: the lock is what tells locked from disabled,
6472
+ so as a meaningful graphic it needs 3:1 (WCAG 1.4.11). */
6473
+ .kds-theme-root .field.locked > i:not(:first-child) {
5922
6474
  position: absolute;
5923
6475
  right: var(--kds-spacing-1-5);
5924
- top: 50%;
6476
+ /* Center of the input (BeerCSS --_middle), not of the field: with helper text the
6477
+ field is taller than the input. Without it both are the same. */
6478
+ top: var(--_middle, 50%);
5925
6479
  transform: translateY(-50%);
5926
- color: var(--kds-color-text-disabled);
6480
+ color: var(--kds-color-text-secondary);
5927
6481
  pointer-events: none;
5928
6482
  font-size: 18px;
5929
6483
  }
5930
6484
 
5931
6485
  /* Verified variant (green check) */
5932
- .kds-theme-root .field.locked.verified > i {
6486
+ .kds-theme-root .field.locked.verified > i:not(:first-child) {
5933
6487
  color: var(--kds-color-success-main);
5934
6488
  }
5935
6489
 
@@ -6850,6 +7404,260 @@
6850
7404
  }
6851
7405
  }
6852
7406
 
7407
+ /* ========================================
7408
+ PROGRESS CHECKLIST (.kds-progress-checklist)
7409
+ Steps that advance pending → active → done (or error), e.g. an automatic
7410
+ validation. The list is aria-live; each item carries its status as visually
7411
+ hidden text (.kds-progress-checklist-status). Status modifiers are BEM
7412
+ (--pending/--active/--done/--error): BeerCSS already has global .error/.active.
7413
+ ======================================== */
7414
+
7415
+ .kds-theme-root .kds-progress-checklist {
7416
+ list-style: none;
7417
+ margin: 0;
7418
+ padding: 0;
7419
+ display: flex;
7420
+ flex-direction: column;
7421
+ gap: var(--kds-spacing-0-75);
7422
+ text-align: start;
7423
+ }
7424
+
7425
+ .kds-theme-root .kds-progress-checklist-item {
7426
+ position: relative;
7427
+ display: flex;
7428
+ align-items: center;
7429
+ gap: var(--kds-spacing-1-25);
7430
+ margin: 0;
7431
+ font-size: var(--kds-font-size-base);
7432
+ color: var(--kds-color-text-primary);
7433
+ transition: color 0.25s ease;
7434
+ }
7435
+
7436
+ /* Inside a bottom sheet the list is a centered block, under the centered title. */
7437
+ .kds-theme-root .kds-bottom-sheet-body > .kds-progress-checklist {
7438
+ width: fit-content;
7439
+ margin-inline: auto;
7440
+ }
7441
+
7442
+ .kds-theme-root .kds-progress-checklist-item--pending {
7443
+ color: var(--kds-color-text-secondary);
7444
+ }
7445
+
7446
+ .kds-theme-root .kds-progress-checklist-mark {
7447
+ display: inline-flex;
7448
+ align-items: center;
7449
+ justify-content: center;
7450
+ flex: none;
7451
+ width: var(--kds-spacing-2-5);
7452
+ height: var(--kds-spacing-2-5);
7453
+ }
7454
+
7455
+ .kds-theme-root .kds-progress-checklist-mark > i {
7456
+ font-size: var(--kds-spacing-2-5);
7457
+ }
7458
+
7459
+ /* Smaller dots so the loader fits the 20px mark like the icons do. */
7460
+ .kds-theme-root .kds-progress-checklist-mark .kds-dots-loader > span {
7461
+ width: var(--kds-spacing-0-5);
7462
+ height: var(--kds-spacing-0-5);
7463
+ }
7464
+
7465
+ .kds-theme-root .kds-progress-checklist-item--done .kds-progress-checklist-mark {
7466
+ color: var(--kds-color-success-main);
7467
+ }
7468
+
7469
+ .kds-theme-root .kds-progress-checklist-item--error .kds-progress-checklist-mark {
7470
+ color: var(--kds-color-error-main);
7471
+ }
7472
+
7473
+ .kds-theme-root .kds-progress-checklist-item--active .kds-progress-checklist-mark {
7474
+ color: var(--kds-color-text-secondary);
7475
+ }
7476
+
7477
+ /* The pending dot is decorative (the status is in the hidden text), so it can be faint;
7478
+ the label keeps text-secondary for contrast. */
7479
+ .kds-theme-root .kds-progress-checklist-item--pending .kds-progress-checklist-mark {
7480
+ color: var(--kds-color-text-disabled);
7481
+ }
7482
+
7483
+ .kds-theme-root .kds-progress-checklist-dot {
7484
+ width: var(--kds-spacing-0-75);
7485
+ height: var(--kds-spacing-0-75);
7486
+ border-radius: var(--kds-radius-full);
7487
+ background: currentColor;
7488
+ }
7489
+
7490
+ .kds-theme-root .kds-progress-checklist-status {
7491
+ position: absolute;
7492
+ width: 1px;
7493
+ height: 1px;
7494
+ overflow: hidden;
7495
+ clip-path: inset(50%);
7496
+ white-space: nowrap;
7497
+ }
7498
+
7499
+ /* ========================================
7500
+ FEEDBACK CARD (.kds-feedback-card)
7501
+ Optional question (e.g. "¿Cómo nos conociste?") with an answer control and a
7502
+ submit button; turns into a thank-you note (--submitted) in the same aria-live
7503
+ region. Text blocks are <div>s: BeerCSS adds margins to a <p> after a sibling.
7504
+ ======================================== */
7505
+
7506
+ .kds-theme-root .kds-feedback-card {
7507
+ display: flex;
7508
+ align-items: flex-start;
7509
+ gap: var(--kds-spacing-2);
7510
+ padding: var(--kds-spacing-2);
7511
+ border: 1px solid var(--kds-border-light);
7512
+ border-radius: var(--kds-radius-lg);
7513
+ background: var(--kds-color-background-elevated);
7514
+ }
7515
+
7516
+ .kds-theme-root .kds-feedback-card-icon {
7517
+ display: grid;
7518
+ place-items: center;
7519
+ flex: none;
7520
+ width: var(--kds-spacing-5);
7521
+ height: var(--kds-spacing-5);
7522
+ border-radius: var(--kds-radius-md);
7523
+ background: var(--kds-color-primary-focus);
7524
+ color: var(--kds-color-primary-main);
7525
+ }
7526
+
7527
+ .kds-theme-root .kds-feedback-card-body {
7528
+ flex: 1;
7529
+ min-width: 0;
7530
+ display: flex;
7531
+ flex-direction: column;
7532
+ gap: var(--kds-spacing-2);
7533
+ }
7534
+
7535
+ .kds-theme-root .kds-feedback-card-title {
7536
+ font-size: var(--kds-font-size-base);
7537
+ font-weight: var(--kds-font-weight-bold);
7538
+ color: var(--kds-color-text-primary);
7539
+ }
7540
+
7541
+ /* BeerCSS adds 1rem above a .field after a sibling; the body gap already spaces it. */
7542
+ .kds-theme-root .kds-feedback-card-body > .field {
7543
+ margin-block-start: 0 !important;
7544
+ }
7545
+
7546
+ .kds-theme-root .kds-feedback-card-description {
7547
+ font-size: var(--kds-font-size-sm);
7548
+ line-height: var(--kds-line-height-normal);
7549
+ color: var(--kds-color-text-secondary);
7550
+ }
7551
+
7552
+ .kds-theme-root .kds-feedback-card--submitted {
7553
+ align-items: center;
7554
+ border-color: var(--kds-color-success-border-light);
7555
+ background: var(--kds-color-success-soft);
7556
+ }
7557
+
7558
+ .kds-theme-root .kds-feedback-card--submitted .kds-feedback-card-icon {
7559
+ background: var(--kds-color-background-paper);
7560
+ color: var(--kds-color-success-main);
7561
+ }
7562
+
7563
+ /* ========================================
7564
+ CONSENT CARD (.kds-consent-card)
7565
+ Access consent on a .kds-card-elevated: "<requester> solicita acceso a
7566
+ <resource>", sections (data requested, validity, purpose) and
7567
+ Authorize / Reject. Headings are div[role=heading] so BeerCSS heading
7568
+ margins do not apply. The secure footer goes outside the card.
7569
+ ======================================== */
7570
+
7571
+ .kds-theme-root .kds-consent-card {
7572
+ display: flex;
7573
+ flex-direction: column;
7574
+ gap: var(--kds-spacing-3);
7575
+ padding: var(--kds-spacing-3);
7576
+ }
7577
+
7578
+ .kds-theme-root .kds-consent-card-header {
7579
+ display: flex;
7580
+ flex-direction: column;
7581
+ align-items: center;
7582
+ gap: var(--kds-spacing-1);
7583
+ text-align: center;
7584
+ }
7585
+
7586
+ .kds-theme-root .kds-consent-card-title {
7587
+ font-size: var(--kds-font-size-xl);
7588
+ line-height: var(--kds-line-height-tight);
7589
+ color: var(--kds-color-text-primary);
7590
+ }
7591
+
7592
+ .kds-theme-root .kds-consent-card-title strong {
7593
+ color: var(--primary);
7594
+ font-weight: var(--kds-font-weight-semibold);
7595
+ }
7596
+
7597
+ .kds-theme-root .kds-consent-card-subtitle {
7598
+ font-size: var(--kds-font-size-sm);
7599
+ color: var(--kds-color-text-secondary);
7600
+ }
7601
+
7602
+ .kds-theme-root .kds-consent-card-body {
7603
+ display: flex;
7604
+ flex-direction: column;
7605
+ gap: var(--kds-spacing-2);
7606
+ }
7607
+
7608
+ .kds-theme-root .kds-consent-card-section {
7609
+ display: flex;
7610
+ flex-direction: column;
7611
+ gap: var(--kds-spacing-1);
7612
+ }
7613
+
7614
+ /* Dividers only between sections, not before the actions. */
7615
+ .kds-theme-root .kds-consent-card-section + .kds-consent-card-section {
7616
+ padding-block-start: var(--kds-spacing-2);
7617
+ border-block-start: 1px solid var(--kds-color-divider);
7618
+ }
7619
+
7620
+ .kds-theme-root .kds-consent-card-section-title {
7621
+ font-size: var(--kds-font-size-xs);
7622
+ font-weight: var(--kds-font-weight-semibold);
7623
+ letter-spacing: var(--kds-letter-spacing-wide);
7624
+ text-transform: uppercase;
7625
+ color: var(--kds-color-text-secondary);
7626
+ }
7627
+
7628
+ /* !important on the top margin: BeerCSS adds 1rem to a <ul> after a sibling with a
7629
+ higher specificity (same approach as .kds-card-elevated). */
7630
+ .kds-theme-root .kds-consent-card-items {
7631
+ list-style: none;
7632
+ margin: 0;
7633
+ margin-block-start: 0 !important;
7634
+ padding: 0;
7635
+ display: flex;
7636
+ flex-direction: column;
7637
+ gap: var(--kds-spacing-0-75);
7638
+ }
7639
+
7640
+ .kds-theme-root .kds-consent-card-item {
7641
+ display: flex;
7642
+ align-items: flex-start;
7643
+ gap: var(--kds-spacing-1-25);
7644
+ margin: 0;
7645
+ font-size: var(--kds-font-size-base);
7646
+ color: var(--kds-color-text-primary);
7647
+ }
7648
+
7649
+ .kds-theme-root .kds-consent-card-item > i {
7650
+ flex: none;
7651
+ font-size: var(--kds-spacing-2-5);
7652
+ color: var(--kds-color-text-secondary);
7653
+ }
7654
+
7655
+ .kds-theme-root .kds-consent-card-actions {
7656
+ display: flex;
7657
+ flex-direction: column;
7658
+ gap: var(--kds-spacing-1);
7659
+ }
7660
+
6853
7661
  /* ========================================
6854
7662
  14 - BOTTOM SHEET (.kds-bottom-sheet)
6855
7663
  Modal bottom sheet for mobile confirmations
@@ -6879,12 +7687,33 @@
6879
7687
  background: var(--kds-color-background-paper);
6880
7688
  border-radius: var(--kds-radius-2xl) var(--kds-radius-2xl) 0 0;
6881
7689
  padding: var(--kds-spacing-3-5) var(--kds-spacing-3) var(--kds-spacing-3);
7690
+ /* iPhone home indicator: keep the actions clear of it on viewport-fit=cover pages. */
7691
+ padding-bottom: calc(var(--kds-spacing-3) + env(safe-area-inset-bottom, 0px));
6882
7692
  box-shadow: var(--kds-bottom-sheet-shadow);
6883
7693
  animation: kds-rise 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
6884
7694
  text-align: center;
6885
7695
  position: relative;
6886
7696
  }
6887
7697
 
7698
+ /* The dialog container receives focus programmatically when it opens (Radix, tabindex=-1);
7699
+ the browser ring around the whole sheet is noise. Controls inside keep their own ring. */
7700
+ .kds-theme-root .kds-bottom-sheet:focus-visible {
7701
+ outline: none;
7702
+ }
7703
+
7704
+ /* As soon as the viewport is wider than the sheet (--kds-bottom-sheet-max-width = 420px;
7705
+ media queries cannot read tokens) the sheet no longer spans the screen, and glued to the
7706
+ bottom edge with square bottom corners it looks cut off. It stays anchored at the bottom
7707
+ (still a drawer) but floats: all corners rounded and a gap to the edge. The max-height
7708
+ also caps the full-height variant. */
7709
+ @media (min-width: 421px) {
7710
+ .kds-theme-root .kds-bottom-sheet {
7711
+ margin-bottom: var(--kds-spacing-3);
7712
+ border-radius: var(--kds-radius-2xl);
7713
+ max-height: calc(90dvh - var(--kds-spacing-3));
7714
+ }
7715
+ }
7716
+
6888
7717
  .kds-theme-root .kds-bottom-sheet-grabber {
6889
7718
  position: absolute;
6890
7719
  left: 50%;
@@ -6948,6 +7777,92 @@
6948
7777
  flex-direction: column;
6949
7778
  }
6950
7779
 
7780
+ /* Dialog variant (KdsBottomSheet variant="dialog"): a regular modal for desktop flows, with
7781
+ left-aligned text. On phones it stays a bottom sheet (stacked actions, primary first, as
7782
+ the DOM order); from 521px it is centered on the screen with the actions side by side and
7783
+ the primary on the right (row-reverse keeps the primary first in the tab order). 520px is
7784
+ where two buttons stop fitting side by side. The scrim modifier centers it vertically. */
7785
+ .kds-theme-root .kds-bottom-sheet--dialog {
7786
+ text-align: left;
7787
+ }
7788
+
7789
+ .kds-theme-root .kds-bottom-sheet--dialog .kds-bottom-sheet-title {
7790
+ font-weight: var(--kds-font-weight-bold);
7791
+ }
7792
+
7793
+ .kds-theme-root .kds-bottom-sheet--dialog .kds-bottom-sheet-description {
7794
+ font-size: var(--kds-font-size-sm);
7795
+ line-height: var(--kds-line-height-normal);
7796
+ color: var(--kds-color-text-primary);
7797
+ }
7798
+
7799
+ /* Status dialog (align="center"), e.g. a validation in progress with a loader on top. */
7800
+ .kds-theme-root .kds-bottom-sheet--dialog.kds-bottom-sheet--center {
7801
+ text-align: center;
7802
+ }
7803
+
7804
+ /* Icon / loader slot above the title (KdsBottomSheet `icon`): a flex row so a block child
7805
+ (a spinner) follows the text alignment too. */
7806
+ .kds-theme-root div.kds-bottom-sheet-icon {
7807
+ display: flex;
7808
+ justify-content: center;
7809
+ margin-bottom: var(--kds-spacing-1);
7810
+ }
7811
+
7812
+ .kds-theme-root .kds-bottom-sheet--dialog:not(.kds-bottom-sheet--center) div.kds-bottom-sheet-icon {
7813
+ justify-content: flex-start;
7814
+ }
7815
+
7816
+ /* An icon in the slot matches the default KdsSpinner (BeerCSS circle, 2.5rem), so swapping
7817
+ the loader for a result icon does not shift the content. */
7818
+ .kds-theme-root div.kds-bottom-sheet-icon > i {
7819
+ font-size: 2.5rem;
7820
+ inline-size: 2.5rem;
7821
+ block-size: 2.5rem;
7822
+ min-inline-size: unset;
7823
+ min-block-size: unset;
7824
+ }
7825
+
7826
+ /* Short note above the actions (KdsBottomSheet `hint`), e.g. "No cierres esta ventana." */
7827
+ .kds-theme-root .kds-bottom-sheet-hint {
7828
+ margin: var(--kds-spacing-2) 0 0;
7829
+ font-size: var(--kds-font-size-xs);
7830
+ line-height: var(--kds-line-height-normal);
7831
+ color: var(--kds-color-text-secondary);
7832
+ }
7833
+
7834
+ @media (min-width: 521px) {
7835
+ .kds-theme-root .kds-bottom-sheet-scrim--dialog {
7836
+ align-items: center;
7837
+ padding: var(--kds-spacing-2);
7838
+ }
7839
+
7840
+ .kds-theme-root .kds-bottom-sheet--dialog {
7841
+ margin: 0;
7842
+ padding: var(--kds-spacing-3);
7843
+ border-radius: var(--kds-radius-lg);
7844
+ max-height: 90dvh;
7845
+ }
7846
+
7847
+ .kds-theme-root .kds-bottom-sheet--dialog .kds-bottom-sheet-grabber {
7848
+ display: none;
7849
+ }
7850
+
7851
+ .kds-theme-root .kds-bottom-sheet--dialog .kds-bottom-sheet-title {
7852
+ margin-top: 0;
7853
+ }
7854
+
7855
+ .kds-theme-root .kds-bottom-sheet--dialog .kds-bottom-sheet-actions {
7856
+ flex-direction: row-reverse;
7857
+ margin-top: var(--kds-spacing-2);
7858
+ }
7859
+
7860
+ .kds-theme-root .kds-bottom-sheet--dialog .kds-bottom-sheet-actions > * {
7861
+ flex: 1;
7862
+ min-width: 0;
7863
+ }
7864
+ }
7865
+
6951
7866
  /* ========================================
6952
7867
  DOCUMENT FRAME (.kds-document-frame)
6953
7868
  Documento embebido (iframe) que llena su contenedor. --kds-document-frame-scale achica
@@ -9286,6 +10201,22 @@
9286
10201
  .kds-theme-root .kds-section-note.kds-error { color: var(--kds-color-error-dark); }
9287
10202
  .kds-theme-root .kds-section-note.kds-error > i { color: var(--kds-color-error-dark); }
9288
10203
 
10204
+ /* Neutral tone: calm, non-alarming context (e.g. "Datos obtenidos de tu cuenta en…",
10205
+ "Khipu no almacena tus contraseñas"). Secondary text with the icon in the brand color. */
10206
+ .kds-theme-root .kds-section-note.kds-neutral { color: var(--kds-color-text-secondary); }
10207
+ .kds-theme-root .kds-section-note.kds-neutral > i { color: var(--primary); }
10208
+
10209
+ /* Neutral notes often wrap to two lines: icon pinned to the first line, with a gap. */
10210
+ .kds-theme-root .kds-section-note.kds-neutral {
10211
+ align-items: flex-start;
10212
+ gap: var(--kds-spacing-1);
10213
+ line-height: var(--kds-line-height-normal);
10214
+ }
10215
+
10216
+ .kds-theme-root .kds-section-note.kds-neutral > i {
10217
+ margin-top: 0.125em;
10218
+ }
10219
+
9289
10220
  /* Dark: the semantic *-dark shades are near-invisible on the dark page bg —
9290
10221
  use the alert *-text tokens (light shades in dark). Base note is warning. */
9291
10222
  .kds-theme-root [data-theme="dark"] .kds-section-note,
@@ -9296,6 +10227,8 @@
9296
10227
  .kds-theme-root [data-theme="dark"] .kds-section-note.kds-success > i { color: var(--kds-alert-success-text); }
9297
10228
  .kds-theme-root [data-theme="dark"] .kds-section-note.kds-error,
9298
10229
  .kds-theme-root [data-theme="dark"] .kds-section-note.kds-error > i { color: var(--kds-alert-error-text); }
10230
+ .kds-theme-root [data-theme="dark"] .kds-section-note.kds-neutral { color: var(--kds-color-text-secondary); }
10231
+ .kds-theme-root [data-theme="dark"] .kds-section-note.kds-neutral > i { color: var(--primary); }
9299
10232
 
9300
10233
  /* ========================================
9301
10234
  INFO TOOLTIP (.kds-info-tip)