@donotdev/ui 0.0.9 → 0.0.10

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.
Files changed (45) hide show
  1. package/dist/crud/components/fields/display/DateFieldDisplay.d.ts.map +1 -1
  2. package/dist/crud/components/fields/display/DateFieldDisplay.js +2 -3
  3. package/dist/crud/components/fields/display/LinkFieldDisplay.d.ts.map +1 -1
  4. package/dist/crud/components/fields/display/LinkFieldDisplay.js +6 -5
  5. package/dist/crud/components/fields/display/NumberFieldDisplay.d.ts.map +1 -1
  6. package/dist/crud/components/fields/display/NumberFieldDisplay.js +2 -3
  7. package/dist/crud/components/fields/display/PhoneNumberDisplay.d.ts.map +1 -1
  8. package/dist/crud/components/fields/display/PhoneNumberDisplay.js +1 -2
  9. package/dist/dndev.css +288 -143
  10. package/dist/index.js +5 -5
  11. package/dist/internal/common/RouteErrorFallback.d.ts.map +1 -1
  12. package/dist/internal/common/RouteErrorFallback.js +1 -2
  13. package/dist/internal/layout/DnDevLayout.d.ts.map +1 -1
  14. package/dist/internal/layout/DnDevLayout.js +3 -2
  15. package/dist/internal/layout/components/footer/FooterBranding.d.ts +0 -2
  16. package/dist/internal/layout/components/footer/FooterBranding.d.ts.map +1 -1
  17. package/dist/internal/layout/components/footer/FooterBranding.js +2 -6
  18. package/dist/internal/layout/components/footer/FooterCopyright.d.ts +0 -2
  19. package/dist/internal/layout/components/footer/FooterCopyright.d.ts.map +1 -1
  20. package/dist/internal/layout/components/footer/FooterCopyright.js +2 -6
  21. package/dist/internal/layout/config/presets/moolti.js +2 -2
  22. package/dist/internal/layout/zones/DnDevFooter.d.ts.map +1 -1
  23. package/dist/internal/layout/zones/DnDevFooter.js +2 -2
  24. package/dist/routing/GoTo.d.ts +1 -1
  25. package/dist/routing/GoTo.d.ts.map +1 -1
  26. package/dist/routing/GoTo.js +1 -1
  27. package/dist/routing/hooks/hooks.next.js +1 -1
  28. package/dist/routing/hooks/hooks.vite.js +1 -1
  29. package/dist/routing/hooks/useFormNavigationBlocker.d.ts +14 -0
  30. package/dist/routing/hooks/useFormNavigationBlocker.d.ts.map +1 -0
  31. package/dist/routing/hooks/useFormNavigationBlocker.js +42 -0
  32. package/dist/routing/hooks/useNavigate.next.d.ts +1 -1
  33. package/dist/routing/hooks/useNavigate.next.d.ts.map +1 -1
  34. package/dist/routing/hooks/useNavigate.next.js +7 -1
  35. package/dist/routing/hooks/useNavigate.vite.d.ts +1 -1
  36. package/dist/routing/hooks/useNavigate.vite.d.ts.map +1 -1
  37. package/dist/routing/hooks/useNavigate.vite.js +7 -1
  38. package/dist/styles/index.css +288 -143
  39. package/dist/utils/index.d.ts +1 -0
  40. package/dist/utils/index.d.ts.map +1 -1
  41. package/dist/utils/index.js +1 -0
  42. package/dist/utils/useFormStoreSafe.d.ts +59 -0
  43. package/dist/utils/useFormStoreSafe.d.ts.map +1 -0
  44. package/dist/utils/useFormStoreSafe.js +115 -0
  45. package/package.json +5 -5
@@ -2209,6 +2209,20 @@ em {
2209
2209
  padding-inline-start: var(--gap-md);
2210
2210
  }
2211
2211
 
2212
+ /* Bare mode - no visual chrome, used inside FloatingLabel or custom wrappers */
2213
+
2214
+ [data-bare] {
2215
+ border: none !important;
2216
+ box-shadow: none !important;
2217
+ background: transparent !important;
2218
+ }
2219
+
2220
+ [data-bare]:hover,[data-bare]:focus,[data-bare]:focus-visible {
2221
+ border-color: transparent !important;
2222
+ box-shadow: none !important;
2223
+ outline: none !important;
2224
+ }
2225
+
2212
2226
  /* Password strength bar height override */
2213
2227
 
