@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
package/dist/dndev.css CHANGED
@@ -2213,6 +2213,20 @@ em {
2213
2213
  padding-inline-start: var(--gap-md);
2214
2214
  }
2215
2215
 
2216
+ /* Bare mode - no visual chrome, used inside FloatingLabel or custom wrappers */
2217
+
2218
+ [data-bare] {
2219
+ border: none !important;
2220
+ box-shadow: none !important;
2221
+ background: transparent !important;
2222
+ }
2223
+
2224
+ [data-bare]:hover,[data-bare]:focus,[data-bare]:focus-visible {
2225
+ border-color: transparent !important;
2226
+ box-shadow: none !important;
2227
+ outline: none !important;
2228
+ }
2229
+
2216
2230
  /* Password strength bar height override */
2217
2231
 
2218
2232
  .dndev-password-strength-bar {
@@ -3314,6 +3328,7 @@ em {
3314
3328
 
3315
3329
  .dndev-collapsible-content[data-state='open'] {
3316
3330
  animation: slideDown var(--dur-normal) var(--ease-in-out);
3331
+ overflow: visible; /* Allow dropdowns/overlays to escape when open */
3317
3332
  }
3318
3333
 
3319
3334
  .dndev-collapsible-content[data-state='closed'] {
@@ -4446,6 +4461,18 @@ em {
4446
4461
 
4447
4462
  /* packages/components/src/atomic/Input/Input.css */
4448
4463
 
4464
+ /* Hide number input spinners - cleaner UI for price/range inputs */
4465
+
4466
+ input[type='number']::-webkit-inner-spin-button,
4467
+ input[type='number']::-webkit-outer-spin-button {
4468
+ -webkit-appearance: none;
4469
+ margin: 0;
4470
+ }
4471
+
4472
+ input[type='number'] {
4473
+ -moz-appearance: textfield;
4474
+ }
4475
+
4449
4476
  /* Input with leading icon (search, etc.) */
4450
4477
 
4451
4478
  .dndev-input-with-leading-icon {
@@ -4655,6 +4682,9 @@ em {
4655
4682
  background-color: transparent;
4656
4683
  transition: all var(--dur-normal) var(--ease-in-out);
4657
4684
  text-align: start;
4685
+ /* Flex-aware: allow fieldset to shrink in flex containers */
4686
+ min-width: 0;
4687
+ width: 100%;
4658
4688
  }
4659
4689
 
4660
4690
  .dndev-floating-fieldset:hover {
@@ -4663,7 +4693,6 @@ em {
4663
4693
 
4664
4694
  .dndev-floating-fieldset:focus-within {
4665
4695
  border-color: var(--ring);
4666
- box-shadow: 0 0 0 2px var(--ring);
4667
4696
  }
4668
4697
 
4669
4698
  .dndev-floating-fieldset[data-disabled='true'] {
@@ -4680,6 +4709,11 @@ em {
4680
4709
  font-weight: 500;
4681
4710
  line-height: 1;
4682
4711
  color: var(--foreground);
4712
+ /* Ellipsis by default */
4713
+ max-width: 100%;
4714
+ overflow: hidden;
4715
+ text-overflow: ellipsis;
4716
+ white-space: nowrap;
4683
4717
  }
4684
4718
 
4685
4719
  .dndev-floating-legend label {
@@ -4693,30 +4727,23 @@ em {
4693
4727
  color: var(--muted-foreground);
4694
4728
  }
4695
4729
 
4696
- .dndev-floating-legend[data-truncate='true'] {
4697
- max-width: calc(100% - var(--gap-md) * 2);
4698
- overflow: hidden;
4699
- text-overflow: ellipsis;
4700
- white-space: nowrap;
4701
- }
4702
-
4703
- /* Remove border from inner input since fieldset has it */
4730
+ /* Disable truncation when explicitly set to false */
4704
4731
 
4705
- .dndev-floating-fieldset .dndev-input {
4706
- border: none;
4707
- border-radius: var(--radius-interactive);
4708
- box-shadow: none;
4732
+ .dndev-floating-legend[data-truncate='false'] {
4733
+ max-width: none;
4734
+ overflow: visible;
4735
+ text-overflow: clip;
4736
+ white-space: normal;
4709
4737
  }
4710
4738
 
4711
- .dndev-floating-fieldset .dndev-input:hover {
4712
- border-color: transparent;
4713
- }
4739
+ /* Input inside fieldset uses bare mode via data-bare attribute (set by Input component) */
4714
4740
 
4715
- .dndev-floating-fieldset .dndev-input:focus,
4716
- .dndev-floating-fieldset .dndev-input:focus-visible {
4717
- border-color: transparent;
4741
+ /* This rule is kept for non-Input children that might need border removal */
4742
+
4743
+ .dndev-floating-fieldset > .dndev-input:not([data-bare]) {
4744
+ border: none;
4718
4745
  box-shadow: none;
4719
- outline: none;
4746
+ background: transparent;
4720
4747
  }
4721
4748
 
4722
4749
  /* packages/components/src/atomic/List/List.css */
@@ -5067,11 +5094,33 @@ em {
5067
5094
  /* packages/components/src/atomic/Pagination/Pagination.css */
5068
5095
 
5069
5096
  .dndev-pagination {
5097
+ display: flex;
5098
+ flex-direction: row;
5099
+ align-items: center;
5100
+ justify-content: space-between;
5101
+ gap: var(--gap-md);
5102
+ width: 100%;
5103
+ }
5104
+
5105
+ .dndev-pagination-info {
5106
+ display: none;
5107
+ }
5108
+
5109
+ .dndev-pagination-size {
5110
+ display: flex;
5111
+ align-items: center;
5112
+ }
5113
+
5114
+ .dndev-pagination-size-label {
5115
+ display: none;
5116
+ }
5117
+
5118
+ .dndev-pagination-nav {
5070
5119
  display: flex;
5071
5120
  align-items: center;
5072
5121
  justify-content: center;
5073
5122
  gap: var(--gap-sm);
5074
- flex-wrap: wrap;
5123
+ width: 100%;
5075
5124
  }
5076
5125
 
5077
5126
  .dndev-pagination-list {
@@ -5083,57 +5132,36 @@ em {
5083
5132
  margin: 0;
5084
5133
  }
5085
5134
 
5086
- .dndev-pagination-item {
5087
- display: flex;
5088
- align-items: center;
5089
- justify-content: center;
5090
- }
5091
-
5092
5135
  .dndev-pagination-button {
5093
- min-width: var(--touch-target);
5136
+ width: var(--touch-target);
5094
5137
  height: var(--touch-target);
5095
- display: flex;
5138
+ padding: 0;
5139
+ flex-shrink: 0;
5140
+ display: inline-flex;
5096
5141
  align-items: center;
5097
5142
  justify-content: center;
5098
- gap: var(--gap-sm);
5099
- border-radius: var(--radius-interactive);
5100
- font-weight: 500;
5101
- transition: var(--transition-fast);
5102
- cursor: pointer;
5103
- border: var(--border-hairline) solid var(--line-2);
5104
- background: transparent;
5105
- color: var(--foreground);
5106
- padding: var(--gap-sm) var(--gap-md);
5107
5143
  }
5108
5144
 
5109
- .dndev-pagination-button:hover:not(:disabled) {
5110
- background: var(--accent);
5111
- color: var(--accent-foreground);
5112
- }
5145
+ /* Desktop: Show all elements in one row */
5113
5146
 
5114
- .dndev-pagination-button:focus-visible {
5115
- outline: 2px solid var(--ring);
5116
- outline-offset: 2px;
5147
+ @media (min-width: 768px) {
5148
+ .dndev-pagination-info,
5149
+ .dndev-pagination-size {
5150
+ display: flex;
5151
+ align-items: center;
5152
+ white-space: nowrap;
5117
5153
  }
5118
5154
 
5119
- .dndev-pagination-button:disabled {
5120
- opacity: var(--opacity-muted);
5121
- cursor: not-allowed;
5155
+ .dndev-pagination-size-label {
5156
+ margin-right: var(--gap-sm);
5122
5157
  }
5123
5158
 
5124
- .dndev-pagination-button[aria-current='page'] {
5125
- background: var(--primary);
5126
- color: var(--primary-foreground);
5127
- border-color: var(--primary);
5159
+ .dndev-pagination-nav {
5160
+ justify-content: flex-end;
5161
+ width: auto;
5162
+ margin-left: auto;
5163
+ /* Push to right */
5128
5164
  }
5129
-
5130
- .dndev-pagination-ellipsis {
5131
- display: flex;
5132
- align-items: center;
5133
- justify-content: center;
5134
- width: var(--touch-target);
5135
- height: var(--touch-target);
5136
- color: var(--muted-foreground);
5137
5165
  }
5138
5166
 
5139
5167
  /* packages/components/src/atomic/Popover/Popover.css */
@@ -5864,8 +5892,12 @@ em {
5864
5892
 
5865
5893
  /* Adjust header padding when drag handle is present (sibling selector) */
5866
5894
 
5867
- .dndev-sheet-content[data-side='bottom'] .dndev-sheet-drag-handle ~ .dndev-sheet-header,
5868
- .dndev-sheet-content[data-side='top'] .dndev-sheet-drag-handle ~ .dndev-sheet-header {
5895
+ .dndev-sheet-content[data-side='bottom']
5896
+ .dndev-sheet-drag-handle
5897
+ ~ .dndev-sheet-header,
5898
+ .dndev-sheet-content[data-side='top']
5899
+ .dndev-sheet-drag-handle
5900
+ ~ .dndev-sheet-header {
5869
5901
  padding-top: 0;
5870
5902
  }
5871
5903
 
@@ -5923,12 +5955,9 @@ em {
5923
5955
  position: relative;
5924
5956
  margin-inline-start: auto;
5925
5957
  /* Push to end (RTL-aware: end = right in LTR, left in RTL) */
5958
+ margin-inline-end: var(--gap-sm);
5959
+ /* Spacing from edge - use margin not padding to keep icon centered */
5926
5960
  opacity: var(--opacity-muted);
5927
- /* No padding - tight spacing */
5928
- padding: 0;
5929
- /* RTL-aware: padding on logical end only */
5930
- padding-inline-end: var(--gap-md);
5931
- padding-inline-start: 0;
5932
5961
  }
5933
5962
 
5934
5963
  .dndev-sheet-close:hover {
@@ -6713,7 +6742,21 @@ em {
6713
6742
  }
6714
6743
 
6715
6744
  .dndev-table-header {
6716
- /* Base header styles */
6745
+ background-color: var(--accent);
6746
+ }
6747
+
6748
+ /* Filter row above header */
6749
+
6750
+ .dndev-table-filter-row {
6751
+ border: 1px solid var(--border);
6752
+ border-bottom: none;
6753
+ }
6754
+
6755
+ .dndev-table-filter-row .dndev-table-head {
6756
+ background-color: var(--muted);
6757
+ padding: var(--gap-xs);
6758
+ height: auto;
6759
+ min-height: auto;
6717
6760
  }
6718
6761
 
6719
6762
  .dndev-table-body {
@@ -6775,22 +6818,34 @@ em {
6775
6818
  padding-block: var(--gap-sm);
6776
6819
  }
6777
6820
 
6778
- .dndev-table-head[data-sortable='true'] {
6821
+ /* Header cells use accent foreground for contrast */
6822
+
6823
+ .dndev-table-header .dndev-table-head {
6824
+ color: var(--accent-foreground);
6825
+ }
6826
+
6827
+ [data-sortable='true']:is(.dndev-table-header .dndev-table-head) {
6779
6828
  cursor: pointer;
6780
6829
  }
6781
6830
 
6782
- .dndev-table-head[data-align='center'] {
6831
+ [data-align='center']:is(.dndev-table-header .dndev-table-head) {
6783
6832
  text-align: center;
6784
6833
  }
6785
6834
 
6786
- .dndev-table-head[data-align='end'] {
6835
+ [data-align='end']:is(.dndev-table-header .dndev-table-head) {
6787
6836
  text-align: end;
6788
6837
  }
6789
6838
 
6790
- .dndev-table-head[data-align='start'] {
6839
+ [data-align='start']:is(.dndev-table-header .dndev-table-head) {
6791
6840
  text-align: start;
6792
6841
  }
6793
6842
 
6843
+ /* Active filter indicator */
6844
+
6845
+ .dndev-table-filter-active {
6846
+ color: var(--primary);
6847
+ }
6848
+
6794
6849
  /* Table cell (td) styles */
6795
6850
 
6796
6851
  .dndev-table-cell {
@@ -6798,6 +6853,7 @@ em {
6798
6853
  padding-inline: var(--gap-md);
6799
6854
  padding-block: var(--gap-sm);
6800
6855
  min-height: var(--touch-target);
6856
+ line-height: 1.5; /* Ensure consistent line height for empty cells */
6801
6857
  }
6802
6858
 
6803
6859
  .dndev-table-cell[data-align='center'] {
@@ -6876,6 +6932,64 @@ em {
6876
6932
  padding-inline-start: calc(var(--gap-md) + var(--icon-md) + var(--gap-sm));
6877
6933
  }
6878
6934
 
6935
+ /* Skeleton rows - apply standard skeleton pulse animation to entire rows */
6936
+
6937
+ /* Keep existing background colors (zebra striping) - just add opacity pulse */
6938
+
6939
+ .dndev-table-body .dndev-table-row.dndev-skeleton-row {
6940
+ animation: dndev-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
6941
+ pointer-events: none;
6942
+
6943
+ /* Keep hover state but disabled (pointer-events: none prevents hover) */
6944
+ }
6945
+
6946
+ :is(.dndev-table-body .dndev-table-row.dndev-skeleton-row):hover {
6947
+ /* Inherit from parent .dndev-table-row hover styles */
6948
+ }
6949
+
6950
+ /* Even rows keep their var(--muted) background, just pulse */
6951
+
6952
+ .dndev-table-body .dndev-table-row.dndev-skeleton-row:nth-child(even) {
6953
+ animation: dndev-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
6954
+ }
6955
+
6956
+ :is(.dndev-table-body .dndev-table-row.dndev-skeleton-row:nth-child(even)):hover {
6957
+ /* Inherit from parent .dndev-table-row:nth-child(even) hover styles */
6958
+ }
6959
+
6960
+ /* Skeleton bars inside cells - adapt to row background for visibility */
6961
+
6962
+ /* Odd rows (transparent background): use default var(--muted) skeleton */
6963
+
6964
+ /* Even rows (var(--muted) background): use lighter skeleton for contrast */
6965
+
6966
+ .dndev-table-body .dndev-table-row.dndev-skeleton-row .dndev-skeleton {
6967
+ background-color: var(--muted);
6968
+ }
6969
+
6970
+ .dndev-table-body
6971
+ .dndev-table-row.dndev-skeleton-row:nth-child(even)
6972
+ .dndev-skeleton {
6973
+ /* Even rows have var(--muted) background, so skeleton should be lighter for contrast */
6974
+ background-color: color-mix(
6975
+ in oklab,
6976
+ var(--muted) 60%,
6977
+ var(--foreground) 40%
6978
+ );
6979
+ }
6980
+
6981
+ /* Use the same pulse animation as standard skeleton (from Skeleton.css) */
6982
+
6983
+ @keyframes dndev-pulse {
6984
+ 0%,
6985
+ 100% {
6986
+ opacity: 1;
6987
+ }
6988
+ 50% {
6989
+ opacity: var(--opacity-muted);
6990
+ }
6991
+ }
6992
+
6879
6993
  /* packages/components/src/atomic/Tabs/Tabs.css */
6880
6994
 
6881
6995
  /* Tabs list: use flexbox for natural wrapping, not grid */
@@ -8815,6 +8929,7 @@ h4[data-variant='code'] {
8815
8929
  from {
8816
8930
  opacity: 1;
8817
8931
  }
8932
+
8818
8933
  to {
8819
8934
  opacity: 0;
8820
8935
  }
@@ -8824,6 +8939,7 @@ h4[data-variant='code'] {
8824
8939
  from {
8825
8940
  opacity: 0;
8826
8941
  }
8942
+
8827
8943
  to {
8828
8944
  opacity: 1;
8829
8945
  }
@@ -8836,6 +8952,7 @@ h4[data-variant='code'] {
8836
8952
  opacity: 1;
8837
8953
  transform: translateX(0);
8838
8954
  }
8955
+
8839
8956
  to {
8840
8957
  opacity: 0;
8841
8958
  transform: translateX(-100%);
@@ -8847,6 +8964,7 @@ h4[data-variant='code'] {
8847
8964
  opacity: 0;
8848
8965
  transform: translateX(100%);
8849
8966
  }
8967
+
8850
8968
  to {
8851
8969
  opacity: 1;
8852
8970
  transform: translateX(0);
@@ -8921,7 +9039,7 @@ main[role='main'][data-routing-animation='none'] {
8921
9039
 
8922
9040
  /* Tablet (768px - 1023px) */
8923
9041
 
8924
- @media (width >= 768px) and (width <= 1023px) {
9042
+ @media (width >=768px) and (width <=1023px) {
8925
9043
  main[role='main'][data-routing-animation='fade'] {
8926
9044
  animation: routeFadeIn
8927
9045
  var(--routing-tablet-duration, var(--routing-default-duration, 300ms))
@@ -8937,7 +9055,7 @@ main[role='main'][data-routing-animation='none'] {
8937
9055
 
8938
9056
  /* Desktop (1024px - 1439px) */
8939
9057
 
8940
- @media (width >= 1024px) and (width <= 1439px) {
9058
+ @media (width >=1024px) and (width <=1439px) {
8941
9059
  main[role='main'][data-routing-animation='fade'] {
8942
9060
  animation: routeFadeIn
8943
9061
  var(--routing-desktop-duration, var(--routing-default-duration, 300ms))
@@ -8953,7 +9071,7 @@ main[role='main'][data-routing-animation='none'] {
8953
9071
 
8954
9072
  /* Wide (>= 1440px) */
8955
9073
 
8956
- @media (width >= 1440px) {
9074
+ @media (width >=1440px) {
8957
9075
  main[role='main'][data-routing-animation='fade'] {
8958
9076
  animation: routeFadeIn
8959
9077
  var(--routing-wide-duration, var(--routing-default-duration, 300ms))
@@ -8986,7 +9104,7 @@ main[role='main'][data-routing-animation='none'] {
8986
9104
 
8987
9105
  /* Mobile/Tablet: Hide sidebars - WCAG & Lighthouse best practices */
8988
9106
 
8989
- @media (width <= 1023px) {
9107
+ @media (width <=1023px) {
8990
9108
  .dndev-layout aside[role='navigation'].sidebar,
8991
9109
  aside[role='navigation'].sidebar {
8992
9110
  display: none !important;
@@ -9016,59 +9134,55 @@ main[role='main'][data-routing-animation='none'] {
9016
9134
  );
9017
9135
  grid-template-columns: var(--sidebar-width) 1fr;
9018
9136
 
9019
- /* Mobile: No footer grid row - footer is inside main */
9020
- /* When mergedBar is shown, header is hidden but grid still needs space for mergedBar */
9137
+ /* Mobile: Grid scrolls instead of main - footer scrolls with content */
9021
9138
  }
9022
9139
 
9023
- @media (width <= 1023px) {
9140
+ @media (width <=1023px) {
9024
9141
 
9025
9142
  .dndev-layout {
9143
+ overflow-y: auto;
9144
+ overflow-x: hidden;
9145
+ /* Keep footer row - grid scrolls so footer scrolls with content */
9026
9146
  grid-template-areas:
9027
9147
  'header header'
9028
- 'sidebar main';
9029
- grid-template-rows: var(--header-height) 1fr;
9030
-
9031
- /* Presets with mergedBar: header is hidden, but grid still allocates space for mergedBar */
9032
- /* No extra padding needed - grid spacing is sufficient */
9148
+ 'sidebar main'
9149
+ 'footer footer';
9150
+ grid-template-rows: var(--header-height) min-content auto;
9033
9151
  }
9034
- .dndev-layout[data-layout='admin'],.dndev-layout[data-layout='moolti'],.dndev-layout[data-layout='game'],.dndev-layout[data-layout='docs'] {
9035
- /* Grid already accounts for header-height, mergedBar is fixed and doesn't need extra padding */
9036
- }
9037
9152
  }
9038
9153
 
9039
- /* Footer containers: show/hide based on breakpoint */
9154
+ /* Footer scroll mode - grid scrolls, footer scrolls with content (opt-in for desktop) */
9040
9155
 
9041
- .footer-mobile {
9042
- display: none;
9043
- /* No margin-top: auto - footer scrolls with content on mobile */
9044
- /* No flex-shrink: 0 - footer is in normal flow, not stuck at bottom */
9156
+ .dndev-layout[data-footer-mode='scroll'] {
9157
+ overflow-y: auto;
9158
+ overflow-x: hidden;
9159
+ grid-template-rows: var(--header-height) min-content auto;
9045
9160
  }
9046
9161
 
9047
- .footer-desktop {
9048
- display: contents; /* Children (footer element) participate in grid */
9162
+ .dndev-layout[data-footer-mode='scroll'] header[role='banner'] {
9163
+ position: sticky;
9164
+ top: 0;
9049
9165
  }
9050
9166
 
9051
- @media (width <= 1023px) {
9052
- .footer-mobile {
9053
- display: block;
9054
- }
9167
+ .dndev-layout[data-footer-mode='scroll'] main[role='main'] {
9168
+ overflow: visible;
9169
+ min-height: -moz-min-content;
9170
+ min-height: min-content;
9171
+ }
9055
9172
 
9056
- .footer-desktop {
9057
- display: none;
9058
- }
9173
+ .dndev-layout[data-footer-mode='scroll'] footer[role='contentinfo'] {
9174
+ height: auto;
9175
+ }
9059
9176
 
9060
- /* Game: No mobile footer - navigation in MergedBar */
9061
- [data-layout='game'] .footer-mobile {
9062
- display: none;
9177
+ :is(.dndev-layout[data-footer-mode='scroll'] footer[role='contentinfo']) > * {
9178
+ height: auto;
9179
+ min-height: var(--footer-height);
9063
9180
  }
9064
- }
9065
9181
 
9066
9182
  /* Presets with no footer at all */
9067
9183
 
9068
- [data-layout='moolti'] .footer-mobile,
9069
- [data-layout='moolti'] .footer-desktop,
9070
- [data-layout='plain'] .footer-mobile,
9071
- [data-layout='plain'] .footer-desktop {
9184
+ [data-layout='moolti'] footer[role='contentinfo'],
9185
+ [data-layout='plain'] footer[role='contentinfo'] {
9072
9186
  display: none;
9073
9187
  }
9074
9188
 
@@ -9106,7 +9220,17 @@ header[role='banner'] {
9106
9220
  /* Theme-aware styling - 100% controlled by theme system */
9107
9221
  background: var(--background);
9108
9222
  border-bottom: var(--border-hairline) solid var(--border);
9223
+
9224
+ /* Mobile: Sticky header (for presets that keep header visible) */
9225
+ }
9226
+
9227
+ @media (width <=1023px) {
9228
+
9229
+ header[role='banner'] {
9230
+ position: sticky;
9231
+ top: 0;
9109
9232
  }
9233
+ }
9110
9234
 
9111
9235
  .header-start {
9112
9236
  display: flex;
@@ -9161,19 +9285,20 @@ header[role='banner'] .header-center {
9161
9285
  aside[role='navigation'].sidebar {
9162
9286
  grid-area: sidebar;
9163
9287
  box-sizing: border-box;
9164
- min-width: calc(
9165
- var(--sidebar-resize-handle-width) + 48px
9166
- ); /* Min: 48px content + 6px handle = 54px */
9167
- max-width: calc(
9168
- var(--sidebar-resize-handle-width) + 400px
9169
- ); /* Max: 400px content + 6px handle = 406px */
9288
+ min-width: calc(var(--sidebar-resize-handle-width) + 48px);
9289
+ /* Min: 48px content + 6px handle = 54px */
9290
+ max-width: calc(var(--sidebar-resize-handle-width) + 400px);
9291
+ /* Max: 400px content + 6px handle = 406px */
9170
9292
  z-index: var(--z-sidebar);
9171
- overflow: none; /* No clipping needed - handle is in grid */
9293
+ overflow: none;
9294
+ /* No clipping needed - handle is in grid */
9172
9295
  contain: layout style;
9173
9296
  padding: 0;
9174
9297
  display: grid;
9175
- grid-template-columns: auto var(--sidebar-resize-handle-width); /* Content | Handle - column 1 width set inline */
9176
- grid-template-rows: auto 1fr auto; /* Top | Content | Bottom */
9298
+ grid-template-columns: auto var(--sidebar-resize-handle-width);
9299
+ /* Content | Handle - column 1 width set inline */
9300
+ grid-template-rows: auto 1fr auto;
9301
+ /* Top | Content | Bottom */
9177
9302
  height: 100%;
9178
9303
 
9179
9304
  /* Theme-aware styling - 100% controlled by theme system */
@@ -9228,7 +9353,8 @@ aside[role='navigation'].sidebar[data-dragging='true']
9228
9353
 
9229
9354
  @media (hover: none) {
9230
9355
  aside[role='navigation'].sidebar .dndev-sidebar-resize-handle {
9231
- width: calc(var(--sidebar-resize-handle-width) * 2); /* 12px for touch */
9356
+ width: calc(var(--sidebar-resize-handle-width) * 2);
9357
+ /* 12px for touch */
9232
9358
  }
9233
9359
  }
9234
9360
 
@@ -9297,7 +9423,8 @@ aside[role='navigation'].sidebar[data-dragging='true']
9297
9423
  .sidebar-content .dndev-interactive[data-role='menu-item'],.sidebar-content .dndev-interactive[data-role='nav-trigger'] {
9298
9424
  height: var(--touch-target);
9299
9425
  min-height: var(--touch-target);
9300
- padding-block: 0; /* No vertical padding - buttons fill exact 48px */
9426
+ padding-block: 0;
9427
+ /* No vertical padding - buttons fill exact 48px */
9301
9428
  }
9302
9429
 
9303
9430
  /* Other interactive elements (not menu items) - consistent padding */
@@ -9337,7 +9464,8 @@ aside.sidebar[role='navigation'] .sidebar-top,aside.sidebar[role='navigation'] .
9337
9464
  }
9338
9465
 
9339
9466
  aside.sidebar[role='navigation'] .sidebar-content {
9340
- overflow-x: hidden; /* Prevent horizontal scroll, allow vertical */
9467
+ overflow-x: hidden;
9468
+ /* Prevent horizontal scroll, allow vertical */
9341
9469
  }
9342
9470
 
9343
9471
  aside.sidebar[role='navigation'] .dndev-interactive {
@@ -9402,12 +9530,9 @@ aside.sidebar[role='navigation'][data-collapsed='true'] .app-branding {
9402
9530
  main[role='main'] {
9403
9531
  grid-area: main;
9404
9532
  overflow-y: auto;
9405
- /* Default: allow scrolling */
9406
9533
  overflow-x: hidden;
9407
- /* Prevent horizontal scroll from breakthrough components */
9408
9534
  display: flex;
9409
9535
  flex-direction: column;
9410
- /* No automatic padding; spacing handled by gaps */
9411
9536
  padding: 0;
9412
9537
  contain: layout style;
9413
9538
 
@@ -9416,19 +9541,18 @@ main[role='main'] {
9416
9541
 
9417
9542
  main[role='main'] > *:not(.breadcrumbs-container):first-of-type,main[role='main'] > .breadcrumbs-container + * {
9418
9543
  flex: 1 1 auto;
9419
- /* Page content grows */
9420
9544
  }
9421
9545
 
9422
- /* Desktop: Footer stays at bottom of viewport */
9546
+ /* Mobile: Grid scrolls, main doesn't */
9423
9547
 
9424
- @media (width > 1023px) {
9425
- main[role='main'] > *:last-child {
9426
- flex-shrink: 0;
9427
- /* Footer stays at bottom */
9428
- }
9429
- }
9548
+ @media (width <=1023px) {
9430
9549
 
9431
- /* Mobile: Footer scrolls with content (no flex-shrink needed) */
9550
+ main[role='main'] {
9551
+ overflow: visible;
9552
+ min-height: -moz-min-content;
9553
+ min-height: min-content;
9554
+ }
9555
+ }
9432
9556
 
9433
9557
  /* Footer: Full width by default, app presets start after sidebar */
9434
9558
 
@@ -9462,11 +9586,25 @@ footer[role='contentinfo'] > * {
9462
9586
  padding-inline-end: var(--content-padding);
9463
9587
  }
9464
9588
 
9589
+ /* Mobile: Allow footer to grow when content wraps */
9590
+
9591
+ @media (width <=1023px) {
9592
+
9593
+ footer[role='contentinfo'] {
9594
+ height: auto;
9595
+ }
9596
+
9597
+ footer[role='contentinfo'] > * {
9598
+ height: auto;
9599
+ min-height: var(--footer-height);
9600
+ }
9601
+ }
9602
+
9465
9603
  /* Footer text styles */
9466
9604
 
9467
9605
  footer[role='contentinfo'] .footer-copyright {
9468
9606
  color: var(--muted-foreground);
9469
- font-size: var(--font-size-sm);
9607
+ font-size: var(--font-size-xs);
9470
9608
  }
9471
9609
 
9472
9610
  footer[role='contentinfo'] a:not(.dndev-interactive) {
@@ -9536,7 +9674,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9536
9674
 
9537
9675
  /* Mobile (<1024px): Show merged-bar, hide zones */
9538
9676
 
9539
- @media (width <= 1023px) {
9677
+ @media (width <=1023px) {
9540
9678
  /* Presets with mergedBar: top (admin, moolti, game, docs) */
9541
9679
  [data-layout='admin'] .merged-bar[data-position='top'],
9542
9680
  [data-layout='moolti'] .merged-bar[data-position='top'],
@@ -9576,7 +9714,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9576
9714
 
9577
9715
  /* Desktop (>=1024px): Always hide merged-bar */
9578
9716
 
9579
- @media (width >= 1024px) {
9717
+ @media (width >=1024px) {
9580
9718
  .merged-bar {
9581
9719
  display: none !important;
9582
9720
  }
@@ -9600,7 +9738,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9600
9738
  /* Admin: Mobile/Tablet (<1024px) - only overrides */
9601
9739
  }
9602
9740
 
9603
- @media (width <= 1023px) {
9741
+ @media (width <=1023px) {
9604
9742
 
9605
9743
  [data-layout='admin'] {
9606
9744
  --sidebar-width: 0px;
@@ -9631,7 +9769,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9631
9769
 
9632
9770
  /* Moolti: Mobile/Tablet (<1024px) - only overrides */
9633
9771
 
9634
- @media (width <= 1023px) {
9772
+ @media (width <=1023px) {
9635
9773
 
9636
9774
  [data-layout='moolti'] {
9637
9775
  --header-height: 62px;
@@ -9658,7 +9796,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9658
9796
 
9659
9797
  /* Docs: Mobile/Tablet (<1024px) - only overrides */
9660
9798
 
9661
- @media (width <= 1023px) {
9799
+ @media (width <=1023px) {
9662
9800
 
9663
9801
  [data-layout='docs'] {
9664
9802
  --sidebar-width: 0px;
@@ -9684,7 +9822,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9684
9822
  /* Blog: Mobile/Tablet (<1024px) - only overrides */
9685
9823
  }
9686
9824
 
9687
- @media (width <= 1023px) {
9825
+ @media (width <=1023px) {
9688
9826
 
9689
9827
  [data-layout='blog'] {
9690
9828
  --header-height: 0px;
@@ -9734,7 +9872,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9734
9872
  /* Game: Mobile/Tablet (<1024px) - only overrides */
9735
9873
  }
9736
9874
 
9737
- @media (width <= 1023px) {
9875
+ @media (width <=1023px) {
9738
9876
 
9739
9877
  [data-layout='game'] {
9740
9878
  --footer-height: 0px;
@@ -9855,7 +9993,14 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9855
9993
  padding-top: var(--gap-lg);
9856
9994
  }
9857
9995
 
9996
+ /* First Section child gets gap-md spacing from top */
9997
+
9998
+ .dndev-container > .dndev-section-full-width:first-child {
9999
+ margin-top: var(--gap-md);
10000
+ }
10001
+
9858
10002
  .dndev-container {
10003
+
9859
10004
  min-height: 0;
9860
10005
  display: flex;
9861
10006
  flex-direction: column;
@@ -9890,7 +10035,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9890
10035
  --max-content-width: 100%;
9891
10036
  }
9892
10037
 
9893
- @media (width >= 1024px) {
10038
+ @media (width >=1024px) {
9894
10039
 
9895
10040
  .dndev-container[data-variant='standard'] {
9896
10041
  --max-content-width: 87.5rem;
@@ -9905,7 +10050,7 @@ footer[role='contentinfo'] a:not(.dndev-interactive):hover {
9905
10050
  --max-content-width: 100%;
9906
10051
  }
9907
10052
 
9908
- @media (width >= 1024px) {
10053
+ @media (width >=1024px) {
9909
10054
 
9910
10055
  .dndev-container[data-variant='docs'] {
9911
10056
  --max-content-width: 56.25rem;