2214
2228
  .dndev-password-strength-bar {
@@ -3310,6 +3324,7 @@ em {
3310
3324
 
3311
3325
  .dndev-collapsible-content[data-state='open'] {
3312
3326
  animation: slideDown var(--dur-normal) var(--ease-in-out);
3327
+ overflow: visible; /* Allow dropdowns/overlays to escape when open */
3313
3328
  }
3314
3329
 
3315
3330
  .dndev-collapsible-content[data-state='closed'] {
@@ -4442,6 +4457,18 @@ em {
4442
4457
 
4443
4458
  /* packages/components/src/atomic/Input/Input.css */
4444
4459
 
4460
+ /* Hide number input spinners - cleaner UI for price/range inputs */
4461
+
4462
+ input[type='number']::-webkit-inner-spin-button,
4463
+ input[type='number']::-webkit-outer-spin-button {
4464
+ -webkit-appearance: none;
4465
+ margin: 0;
4466
+ }
4467
+
4468
+ input[type='number'] {
4469
+ -moz-appearance: textfield;
4470
+ }
4471
+
4445
4472
  /* Input with leading icon (search, etc.) */
4446
4473
 
4447
4474
  .dndev-input-with-leading-icon {
@@ -4651,6 +4678,9 @@ em {
4651
4678
  background-color: transparent;
4652
4679
  transition: all var(--dur-normal) var(--ease-in-out);
4653
4680
  text-align: start;
4681
+ /* Flex-aware: allow fieldset to shrink in flex containers */
4682
+ min-width: 0;
4683
+ width: 100%;
4654
4684
  }
4655
4685
 
4656
4686
  .dndev-floating-fieldset:hover {
@@ -4659,7 +4689,6 @@ em {
4659
4689
 
4660
4690
  .dndev-floating-fieldset:focus-within {
4661
4691
  border-color: var(--ring);
4662
- box-shadow: 0 0 0 2px var(--ring);
4663
4692
  }
4664
4693
 
4665
4694
  .dndev-floating-fieldset[data-disabled='true'] {
@@ -4676,6 +4705,11 @@ em {
4676
4705
  font-weight: 500;
4677
4706
  line-height: 1;
4678
4707
  color: var(--foreground);
4708
+ /* Ellipsis by default */
4709
+ max-width: 100%;
4710
+ overflow: hidden;
4711
+ text-overflow: ellipsis;
4712
+ white-space: nowrap;
4679
4713
  }
4680
4714
 
4681
4715
  .dndev-floating-legend label {
@@ -4689,30 +4723,23 @@ em {
4689
4723
  color: var(--muted-foreground);
4690
4724
  }
4691
4725
 
4692
- .dndev-floating-legend[data-truncate='true'] {
4693
- max-width: calc(100% - var(--gap-md) * 2);
4694
- overflow: hidden;
4695
- text-overflow: ellipsis;
4696
- white-space: nowrap;
4697
- }
4698
-
4699
- /* Remove border from inner input since fieldset has it */
4726
+ /* Disable truncation when explicitly set to false */
4700
4727
 
4701
- .dndev-floating-fieldset .dndev-input {
4702
- border: none;
4703
- border-radius: var(--radius-interactive);
4704
- box-shadow: none;
4728
+ .dndev-floating-legend[data-truncate='false'] {
4729
+ max-width: none;
4730
+ overflow: visible;
4731
+ text-overflow: clip;
4732
+ white-space: normal;
4705
4733
  }
4706
4734
 
4707
- .dndev-floating-fieldset .dndev-input:hover {
4708
- border-color: transparent;
4709
- }
4735
+ /* Input inside fieldset uses bare mode via data-bare attribute (set by Input component) */
4710
4736
 
4711
- .dndev-floating-fieldset .dndev-input:focus,
4712
- .dndev-floating-fieldset .dndev-input:focus-visible {
4713
- border-color: transparent;
4737
+ /* This rule is kept for non-Input children that might need border removal */
4738
+
4739
+ .dndev-floating-fieldset > .dndev-input:not([data-bare]) {
4740
+ border: none;
4714
4741
  box-shadow: none;
4715
- outline: none;
4742
+ background: transparent;
4716
4743
  }
4717
4744
 
4718
4745
  /* packages/components/src/atomic/List/List.css */
@@ -5063,11 +5090,33 @@ em {
5063
5090
  /* packages/components/src/atomic/Pagination/Pagination.css */
5064
5091
 
5065
5092
  .dndev-pagination {
5093
+ display: flex;
5094
+ flex-direction: row;
5095
+ align-items: center;
5096
+ justify-content: space-between;
5097
+ gap: var(--gap-md);
5098
+ width: 100%;
5099
+ }
5100
+
5101
+ .dndev-pagination-info {
5102
+ display: none;
5103
+ }
5104
+
5105
+ .dndev-pagination-size {
5106
+ display: flex;
5107
+ align-items: center;
5108
+ }
5109
+
5110
+ .dndev-pagination-size-label {
5111
+ display: none;
5112
+ }
5113
+
5114
+ .dndev-pagination-nav {
5066
5115
  display: flex;
5067
5116
  align-items: center;
5068
5117
  justify-content: center;
5069
5118
  gap: var(--gap-sm);
5070
- flex-wrap: wrap;
5119
+ width: 100%;
5071
5120
  }
5072
5121
 
5073
5122
  .dndev-pagination-list {
@@ -5079,57 +5128,36 @@ em {
5079
5128
  margin: 0;
5080
5129
  }
5081
5130
 
5082
- .dndev-pagination-item {
5083
- display: flex;
5084
- align-items: center;
5085
- justify-content: center;
5086
- }
5087
-
5088
5131
  .dndev-pagination-button {
5089
- min-width: var(--touch-target);
5132
+ width: var(--touch-target);
5090
5133
  height: var(--touch-target);
5091
- display: flex;
5134
+ padding: 0;
5135
+ flex-shrink: 0;
5136
+ display: inline-flex;
5092
5137
  align-items: center;
5093
5138
  justify-content: center;
5094
- gap: var(--gap-sm);
5095
- border-radius: var(--radius-interactive);
5096
- font-weight: 500;
5097
- transition: var(--transition-fast);
5098
- cursor: pointer;
5099
- border: var(--border-hairline) solid var(--line-2);
5100
- background: transparent;
5101
- color: var(--foreground);
5102
- padding: var(--gap-sm) var(--gap-md);
5103
5139
  }
5104
5140
 
5105
- .dndev-pagination-button:hover:not(:disabled) {
5106
- background: var(--accent);
5107
- color: var(--accent-foreground);
5108
- }
5141
+ /* Desktop: Show all elements in one row */
5109
5142
 
5110
- .dndev-pagination-button:focus-visible {
5111
- outline: 2px solid var(--ring);
5112
- outline-offset: 2px;
5143
+ @media (min-width: 768px) {
5144
+ .dndev-pagination-info,
5145
+ .dndev-pagination-size {
5146
+ display: flex;
5147
+ align-items: center;
5148
+ white-space: nowrap;
5113
5149
  }
5114
5150
 
5115
- .dndev-pagination-button:disabled {
5116
- opacity: var(--opacity-muted);
5117
- cursor: not-allowed;
5151
+ .dndev-pagination-size-label {
5152
+ margin-right: var(--gap-sm);
5118
5153
  }
5119
5154
 
5120
- .dndev-pagination-button[aria-current='page'] {
5121
- background: var(--primary);
5122
- color: var(--primary-foreground);
5123
- border-color: var(--primary);
5155
+ .dndev-pagination-nav {
5156
+ justify-content: flex-end;
5157
+ width: auto;
5158
+ margin-left: auto;
5159
+ /* Push to right */
5124
5160
  }
5125
-
5126
- .dndev-pagination-ellipsis {
5127
- display: flex;
5128
- align-items: center;
5129
- justify-content: center;
5130
- width: var(--touch-target);
5131
- height: var(--touch-target);
5132
- color: var(--muted-foreground);
5133
5161
  }
5134
5162
 
5135
5163
  /* packages/components/src/atomic/Popover/Popover.css */
@@ -5860,8 +5888,12 @@ em {
5860
5888
 
5861
5889
  /* Adjust header padding when drag handle is present (sibling selector) */
5862
5890
 
5863
- .dndev-sheet-content[data-side='bottom'] .dndev-sheet-drag-handle ~ .dndev-sheet-header,
5864
- .dndev-sheet-content[data-side='top'] .dndev-sheet-drag-handle ~ .dndev-sheet-header {
5891
+ .dndev-sheet-content[data-side='bottom']
5892
+ .dndev-sheet-drag-handle
5893
+ ~ .dndev-sheet-header,
5894
+ .dndev-sheet-content[data-side='top']
5895
+ .dndev-sheet-drag-handle
5896
+ ~ .dndev-sheet-header {
5865
5897
  padding-top: 0;
5866
5898
  }
5867
5899
 
@@ -5919,12 +5951,9 @@ em {
5919
5951
  position: relative;
5920
5952
  margin-inline-start: auto;
5921
5953
  /* Push to end (RTL-aware: end = right in LTR, left in RTL) */
5954
+ margin-inline-end: var(--gap-sm);
5955
+ /* Spacing from edge - use margin not padding to keep icon centered */
5922
5956
  opacity: var(--opacity-muted);
5923
- /* No padding - tight spacing */
5924
- padding: 0;
5925
- /* RTL-aware: padding on logical end only */
5926
- padding-inline-end: var(--gap-md);
5927
- padding-inline-start: 0;
5928
5957
  }
5929
5958
 
5930
5959
  .dndev-sheet-close:hover {
@@ -6709,7 +6738,21 @@ em {
6709
6738
  }
6710
6739
 
6711
6740
  .dndev-table-header {
6712
- /* Base header styles */
6741
+ background-color: var(--accent);
6742
+ }
6743
+
6744
+ /* Filter row above header */
6745
+
6746
+ .dndev-table-filter-row {
6747
+ border: 1px solid var(--border);
6748
+ border-bottom: none;
6749
+ }
6750
+
6751
+ .dndev-table-filter-row .dndev-table-head {
6752
+ background-color: var(--muted);
6753
+ padding: var(--gap-xs);
6754
+ height: auto;
6755
+ min-height: auto;
6713
6756
  }
6714
6757
 
6715
6758
  .dndev-table-body {
@@ -6771,22 +6814,34 @@ em {
6771
6814
  padding-block: var(--gap-sm);
6772
6815
  }
6773
6816
 
6774
- .dndev-table-head[data-sortable='true'] {
6817
+ /* Header cells use accent foreground for contrast */
6818
+
6819
+ .dndev-table-header .dndev-table-head {
6820
+ color: var(--accent-foreground);
6821
+ }
6822
+
6823
+ [data-sortable='true']:is(.dndev-table-header .dndev-table-head) {
6775
6824
  cursor: pointer;
6776
6825
  }
6777
6826
 
6778
- .dndev-table-head[data-align='center'] {
6827
+ [data-align='center']:is(.dndev-table-header .dndev-table-head) {
6779
6828
  text-align: center;
6780
6829
  }
6781
6830
 
6782
- .dndev-table-head[data-align='end'] {
6831
+ [data-align='end']:is(.dndev-table-header .dndev-table-head) {
6783
6832
  text-align: end;
6784
6833
  }
6785
6834
 
6786
- .dndev-table-head[data-align='start'] {
6835
+ [data-align='start']:is(.dndev-table-header .dndev-table-head) {
6787
6836
  text-align: start;
6788
6837
  }
6789
6838
 
6839
+ /* Active filter indicator */
6840
+
6841
+ .dndev-table-filter-active {
6842
+ color: var(--primary);
6843
+ }
6844
+
6790
6845
  /* Table cell (td) styles */
6791
6846
 
6792
6847
  .dndev-table-cell {
@@ -6794,6 +6849,7 @@ em {
6794
6849
  padding-inline: var(--gap-md);
6795
6850
  padding-block: var(--gap-sm);
6796
6851
  min-height: var(--touch-target);
6852
+ line-height: 1.5; /* Ensure consistent line height for empty cells */
6797
6853
  }
6798
6854
 
6799
6855
  .dndev-table-cell[data-align='center'] {
@@ -6872,6 +6928,64 @@ em {
6872
6928
  padding-inline-start: calc(var(--gap-md) + var(--icon-md) + var(--gap-sm));
6873
6929
  }
6874
6930
 
6931
+ /* Skeleton rows - apply standard skeleton pulse animation to entire rows */
6932
+
6933
+ /* Keep existing background colors (zebra striping) - just add opacity pulse */
6934
+
6935
+ .dndev-table-body .dndev-table-row.dndev-skeleton-row {
6936
+ animation: dndev-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
6937
+ pointer-events: none;
6938
+
6939
+ /* Keep hover state but disabled (pointer-events: none prevents hover) */
6940
+ }
6941
+
6942
+ :is(.dndev-table-body .dndev-table-row.dndev-skeleton-row):hover {
6943
+ /* Inherit from parent .dndev-table-row hover styles */
6944
+ }
6945
+
6946
+ /* Even rows keep their var(--muted) background, just pulse */
6947
+
6948
+ .dndev-table-body .dndev-table-row.dndev-skeleton-row:nth-child(even) {
6949
+ animation: dndev-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
6950
+ }
6951
+
6952
+ :is(.dndev-table-body .dndev-table-row.dndev-skeleton-row:nth-child(even)):hover {
6953
+ /* Inherit from parent .dndev-table-row:nth-child(even) hover styles */
6954
+ }
6955
+
6956
+ /* Skeleton bars inside cells - adapt to row background for visibility */
6957
+
6958
+ /* Odd rows (transparent background): use default var(--muted) skeleton */
6959
+
6960
+ /* Even rows (var(--muted) background): use lighter skeleton for contrast */
6961
+
6962
+ .dndev-table-body .dndev-table-row.dndev-skeleton-row .dndev-skeleton {
6963
+ background-color: var(--muted);
6964
+ }
6965
+
6966
+ .dndev-table-body
6967
+ .dndev-table-row.dndev-skeleton-row:nth-child(even)
6968
+ .dndev-skeleton {
6969
+ /* Even rows have var(--muted) background, so skeleton should be lighter for contrast */
6970
+ background-color: color-mix(
6971
+ in oklab,
6972
+ var(--muted) 60%,
6973
+ var(--foreground) 40%
6974
+ );
6975
+ }
6976
+
6977
+ /* Use the same pulse animation as standard skeleton (from Skeleton.css) */
6978
+
6979
+ @keyframes dndev-pulse {
6980
+ 0%,
6981
+ 100% {
6982
+ opacity: 1;
6983
+ }
6984
+ 50% {
6985
+ opacity: var(--opacity-muted);
6986
+ }
6987
+ }
6988
+
6875
6989
  /* packages/components/src/atomic/Tabs/Tabs.css */
6876
6990
 
6877
6991
  /* Tabs list: use flexbox for natural wrapping, not grid */
@@ -8811,6 +8925,7 @@ h4[data-variant='code'] {
8811
8925
  from {
8812
8926
  opacity: 1;
8813
8927
  }
8928
+
8814
8929
  to {
8815
8930
  opacity: 0;
8816
8931
  }
@@ -8820,6 +8935,7 @@ h4[data-variant='code'] {
8820
8935
  from {
8821
8936
  opacity: 0;
8822
8937
  }
8938
+
8823
8939
  to {
8824
8940
  opacity: 1;
8825
8941
  }
@@ -8832,6 +8948,7 @@ h4[data-variant='code'] {
8832
8948
  opacity: 1;
8833
8949
  transform: translateX(0);
8834
8950
  }
8951
+
8835
8952
  to {
8836
8953
  opacity: 0;
8837
8954
  transform: translateX(-100%);
@@ -8843,6 +8960,7 @@ h4[data-variant='code'] {
8843
8960
  opacity: 0;
8844
8961
  transform: translateX(100%);
8845
8962
  }
8963
+
8846
8964
  to {
8847
8965
  opacity: 1;
8848
8966
  transform: translateX(0);
@@ -8917,7 +9035,7 @@ main[role='main'][data-routing-animation='none'] {
8917
9035
 
8918
9036
  /* Tablet (768px - 1023px) */
8919
9037
 
8920
- @media (width >= 768px) and (width <= 1023px) {
9038
+ @media (width >=768px) and (width <=1023px) {
8921
9039
  main[role='main'][data-routing-animation='fade'] {
8922
9040
  animation: routeFadeIn
8923
9041
  var(--routing-tablet-duration, var(--routing-default-duration, 300ms))
@@ -8933,7 +9051,7 @@ main[role='main'][data-routing-animation='none'] {
8933
9051
 
8934
9052
  /* Desktop (1024px - 1439px) */
8935
9053
 
8936
- @media (width >= 1024px) and (width <= 1439px) {
9054
+ @media (width >=1024px) and (width <=1439px) {
8937
9055
  main[role='main'][data-routing-animation='fade'] {
8938
9056
  animation: routeFadeIn
8939
9057
  var(--routing-desktop-duration, var(--routing-default-duration, 300ms))
@@ -8949,7 +9067,7 @@ main[role='main'][data-routing-animation='none'] {
8949
9067
 
8950
9068
  /* Wide (>= 1440px) */
8951
9069
 
8952
- @media (width >= 1440px) {
9070
+ @media (width >=1440px) {
8953
9071
  main[role='main'][data-routing-animation='fade'] {
8954
9072
  animation: routeFadeIn
8955
9073
  var(--routing-wide-duration, var(--routing-default-duration, 300ms))
@@ -8982,7 +9100,7 @@ main[role='main'][data-routing-animation='none'] {
8982
9100
 
8983
9101
  /* Mobile/Tablet: Hide sidebars - WCAG & Lighthouse best practices */
8984
9102
 
8985
- @media (width <= 1023px) {
9103
+ @media (width <=1023px) {
8986
9104
  .dndev-layout aside[role='navigation'].sidebar,
8987
9105
  aside[role='navigation'].sidebar {
8988
9106
  display: none !important;
@@ -9012,59 +9130,55 @@ main[role='main'][data-routing-animation='none'] {
9012
9130
  );
9013
9131
  grid-template-columns: var(--sidebar-width) 1fr;
9014
9132
 
9015
- /* Mobile: No footer grid row - footer is inside main */
9016
- /* When mergedBar is shown, header is hidden but grid still needs space for mergedBar */
9133
+ /* Mobile: Grid scrolls instead of main - footer scrolls with content */
9017
9134
  }
9018
9135
 
9019
- @media (width <= 1023px) {
9136
+ @media (width <=1023px) {
9020
9137
 
9021
9138
  .dndev-layout {
9139
+ overflow-y: auto;
9140
+ overflow-x: hidden;
9141
+ /* Keep footer row - grid scrolls so footer scrolls with content */
9022
9142
  grid-template-areas:
9023
9143
  'header header'
9024
- 'sidebar main';
9025
- grid-template-rows: var(--header-height) 1fr;
9026
-
9027
- /* Presets with mergedBar: header is hidden, but grid still allocates space for mergedBar */
9028
- /* No extra padding needed - grid spacing is sufficient */
9144
+ 'sidebar main'
9145
+ 'footer footer';
9146
+ grid-template-rows: var(--header-height) min-content auto;
9029
9147
  }
9030
- .dndev-layout[data-layout='admin'],.dndev-layout[data-layout='moolti'],.dndev-layout[data-layout='game'],.dndev-layout[data-layout='docs'] {
9031
- /* Grid already accounts for header-height, mergedBar is fixed and doesn't need extra padding */
9032
- }
9033
9148
  }
9034
9149
 
9035
- /* Footer containers: show/hide based on breakpoint */
9150
+ /* Footer scroll mode - grid scrolls, footer scrolls with content (opt-in for desktop) */
9036
9151
 
9037
- .footer-mobile {
9038
- display: none;
9039
- /* No margin-top: auto - footer scrolls with content on mobile */
9040
- /* No flex-shrink: 0 - footer is in normal flow, not stuck at bottom */
9152
+ .dndev-layout[data-footer-mode='scroll'] {
9153
+ overflow-y: auto;
9154
+ overflow-x: hidden;
9155
+ grid-template-rows: var(--header-height) min-content auto;
9041
9156
  }
9042
9157
 
9043
- .footer-desktop {
9044
- display: contents; /* Children (footer element) participate in grid */
9158
+ .dndev-layout[data-footer-mode='scroll'] header[role='banner'] {
9159
+ position: sticky;
9160
+ top: 0;
9045
9161
  }
9046
9162
 
9047
- @media (width <= 1023px) {
9048
- .footer-mobile {
9049
- display: block;
9050
- }
9163
+ .dndev-layout[data-footer-mode='scroll'] main[role='main'] {
9164
+ overflow: visible;
9165
+ min-height: -moz-min-content;
9166
+ min-height: min-content;
9167
+ }
9051
9168
 
9052
- .footer-desktop {
9053
- display: none;
9054
- }
9169
+ .dndev-layout[data-footer-mode='scroll'] footer[role='contentinfo'] {
9170
+ height: auto;
9171
+ }
9055
9172
 
9056
- /* Game: No mobile footer - navigation in MergedBar */
9057
- [data-layout='game'] .footer-mobile {
9058
- display: none;
9173
+ :is(.dndev-layout[data-footer-mode='scroll'] footer[role='contentinfo']) > * {
9174
+ height: auto;
9175
+ min-height: var(--footer-height);
9059
9176
  }
9060
- }
9061
9177
 
9062
9178
  /* Presets with no footer at all */
9063
9179
 
9064
- [data-layout='moolti'] .footer-mobile,
9065
- [data-layout='moolti'] .footer-desktop,
9066
- [data-layout='plain'] .footer-mobile,
9067
- [data-layout='plain'] .footer-desktop {
9180
+ [data-layout='moolti'] footer[role='contentinfo'],
9181
+ [data-layout='plain'] footer[role='contentinfo'] {
9068
9182
  display: none;
9069
9183
  }
9070
9184
 
@@ -9102,7 +9216,17 @@ header[role='banner'] {
9102
9216
  /* Theme-aware styling - 100% controlled by theme system */
9103
9217
  background: var(--background);
9104
9218
  border-bottom: var(--border-hairline) solid var(--border);
9219
+
9220
+ /* Mobile: Sticky header (for presets that keep header visible) */
9221
+ }
9222
+
9223
+ @media (width <=1023px) {
9224
+
9225
+ header[role='banner'] {
9226
+ position: sticky;
9227
+ top: 0;
9105
9228
  }
9229
+ }
9106
9230
 
9107
9231
  .header-start {
9108
9232
  display: flex;
@@ -9157,19 +9281,20 @@ header[role='banner'] .header-center {
9157
9281
  aside[role='navigation'].sidebar {
9158
9282
  grid-area: sidebar;
9159
9283
  box-sizing: border-box;
9160
- min-width: calc(
9161
- var(--sidebar-resize-handle-width) + 48px
9162
- ); /* Min: 48px content + 6px handle = 54px */
9163
- max-width: calc(
9164
- var(--sidebar-resize-handle-width) + 400px
9165
- ); /* Max: 400px content + 6px handle = 406px */
9284
+ min-width: calc(var(--sidebar-resize-handle-width) + 48px);
9285
+ /* Min: 48px content + 6px handle = 54px */
9286
+ max-width: calc(var(--sidebar-resize-handle-width) + 400px);
9287
+ /* Max: 400px content + 6px handle = 406px */
9166
9288
  z-index: var(--z-sidebar);
9167
- overflow: none; /* No clipping needed - handle is in grid */
9289
+ overflow: none;
9290
+ /* No clipping needed - handle is in grid */
9168
9291
  contain: layout style;
9169
9292
  padding: 0;
9170
9293
  display: grid;
9171
- grid-template-columns: auto var(--sidebar-resize-handle-width); /* Content | Handle - column 1 width set inline */
9172
- grid-template-rows: auto 1fr auto; /* Top | Content | Bottom */
9294
+ grid-template-columns: auto var(--sidebar-resize-handle-width);
9295
+ /* Content | Handle - column 1 width set inline */
9296
+ grid-template-rows: auto 1fr auto;
9297
+ /* Top | Content | Bottom */
9173
9298
  height: 100%;
9174
9299
 
9175
9300
  /* Theme-aware styling - 100% controlled by theme system */
@@ -9224,7 +9349,8 @@ aside[role='navigation'].sidebar[data-dragging='true']
9224
9349
 
9225
9350
  @media (hover: none) {
9226
9351
  aside[role='navigation'].sidebar .dndev-sidebar-resize-handle {
9227
- width: calc(var(--sidebar-resize-handle-width) * 2); /* 12px for touch */
9352
+ width: calc(var(--sidebar-resize-handle-width) * 2);
9353
+ /* 12px for touch */
9228
9354
  }
9229
9355
  }
9230
9356
 
@@ -9293,7 +9419,8 @@ aside[role='navigation'].sidebar[data-dragging='true']
9293
9419
  .sidebar-content .dndev-interactive[data-role='menu-item'],.sidebar-content .dndev-interactive[data-role='nav-trigger'] {
9294
9420
  height: var(--touch-target);
9295
9421
  min-height: var(--touch-target);
9296
- padding-block: 0; /* No vertical padding - buttons fill exact 48px */
9422
+ padding-block: 0;
9423
+ /* No vertical padding - buttons fill exact 48px */
9297
9424
  }
9298
9425
 
9299
9426
  /* Other interactive elements (not menu items) - consistent padding */
@@ -9333,7 +9460,8 @@ aside.sidebar[role='navigation'] .sidebar-top,aside.sidebar[role='navigation'] .
9333
9460
  }
9334
9461
 
9335
9462
  aside.sidebar[role='navigation'] .sidebar-content {
9336
- overflow-x: hidden; /* Prevent horizontal scroll, allow vertical */
9463
+ overflow-x: hidden;
9464
+ /* Prevent horizontal scroll, allow vertical */
9337
9465
  }
9338
9466
 
9339
9467
  aside.sidebar[role='navigation'] .dndev-interactive {
@@ -9398,12 +9526,9 @@ aside.sidebar[role='navigation'][data-collapsed='true'] .app-branding {
9398
9526
  main[role='main'] {
9399
9527
  grid-area: main;
9400
9528
  overflow-y: auto;
9401
- /* Default: allow scrolling */
9402
9529
  overflow-x: hidden;
9403
- /* Prevent horizontal scroll from breakthrough components */
9404
9530
  display: flex;
9405
9531
  flex-direction: column;
9406
- /* No automatic padding; spacing handled by gaps */
9407
9532
  padding: 0;
9408
9533
  contain: layout style;
9409
9534
 
@@ -9412,19 +9537,18 @@ main[role='main'] {
9412
9537
 
9413
9538
  main[role='main'] > *:not(.breadcrumbs-container):first-of-type,main[role='main'] > .breadcrumbs-container + * {
9414
9539
  flex: 1 1 auto;
9415
- /* Page content grows */
9416
9540
  }
9417
9541
 
9418
- /* Desktop: Footer stays at bottom of viewport */
9542
+ /* Mobile: Grid scrolls, main doesn't */
9419
9543
 
9420
- @media (width > 1023px) {
9421
- main[role='main'] > *:last-child {
9422
- flex-shrink: 0;
9423
- /* Footer stays at bottom */
9424
- }
9425
- }
9544
+ @media (width <=1023px) {
9426
9545
 
9427
- /* Mobile: Footer scrolls with content (no flex-shrink needed) */
9546
+ main[role='main'] {
9547
+ overflow: visible;
9548
+ min-height: -moz-min-content;
9549
+ min-height: min-content;
9550
+ }
9551
+ }
9428
9552
 
9429
9553
  /* Footer: Full width by default, app presets start after sidebar */
9430
9554
 
@@ -9458,11 +9582,25 @@ footer[role='contentinfo'] > * {
9458
9582
  padding-inline-end: var(--content-padding);
9459
9583
  }
9460
9584
 
9585
+ /* Mobile: Allow footer to grow when content wraps */
9586
+
9587
+ @media (width <=1023px) {
9588
+
9589
+ footer[role='contentinfo'] {
9590
+ height: auto;
9591
+ }
9592
+
9593
+ footer[role='contentinfo'] > * {
9594
+ height: auto;
9595
+ min-height: var(--footer-height);
9596
+ }
9597
+ }
9598
+
9461
9599
  /* Footer text styles */
9462
9600
 
9463
9601
  footer[role='contentinfo'] .footer-copyright {
9464
9602
  color: var(--muted-foreground);
9465
- font-size: var(--font-size-sm);
9603
+ font-size: var(--font-size-xs);
9466
9604
  }
9467
9605
 
9468
9606
  footer[role='contentinfo'] a:not(.dndev-interactive) {
@@ -9532,7 +9670,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9532
9670
 
9533
9671
  /* Mobile (<1024px): Show merged-bar, hide zones */
9534
9672
 
9535
- @media (width <= 1023px) {
9673
+ @media (width <=1023px) {
9536
9674
  /* Presets with mergedBar: top (admin, moolti, game, docs) */
9537
9675
  [data-layout='admin'] .merged-bar[data-position='top'],
9538
9676
  [data-layout='moolti'] .merged-bar[data-position='top'],
@@ -9572,7 +9710,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9572
9710
 
9573
9711
  /* Desktop (>=1024px): Always hide merged-bar */
9574
9712
 
9575
- @media (width >= 1024px) {
9713
+ @media (width >=1024px) {
9576
9714
  .merged-bar {
9577
9715
  display: none !important;
9578
9716
  }
@@ -9596,7 +9734,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9596
9734
  /* Admin: Mobile/Tablet (<1024px) - only overrides */
9597
9735
  }
9598
9736
 
9599
- @media (width <= 1023px) {
9737
+ @media (width <=1023px) {
9600
9738
 
9601
9739
  [data-layout='admin'] {
9602
9740
  --sidebar-width: 0px;
@@ -9627,7 +9765,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9627
9765
 
9628
9766
  /* Moolti: Mobile/Tablet (<1024px) - only overrides */
9629
9767
 
9630
- @media (width <= 1023px) {
9768
+ @media (width <=1023px) {
9631
9769
 
9632
9770
  [data-layout='moolti'] {
9633
9771
  --header-height: 62px;
@@ -9654,7 +9792,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9654
9792
 
9655
9793
  /* Docs: Mobile/Tablet (<1024px) - only overrides */
9656
9794
 
9657
- @media (width <= 1023px) {
9795
+ @media (width <=1023px) {
9658
9796
 
9659
9797
  [data-layout='docs'] {
9660
9798
  --sidebar-width: 0px;
@@ -9680,7 +9818,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9680
9818
  /* Blog: Mobile/Tablet (<1024px) - only overrides */
9681
9819
  }
9682
9820
 
9683
- @media (width <= 1023px) {
9821
+ @media (width <=1023px) {
9684
9822
 
9685
9823
  [data-layout='blog'] {
9686
9824
  --header-height: 0px;
@@ -9730,7 +9868,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9730
9868
  /* Game: Mobile/Tablet (<1024px) - only overrides */
9731
9869
  }
9732
9870
 
9733
- @media (width <= 1023px) {
9871
+ @media (width <=1023px) {
9734
9872
 
9735
9873
  [data-layout='game'] {
9736
9874
  --footer-height: 0px;
@@ -9851,7 +9989,14 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9851
9989
  padding-top: var(--gap-lg);
9852
9990
  }
9853
9991
 
9992
+ /* First Section child gets gap-md spacing from top */
9993
+
9994
+ .dndev-container > .dndev-section-full-width:first-child {
9995
+ margin-top: var(--gap-md);
9996
+ }
9997
+
9854
9998
  .dndev-container {
9999
+
9855
10000
  min-height: 0;
9856
10001
  display: flex;
9857
10002
  flex-direction: column;
@@ -9886,7 +10031,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9886
10031
  --max-content-width: 100%;
9887
10032
  }
9888
10033
 
9889
- @media (width >= 1024px) {
10034
+ @media (width >=1024px) {
9890
10035
 
9891
10036
  .dndev-container[data-variant='standard'] {
9892
10037
  --max-content-width: 87.5rem;
@@ -9901,7 +10046,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9901
10046
  --max-content-width: 100%;
9902
10047
  }
9903
10048
 
9904
- @media (width >= 1024px) {
10049
+ @media (width >=1024px) {
9905
10050
 
9906
10051
  .dndev-container[data-variant='docs'] {
9907
10052
  --max-content-width: 56.25rem;