@fayz-ai/ui 0.33.0 → 0.35.0

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 (54) hide show
  1. package/dist/{chunk-NXSDQ7HO.js → chunk-2CRN3BOD.js} +13 -16
  2. package/dist/chunk-2CRN3BOD.js.map +1 -0
  3. package/dist/{chunk-PL5CUWNE.js → chunk-63BB2CNP.js} +883 -309
  4. package/dist/chunk-63BB2CNP.js.map +1 -0
  5. package/dist/{chunk-3XKDGBP4.js → chunk-FNGCA3XR.js} +3 -3
  6. package/dist/{chunk-3XKDGBP4.js.map → chunk-FNGCA3XR.js.map} +1 -1
  7. package/dist/{chunk-UFT3MA5H.js → chunk-OBWOHU5E.js} +324 -223
  8. package/dist/chunk-OBWOHU5E.js.map +1 -0
  9. package/dist/dashboard/DashboardGrid.d.ts +8 -1
  10. package/dist/dashboard/DashboardGrid.d.ts.map +1 -1
  11. package/dist/dashboard/KpiCard.d.ts.map +1 -1
  12. package/dist/dashboard/index.js +3 -3
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +8 -8
  16. package/dist/layout/AppShell.d.ts.map +1 -1
  17. package/dist/layout/ModulePage.d.ts +47 -1
  18. package/dist/layout/ModulePage.d.ts.map +1 -1
  19. package/dist/layout/SaveBar.d.ts.map +1 -1
  20. package/dist/layout/Sidebar.d.ts.map +1 -1
  21. package/dist/layout/index.d.ts +1 -1
  22. package/dist/layout/index.d.ts.map +1 -1
  23. package/dist/layout/index.js +1 -1
  24. package/dist/layout/rail-flyout.d.ts.map +1 -1
  25. package/dist/primitives/collapsible-column.d.ts +38 -0
  26. package/dist/primitives/collapsible-column.d.ts.map +1 -0
  27. package/dist/primitives/coming-soon.d.ts +31 -0
  28. package/dist/primitives/coming-soon.d.ts.map +1 -0
  29. package/dist/primitives/filter-panel.d.ts +85 -0
  30. package/dist/primitives/filter-panel.d.ts.map +1 -0
  31. package/dist/primitives/filter-rail.d.ts +10 -7
  32. package/dist/primitives/filter-rail.d.ts.map +1 -1
  33. package/dist/primitives/header-tabs.d.ts +9 -35
  34. package/dist/primitives/header-tabs.d.ts.map +1 -1
  35. package/dist/primitives/index.d.ts +3 -1
  36. package/dist/primitives/index.d.ts.map +1 -1
  37. package/dist/primitives/index.js +3 -3
  38. package/dist/primitives/modal.d.ts +2 -0
  39. package/dist/primitives/modal.d.ts.map +1 -1
  40. package/dist/primitives/nav-connector.d.ts +23 -0
  41. package/dist/primitives/nav-connector.d.ts.map +1 -0
  42. package/dist/primitives/page-actions.d.ts.map +1 -1
  43. package/dist/primitives/person-picker.d.ts +1 -1
  44. package/dist/primitives/person-picker.d.ts.map +1 -1
  45. package/dist/primitives/search-select.d.ts.map +1 -1
  46. package/dist/stores/index.d.ts +1 -1
  47. package/dist/stores/index.d.ts.map +1 -1
  48. package/dist/stores/page-header.store.d.ts +17 -0
  49. package/dist/stores/page-header.store.d.ts.map +1 -1
  50. package/dist/styles.css +84 -0
  51. package/package.json +2 -2
  52. package/dist/chunk-NXSDQ7HO.js.map +0 -1
  53. package/dist/chunk-PL5CUWNE.js.map +0 -1
  54. package/dist/chunk-UFT3MA5H.js.map +0 -1
@@ -1,17 +1,120 @@
1
1
  import { cn } from './chunk-OKZ6WQB3.js';
2
2
  import { ICON_MAP } from './chunk-ATDIWKBD.js';
3
- import * as React11 from 'react';
4
- import { Loader2, ChevronLeft, ArrowLeft, X, Bell, PanelLeft, PanelLeftClose, Search, CornerDownLeft, Menu, Crown, ChevronDown, ChevronRight, Info, ExternalLink, CreditCard, Sparkles, Home, ChevronUp, Plus, Settings, UserCog, LogOut } from 'lucide-react';
5
- import { useTranslation, useNavReferrer, routeModule, navHistoryBack, recordNavigation } from '@fayz-ai/core';
3
+ import * as React12 from 'react';
4
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
5
+ import { X, Loader2, ChevronLeft, ArrowLeft, Bell, PanelLeft, PanelLeftClose, Search, CornerDownLeft, Menu, Crown, ChevronsRight, ChevronsLeft, ChevronDown, ChevronRight, Info, ExternalLink, CreditCard, Sparkles, Home, ChevronUp, Plus, Settings, UserCog, LogOut } from 'lucide-react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import * as TooltipPrimitive from '@radix-ui/react-tooltip';
8
7
  import { createPortal } from 'react-dom';
8
+ import { useTranslation, useNavReferrer, routeModule, navHistoryBack, recordNavigation } from '@fayz-ai/core';
9
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
9
10
  import { create } from 'zustand';
10
11
  import * as Popover from '@radix-ui/react-popover';
11
12
 
13
+ var SIZE_MAP = {
14
+ sm: "sm:max-w-sm",
15
+ md: "sm:max-w-md",
16
+ lg: "sm:max-w-lg",
17
+ xl: "sm:max-w-xl",
18
+ "2xl": "sm:max-w-2xl",
19
+ "3xl": "sm:max-w-3xl",
20
+ // Duas colunas de trabalho lado a lado (ficha + linha do tempo) não cabem em
21
+ // 3xl: a coluna da direita fica com 20rem e o texto de cada anotação quebra
22
+ // a cada quatro palavras.
23
+ "4xl": "sm:max-w-4xl",
24
+ "5xl": "sm:max-w-5xl",
25
+ full: "sm:max-w-[calc(100vw-4rem)]"
26
+ };
27
+ var Modal = DialogPrimitive.Root;
28
+ var ModalTrigger = DialogPrimitive.Trigger;
29
+ var ModalClose = DialogPrimitive.Close;
30
+ var ModalPortal = DialogPrimitive.Portal;
31
+ var ModalHostContext = React12.createContext(null);
32
+ function useModalHost() {
33
+ return React12.useContext(ModalHostContext);
34
+ }
35
+ var ModalOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
36
+ DialogPrimitive.Overlay,
37
+ {
38
+ ref,
39
+ className: cn(
40
+ "fayz-modal-overlay saas-mdl-ov fixed inset-0 z-[100]",
41
+ "flex items-center justify-center p-0 sm:p-6",
42
+ className
43
+ ),
44
+ ...props
45
+ }
46
+ ));
47
+ ModalOverlay.displayName = "ModalOverlay";
48
+ var ModalContent = React12.forwardRef(({ className, children, size = "lg", hideClose, noPadding, onPointerDownOutside, onInteractOutside, onCloseAutoFocus, ...props }, ref) => {
49
+ const [host, setHost] = React12.useState(null);
50
+ const attach = React12.useCallback((node) => {
51
+ setHost(node);
52
+ if (typeof ref === "function") ref(node);
53
+ else if (ref) ref.current = node;
54
+ }, [ref]);
55
+ return /* @__PURE__ */ jsx(ModalPortal, { children: /* @__PURE__ */ jsx(ModalOverlay, { children: /* @__PURE__ */ jsxs(
56
+ DialogPrimitive.Content,
57
+ {
58
+ ref: attach,
59
+ onCloseAutoFocus: (e) => {
60
+ e.preventDefault();
61
+ onCloseAutoFocus?.(e);
62
+ },
63
+ onPointerDownOutside: (e) => {
64
+ const target = e.target;
65
+ if (target.closest("[data-modal-passthrough]") || target.closest("[data-radix-popper-content-wrapper]")) {
66
+ e.preventDefault();
67
+ }
68
+ onPointerDownOutside?.(e);
69
+ },
70
+ onInteractOutside: (e) => {
71
+ const target = e.target;
72
+ if (target.closest("[data-modal-passthrough]") || target.closest("[data-radix-popper-content-wrapper]")) {
73
+ e.preventDefault();
74
+ }
75
+ onInteractOutside?.(e);
76
+ },
77
+ className: cn(
78
+ // fz-container: a form inside a dialog measures the DIALOG. Without
79
+ // it a two-column field grid in an `sm` modal read the window's width
80
+ // and kept both columns in 380px.
81
+ "fayz-glass-surface fayz-modal-content saas-mdl-ct fz-container relative z-[100] flex flex-col w-full outline-none",
82
+ // Mobile fullscreen
83
+ "h-full rounded-none border-0",
84
+ // Desktop centered card
85
+ "sm:h-auto sm:max-h-[85vh] sm:rounded-2xl sm:border",
86
+ SIZE_MAP[size],
87
+ noPadding ? "" : "p-6 gap-4",
88
+ className
89
+ ),
90
+ ...props,
91
+ children: [
92
+ /* @__PURE__ */ jsx(ModalHostContext.Provider, { value: host, children }),
93
+ !hideClose && /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 z-10 flex h-7 w-7 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring", children: [
94
+ /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
95
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
96
+ ] })
97
+ ]
98
+ }
99
+ ) }) });
100
+ });
101
+ ModalContent.displayName = "ModalContent";
102
+ function ModalHeader({ className, ...props }) {
103
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left shrink-0", className), ...props });
104
+ }
105
+ function ModalBody({ className, ...props }) {
106
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 flex-col overflow-y-auto min-h-0", className), ...props });
107
+ }
108
+ function ModalFooter({ className, ...props }) {
109
+ return /* @__PURE__ */ jsx("div", { className: cn("mt-auto flex flex-col-reverse gap-2 pb-[env(safe-area-inset-bottom)] sm:mt-0 sm:flex-row sm:justify-end sm:gap-0 sm:space-x-2 sm:pb-0 shrink-0", className), ...props });
110
+ }
111
+ var ModalTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props }));
112
+ ModalTitle.displayName = "ModalTitle";
113
+ var ModalDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
114
+ ModalDescription.displayName = "ModalDescription";
12
115
  var HIDDEN = { visible: false, saving: false };
13
- var SaveBarApiContext = React11.createContext(null);
14
- var SaveBarStateContext = React11.createContext({ visible: false, saving: false });
116
+ var SaveBarApiContext = React12.createContext(null);
117
+ var SaveBarStateContext = React12.createContext({ visible: false, saving: false });
15
118
  var _saveBarVisible = false;
16
119
  var _saveBarSubs = /* @__PURE__ */ new Set();
17
120
  function setSaveBarVisibleSignal(v) {
@@ -20,7 +123,7 @@ function setSaveBarVisibleSignal(v) {
20
123
  _saveBarSubs.forEach((fn) => fn());
21
124
  }
22
125
  function useSaveBarVisible() {
23
- return React11.useSyncExternalStore(
126
+ return React12.useSyncExternalStore(
24
127
  (cb) => {
25
128
  _saveBarSubs.add(cb);
26
129
  return () => {
@@ -32,10 +135,10 @@ function useSaveBarVisible() {
32
135
  );
33
136
  }
34
137
  function SaveBarProvider({ children }) {
35
- const [state, setState] = React11.useState({ visible: false, saving: false });
36
- const handlers = React11.useRef({});
37
- const entries = React11.useRef([]);
38
- const api = React11.useMemo(() => ({
138
+ const [state, setState] = React12.useState({ visible: false, saving: false });
139
+ const handlers = React12.useRef({});
140
+ const entries = React12.useRef([]);
141
+ const api = React12.useMemo(() => ({
39
142
  setState,
40
143
  handlers,
41
144
  entries,
@@ -45,12 +148,12 @@ function SaveBarProvider({ children }) {
45
148
  setState(top ? top.state : HIDDEN);
46
149
  }
47
150
  }), []);
48
- const backStack = React11.useRef([]);
49
- const backApi = React11.useMemo(() => ({ stack: backStack }), []);
50
- React11.useEffect(() => {
151
+ const backStack = React12.useRef([]);
152
+ const backApi = React12.useMemo(() => ({ stack: backStack }), []);
153
+ React12.useEffect(() => {
51
154
  setSaveBarVisibleSignal(state.visible);
52
155
  }, [state.visible]);
53
- React11.useEffect(() => {
156
+ React12.useEffect(() => {
54
157
  function onKey(e) {
55
158
  if (state.visible && !state.saving) {
56
159
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
@@ -78,7 +181,7 @@ function SaveBarProvider({ children }) {
78
181
  }, [state.visible, state.saving]);
79
182
  return /* @__PURE__ */ jsx(SaveBarApiContext.Provider, { value: api, children: /* @__PURE__ */ jsx(BackNavApiContext.Provider, { value: backApi, children: /* @__PURE__ */ jsx(SaveBarStateContext.Provider, { value: state, children }) }) });
80
183
  }
81
- var BackNavApiContext = React11.createContext(null);
184
+ var BackNavApiContext = React12.createContext(null);
82
185
  function isEditableTarget(target) {
83
186
  const el = target;
84
187
  if (!el || !el.tagName) return false;
@@ -86,12 +189,12 @@ function isEditableTarget(target) {
86
189
  return tag === "input" || tag === "textarea" || tag === "select" || el.isContentEditable;
87
190
  }
88
191
  function useBackHandler(onBack) {
89
- const api = React11.useContext(BackNavApiContext);
90
- const ref = React11.useRef(onBack);
91
- React11.useEffect(() => {
192
+ const api = React12.useContext(BackNavApiContext);
193
+ const ref = React12.useRef(onBack);
194
+ React12.useEffect(() => {
92
195
  ref.current = onBack;
93
196
  });
94
- React11.useEffect(() => {
197
+ React12.useEffect(() => {
95
198
  if (!api) return;
96
199
  const stack = api.stack.current;
97
200
  stack.push(ref);
@@ -102,15 +205,16 @@ function useBackHandler(onBack) {
102
205
  }, [api]);
103
206
  }
104
207
  function useSaveBar({ dirty, alwaysVisible, saving = false, onSave, onDiscard, message, saveLabel, discardLabel }) {
105
- const api = React11.useContext(SaveBarApiContext);
106
- const entry = React11.useRef({ state: HIDDEN, handlers: {} });
107
- React11.useEffect(() => {
208
+ const api = React12.useContext(SaveBarApiContext);
209
+ const host = useModalHost();
210
+ const entry = React12.useRef({ state: HIDDEN, handlers: {} });
211
+ React12.useEffect(() => {
108
212
  entry.current.handlers = { onSave, onDiscard };
109
213
  if (api && api.entries.current[api.entries.current.length - 1] === entry.current) {
110
214
  api.handlers.current = entry.current.handlers;
111
215
  }
112
216
  });
113
- React11.useEffect(() => {
217
+ React12.useEffect(() => {
114
218
  if (!api) return;
115
219
  const list = api.entries.current;
116
220
  list.push(entry.current);
@@ -121,19 +225,19 @@ function useSaveBar({ dirty, alwaysVisible, saving = false, onSave, onDiscard, m
121
225
  api.sync();
122
226
  };
123
227
  }, [api]);
124
- React11.useEffect(() => {
228
+ React12.useEffect(() => {
125
229
  if (!api) return;
126
- entry.current.state = { visible: dirty || !!alwaysVisible, dirty, saving, message, saveLabel, discardLabel };
230
+ entry.current.state = { visible: dirty || !!alwaysVisible, dirty, saving, message, saveLabel, discardLabel, host };
127
231
  if (api.entries.current[api.entries.current.length - 1] === entry.current) api.sync();
128
- }, [api, dirty, alwaysVisible, saving, message, saveLabel, discardLabel]);
232
+ }, [api, dirty, alwaysVisible, saving, message, saveLabel, discardLabel, host]);
129
233
  }
130
234
  function SaveBar({ className }) {
131
- const state = React11.useContext(SaveBarStateContext);
132
- const api = React11.useContext(SaveBarApiContext);
235
+ const state = React12.useContext(SaveBarStateContext);
236
+ const api = React12.useContext(SaveBarApiContext);
133
237
  const t = useTranslation();
134
- const [rendered, setRendered] = React11.useState(state.visible);
135
- const [closing, setClosing] = React11.useState(false);
136
- React11.useEffect(() => {
238
+ const [rendered, setRendered] = React12.useState(state.visible);
239
+ const [closing, setClosing] = React12.useState(false);
240
+ React12.useEffect(() => {
137
241
  if (state.visible) {
138
242
  setRendered(true);
139
243
  setClosing(false);
@@ -148,15 +252,12 @@ function SaveBar({ className }) {
148
252
  return () => clearTimeout(id);
149
253
  }, [state.visible, rendered]);
150
254
  if (!api || !rendered) return null;
151
- const { saving, message, saveLabel, discardLabel } = state;
152
- return /* @__PURE__ */ jsx(
255
+ const { saving, message, saveLabel, discardLabel, host } = state;
256
+ const island = /* @__PURE__ */ jsx(
153
257
  "div",
154
258
  {
155
259
  className: cn(
156
- // Above the tab bar (z-50), below a full-screen sheet (z-60), and lifted
157
- // clear of the bar's height so its actions are not sitting under it.
158
- "pointer-events-none fixed inset-x-0 z-[55] flex justify-center px-4",
159
- "bottom-[calc(var(--fz-bottom-bar,0px)+1.25rem)]",
260
+ host ? "pointer-events-none absolute inset-x-0 bottom-4 z-10 flex justify-center px-4" : "pointer-events-none fixed inset-x-0 z-[55] flex justify-center px-4 bottom-[calc(var(--fz-bottom-bar,0px)+1.25rem)]",
160
261
  className
161
262
  ),
162
263
  children: /* @__PURE__ */ jsxs("div", { className: cn(
@@ -197,11 +298,12 @@ function SaveBar({ className }) {
197
298
  ] })
198
299
  }
199
300
  );
301
+ return host ? createPortal(island, host) : island;
200
302
  }
201
303
  var TooltipProvider = TooltipPrimitive.Provider;
202
304
  var Tooltip = TooltipPrimitive.Root;
203
305
  var TooltipTrigger = TooltipPrimitive.Trigger;
204
- var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
306
+ var TooltipContent = React12.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
205
307
  TooltipPrimitive.Content,
206
308
  {
207
309
  ref,
@@ -215,6 +317,8 @@ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }
215
317
  ));
216
318
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
217
319
  var usePageHeaderStore = create((set, get) => ({
320
+ moduleViewLabel: null,
321
+ setModuleViewLabel: (moduleViewLabel) => set((state) => state.moduleViewLabel === moduleViewLabel ? state : { moduleViewLabel }),
218
322
  shellSlot: null,
219
323
  setShellSlot: (element) => set({ shellSlot: element }),
220
324
  outletSlot: null,
@@ -241,7 +345,7 @@ var usePageHeaderStore = create((set, get) => ({
241
345
  function useRegisterPageActions() {
242
346
  const add = usePageHeaderStore((s) => s.addActions);
243
347
  const remove = usePageHeaderStore((s) => s.removeActions);
244
- React11.useEffect(() => {
348
+ React12.useEffect(() => {
245
349
  add();
246
350
  return remove;
247
351
  }, [add, remove]);
@@ -264,7 +368,7 @@ function usePageTitleSlotHost() {
264
368
  function usePageHeaderHost() {
265
369
  const addHost = usePageHeaderStore((s) => s.addHost);
266
370
  const removeHost = usePageHeaderStore((s) => s.removeHost);
267
- React11.useEffect(() => {
371
+ React12.useEffect(() => {
268
372
  addHost();
269
373
  return removeHost;
270
374
  }, [addHost, removeHost]);
@@ -282,30 +386,30 @@ function PageHeaderOutlet({ className, active = true }) {
282
386
  const hasActions = usePageHeaderStore((s) => s.actions > 0);
283
387
  const addOutlet = usePageHeaderStore((s) => s.addOutlet);
284
388
  const removeOutlet = usePageHeaderStore((s) => s.removeOutlet);
285
- React11.useEffect(() => {
389
+ React12.useEffect(() => {
286
390
  if (!active) return;
287
391
  addOutlet();
288
392
  return removeOutlet;
289
393
  }, [active, addOutlet, removeOutlet]);
290
- React11.useEffect(() => {
394
+ React12.useEffect(() => {
291
395
  if (active) return;
292
396
  setOutletSlot(null);
293
397
  setOutletActionsSlot(null);
294
398
  }, [active, setOutletSlot, setOutletActionsSlot]);
295
399
  if (!active) return null;
296
- return React11.createElement(
400
+ return React12.createElement(
297
401
  "div",
298
402
  { className: `flex min-h-9 items-center justify-between gap-3${claimed || hasActions ? "" : " hidden"} ${className ?? "mb-3"}` },
299
- React11.createElement("div", { ref: setOutletSlot, className: "flex min-w-0 flex-1 items-center" }),
300
- React11.createElement("div", { ref: setOutletActionsSlot, className: "flex shrink-0 items-center gap-2" })
403
+ React12.createElement("div", { ref: setOutletSlot, className: "flex min-w-0 flex-1 items-center" }),
404
+ React12.createElement("div", { ref: setOutletActionsSlot, className: "flex shrink-0 items-center gap-2" })
301
405
  );
302
406
  }
303
407
  function usePageHeader(active, options) {
304
- const id = React11.useId();
408
+ const id = React12.useId();
305
409
  const claim = usePageHeaderStore((s) => s.claim);
306
410
  const release = usePageHeaderStore((s) => s.release);
307
411
  const back = options?.back ?? false;
308
- React11.useEffect(() => {
412
+ React12.useEffect(() => {
309
413
  if (!active) {
310
414
  release(id);
311
415
  return;
@@ -317,13 +421,23 @@ function usePageHeader(active, options) {
317
421
  function useHasPageHeaderBack() {
318
422
  return usePageHeaderStore((s) => s.hasBack);
319
423
  }
424
+ function useModuleViewLabel() {
425
+ return usePageHeaderStore((s) => s.moduleViewLabel);
426
+ }
427
+ function usePublishModuleViewLabel(label) {
428
+ const setLabel = usePageHeaderStore((s) => s.setModuleViewLabel);
429
+ React12.useEffect(() => {
430
+ setLabel(label ?? null);
431
+ return () => setLabel(null);
432
+ }, [label, setLabel]);
433
+ }
320
434
  function PageTitlePortal({ children }) {
321
435
  const slot = usePageTitleSlot();
322
- if (!slot) return React11.createElement(React11.Fragment, null, children);
436
+ if (!slot) return React12.createElement(React12.Fragment, null, children);
323
437
  return createPortal(children, slot);
324
438
  }
325
- var Hint = React11.forwardRef(function Hint2({ label, children, side = "top", delayDuration = 0, ...rest }, ref) {
326
- if (!label) return React11.cloneElement(children, { ...rest, ref });
439
+ var Hint = React12.forwardRef(function Hint2({ label, children, side = "top", delayDuration = 0, ...rest }, ref) {
440
+ if (!label) return React12.cloneElement(children, { ...rest, ref });
327
441
  return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
328
442
  /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, ...rest, ref, children }),
329
443
  /* @__PURE__ */ jsx(TooltipContent, { side, className: "px-2 py-1 text-xs font-medium", children: label })
@@ -412,7 +526,7 @@ function PageHeader({ title, onBack, parentLabel, backLabel }) {
412
526
  const hasHost = useHasPageHeaderHost();
413
527
  const { onBack: effectiveOnBack, parentLabel: effectiveParent } = useCrossModuleBack(onBack, parentLabel);
414
528
  useBackHandler(effectiveOnBack);
415
- const node = React11.useMemo(() => /* @__PURE__ */ jsx(
529
+ const node = React12.useMemo(() => /* @__PURE__ */ jsx(
416
530
  PageHeaderCrumb,
417
531
  {
418
532
  title,
@@ -426,15 +540,15 @@ function PageHeader({ title, onBack, parentLabel, backLabel }) {
426
540
  }
427
541
  var GUTTER_PX = 8;
428
542
  var CLOSE_DELAY_MS = 140;
429
- var useIsomorphicLayoutEffect = typeof window !== "undefined" ? React11.useLayoutEffect : React11.useEffect;
543
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? React12.useLayoutEffect : React12.useEffect;
430
544
  function iconOf(name) {
431
545
  if (!name) return null;
432
546
  return ICON_MAP[name] ?? null;
433
547
  }
434
- var RailFlyoutContext = React11.createContext(null);
548
+ var RailFlyoutContext = React12.createContext(null);
435
549
  var RailFlyoutProvider = RailFlyoutContext.Provider;
436
550
  function useRailRow(content) {
437
- const flyout = React11.useContext(RailFlyoutContext);
551
+ const flyout = React12.useContext(RailFlyoutContext);
438
552
  if (!flyout || !content) return {};
439
553
  return flyout.rowProps(content);
440
554
  }
@@ -444,19 +558,19 @@ function useRailFlyout({
444
558
  activeRoute,
445
559
  onNavigate
446
560
  }) {
447
- const [state, setState] = React11.useState(null);
448
- const [pos, setPos] = React11.useState({ top: 0, arrow: 20 });
449
- const [animate, setAnimate] = React11.useState(false);
450
- const panelRef = React11.useRef(null);
451
- const closeTimer = React11.useRef(null);
452
- const lastContent = React11.useRef(null);
453
- const cancelClose = React11.useCallback(() => {
561
+ const [state, setState] = React12.useState(null);
562
+ const [pos, setPos] = React12.useState({ top: 0, arrow: 20 });
563
+ const [animate, setAnimate] = React12.useState(false);
564
+ const panelRef = React12.useRef(null);
565
+ const closeTimer = React12.useRef(null);
566
+ const lastContent = React12.useRef(null);
567
+ const cancelClose = React12.useCallback(() => {
454
568
  if (closeTimer.current) {
455
569
  clearTimeout(closeTimer.current);
456
570
  closeTimer.current = null;
457
571
  }
458
572
  }, []);
459
- const show = React11.useCallback(
573
+ const show = React12.useCallback(
460
574
  (anchor, content2) => {
461
575
  if (!enabled) return;
462
576
  cancelClose();
@@ -464,19 +578,19 @@ function useRailFlyout({
464
578
  },
465
579
  [enabled, cancelClose]
466
580
  );
467
- const hide = React11.useCallback(() => {
581
+ const hide = React12.useCallback(() => {
468
582
  cancelClose();
469
583
  closeTimer.current = setTimeout(() => setState(null), CLOSE_DELAY_MS);
470
584
  }, [cancelClose]);
471
- const dismiss = React11.useCallback(() => {
585
+ const dismiss = React12.useCallback(() => {
472
586
  cancelClose();
473
587
  setState(null);
474
588
  }, [cancelClose]);
475
- React11.useEffect(() => () => cancelClose(), [cancelClose]);
476
- React11.useEffect(() => {
589
+ React12.useEffect(() => () => cancelClose(), [cancelClose]);
590
+ React12.useEffect(() => {
477
591
  if (!enabled) dismiss();
478
592
  }, [enabled, dismiss]);
479
- const reposition = React11.useCallback(() => {
593
+ const reposition = React12.useCallback(() => {
480
594
  const rail = railRef.current;
481
595
  const anchor = state?.anchor;
482
596
  if (!rail || !anchor) return;
@@ -491,7 +605,7 @@ function useRailFlyout({
491
605
  setPos({ top, arrow });
492
606
  }, [railRef, state]);
493
607
  useIsomorphicLayoutEffect(reposition, [reposition, state?.content.key]);
494
- React11.useEffect(() => {
608
+ React12.useEffect(() => {
495
609
  if (!state) return;
496
610
  const rail = railRef.current;
497
611
  const onScroll = () => reposition();
@@ -503,7 +617,7 @@ function useRailFlyout({
503
617
  };
504
618
  }, [state, railRef, reposition]);
505
619
  const visible = !!state;
506
- React11.useEffect(() => {
620
+ React12.useEffect(() => {
507
621
  if (!visible) {
508
622
  setAnimate(false);
509
623
  return;
@@ -511,7 +625,7 @@ function useRailFlyout({
511
625
  const id = requestAnimationFrame(() => setAnimate(true));
512
626
  return () => cancelAnimationFrame(id);
513
627
  }, [visible]);
514
- React11.useEffect(() => {
628
+ React12.useEffect(() => {
515
629
  if (!visible) return;
516
630
  const onKey = (event) => {
517
631
  if (event.key === "Escape") dismiss();
@@ -519,7 +633,7 @@ function useRailFlyout({
519
633
  window.addEventListener("keydown", onKey);
520
634
  return () => window.removeEventListener("keydown", onKey);
521
635
  }, [visible, dismiss]);
522
- const rowProps = React11.useCallback(
636
+ const rowProps = React12.useCallback(
523
637
  (content2) => ({
524
638
  onMouseEnter: (event) => show(event.currentTarget, content2),
525
639
  onFocus: (event) => show(event.currentTarget, content2),
@@ -555,6 +669,7 @@ function useRailFlyout({
555
669
  "div",
556
670
  {
557
671
  ref: panelRef,
672
+ style: { borderTopLeftRadius: 2, borderBottomLeftRadius: 2 },
558
673
  className: cn(
559
674
  // Sidebar tone, sidebar border: the panel is the menu leaning out,
560
675
  // not a popover from the page underneath it.
@@ -635,8 +750,53 @@ function FlyoutBody({
635
750
  ] })
636
751
  ] });
637
752
  }
753
+ function NavChildConnector({ onPath, active }) {
754
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
755
+ onPath && /* @__PURE__ */ jsx(
756
+ "span",
757
+ {
758
+ "aria-hidden": true,
759
+ className: "pointer-events-none absolute bottom-0 left-[13px] top-0 w-[1.5px] bg-current"
760
+ }
761
+ ),
762
+ active && /* @__PURE__ */ jsxs(
763
+ "svg",
764
+ {
765
+ "aria-hidden": true,
766
+ className: "pointer-events-none absolute left-1 top-0",
767
+ width: "21",
768
+ height: "32",
769
+ viewBox: "0 0 21 32",
770
+ fill: "none",
771
+ children: [
772
+ /* @__PURE__ */ jsx(
773
+ "path",
774
+ {
775
+ d: "M9.75 0 V11 Q9.75 16 14.75 16 H20",
776
+ stroke: "currentColor",
777
+ strokeWidth: "1.5",
778
+ strokeLinecap: "round",
779
+ fill: "none"
780
+ }
781
+ ),
782
+ /* @__PURE__ */ jsx(
783
+ "path",
784
+ {
785
+ d: "M17 13 L20 16 L17 19",
786
+ stroke: "currentColor",
787
+ strokeWidth: "1.5",
788
+ strokeLinecap: "round",
789
+ strokeLinejoin: "round",
790
+ fill: "none"
791
+ }
792
+ )
793
+ ]
794
+ }
795
+ )
796
+ ] });
797
+ }
638
798
  var RAIL_PUSH_MS = 260;
639
- var useIsomorphicLayoutEffect2 = typeof window !== "undefined" ? React11.useLayoutEffect : React11.useEffect;
799
+ var useIsomorphicLayoutEffect2 = typeof window !== "undefined" ? React12.useLayoutEffect : React12.useEffect;
640
800
  function getIcon(name) {
641
801
  return ICON_MAP[name] ?? Home;
642
802
  }
@@ -847,7 +1007,7 @@ function NavGroup({
847
1007
  // case in an app that groups its rail).
848
1008
  /* @__PURE__ */ jsx("button", { "data-tour": `nav.${child.route}`, onClick: () => onNavigate(child.route), className: childClass, children: childInner })
849
1009
  );
850
- if (!childConnector) return /* @__PURE__ */ jsx(React11.Fragment, { children: row }, child.id);
1010
+ if (!childConnector) return /* @__PURE__ */ jsx(React12.Fragment, { children: row }, child.id);
851
1011
  const activeIndex = item.children.findIndex((c) => c.route === activeRoute);
852
1012
  const onPath = activeIndex >= 0 && childIndex < activeIndex;
853
1013
  return (
@@ -861,47 +1021,7 @@ function NavGroup({
861
1021
  // to /70 when inactive, and a line fading along with the label it
862
1022
  // points AT was nearly invisible on a dark rail.
863
1023
  /* @__PURE__ */ jsxs("div", { className: "relative h-8 text-sidebar-foreground/45", children: [
864
- onPath && /* @__PURE__ */ jsx(
865
- "span",
866
- {
867
- "aria-hidden": true,
868
- className: "pointer-events-none absolute bottom-0 left-[13px] top-0 w-[1.5px] bg-current"
869
- }
870
- ),
871
- isActive && /* @__PURE__ */ jsxs(
872
- "svg",
873
- {
874
- "aria-hidden": true,
875
- className: "pointer-events-none absolute left-1 top-0",
876
- width: "21",
877
- height: "32",
878
- viewBox: "0 0 21 32",
879
- fill: "none",
880
- children: [
881
- /* @__PURE__ */ jsx(
882
- "path",
883
- {
884
- d: "M9.75 0 V11 Q9.75 16 14.75 16 H20",
885
- stroke: "currentColor",
886
- strokeWidth: "1.5",
887
- strokeLinecap: "round",
888
- fill: "none"
889
- }
890
- ),
891
- /* @__PURE__ */ jsx(
892
- "path",
893
- {
894
- d: "M17 13 L20 16 L17 19",
895
- stroke: "currentColor",
896
- strokeWidth: "1.5",
897
- strokeLinecap: "round",
898
- strokeLinejoin: "round",
899
- fill: "none"
900
- }
901
- )
902
- ]
903
- }
904
- ),
1024
+ /* @__PURE__ */ jsx(NavChildConnector, { onPath, active: isActive }),
905
1025
  row
906
1026
  ] }, child.id)
907
1027
  );
@@ -909,9 +1029,9 @@ function NavGroup({
909
1029
  ] });
910
1030
  }
911
1031
  function withCollapsed(slot, collapsed) {
912
- if (!React11.isValidElement(slot)) return slot;
1032
+ if (!React12.isValidElement(slot)) return slot;
913
1033
  if (typeof slot.type === "string") return slot;
914
- return React11.cloneElement(slot, { collapsed });
1034
+ return React12.cloneElement(slot, { collapsed });
915
1035
  }
916
1036
  var SKELETON_ROWS = [
917
1037
  { width: 56, group: false },
@@ -953,7 +1073,7 @@ function Sidebar({
953
1073
  }) {
954
1074
  const currentPath = currentPathProp;
955
1075
  const activeRoute = resolveActiveRoute(navigation, currentPath);
956
- const railRef = React11.useRef(null);
1076
+ const railRef = React12.useRef(null);
957
1077
  const flyout = useRailFlyout({
958
1078
  enabled: collapsed,
959
1079
  railRef,
@@ -966,14 +1086,14 @@ function Sidebar({
966
1086
  const handleNavigate = (route) => {
967
1087
  onNavigate?.(route);
968
1088
  };
969
- const groupWithActiveRoute = React11.useMemo(() => {
1089
+ const groupWithActiveRoute = React12.useMemo(() => {
970
1090
  const groups = navigation.filter((item) => item.children && item.children.length > 0);
971
1091
  return groups.find(
972
1092
  (item) => item.route === activeRoute || item.children.some((child) => child.route === activeRoute)
973
1093
  )?.id ?? null;
974
1094
  }, [navigation, activeRoute]);
975
- const [openGroup, setOpenGroup] = React11.useState(groupWithActiveRoute);
976
- React11.useEffect(() => {
1095
+ const [openGroup, setOpenGroup] = React12.useState(groupWithActiveRoute);
1096
+ React12.useEffect(() => {
977
1097
  if (groupWithActiveRoute) setOpenGroup(groupWithActiveRoute);
978
1098
  }, [groupWithActiveRoute]);
979
1099
  const sectionHeading = (label) => label && !collapsed ? /* @__PURE__ */ jsx("p", { className: "px-2.5 pb-0.5 pt-1 text-[10px] font-semibold uppercase tracking-wider text-sidebar-muted", children: label }) : null;
@@ -1025,10 +1145,10 @@ function Sidebar({
1025
1145
  mainItems.length > 0 && renderSection(mainItems, sectionLabels?.main),
1026
1146
  secondaryItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-6", children: renderSection(secondaryItems, sectionLabels?.secondary) })
1027
1147
  ] });
1028
- const [outgoing, setOutgoing] = React11.useState(null);
1029
- const lastBodyRef = React11.useRef(null);
1030
- const lastKeyRef = React11.useRef(navKey);
1031
- const timerRef = React11.useRef(null);
1148
+ const [outgoing, setOutgoing] = React12.useState(null);
1149
+ const lastBodyRef = React12.useRef(null);
1150
+ const lastKeyRef = React12.useRef(navKey);
1151
+ const timerRef = React12.useRef(null);
1032
1152
  useIsomorphicLayoutEffect2(() => {
1033
1153
  if (lastKeyRef.current !== navKey) {
1034
1154
  const previousBody = lastBodyRef.current;
@@ -1041,7 +1161,7 @@ function Sidebar({
1041
1161
  }
1042
1162
  lastBodyRef.current = navBody;
1043
1163
  });
1044
- React11.useEffect(() => () => {
1164
+ React12.useEffect(() => () => {
1045
1165
  if (timerRef.current) clearTimeout(timerRef.current);
1046
1166
  }, []);
1047
1167
  return (
@@ -1285,7 +1405,7 @@ function ShellSearch({
1285
1405
  const rail = tone === "rail";
1286
1406
  const contextual = !!onValueChange && !collapsed;
1287
1407
  const query = value ?? "";
1288
- const inputRef = React11.useRef(null);
1408
+ const inputRef = React12.useRef(null);
1289
1409
  const escalate = () => setCommandPaletteOpen(true, query);
1290
1410
  const surface = rail ? "bg-sidebar-accent/40 text-sidebar-muted hover:bg-sidebar-accent/70 hover:text-sidebar-foreground" : "bg-accent/40 text-muted-foreground hover:bg-accent/70 hover:text-foreground";
1291
1411
  const ring = rail ? "focus-within:bg-sidebar-accent/70 focus-within:ring-1 focus-within:ring-sidebar-accent-foreground/25" : "focus-within:bg-accent/70 focus-within:ring-1 focus-within:ring-ring/40";
@@ -1396,7 +1516,7 @@ function TopbarUserMenu({
1396
1516
  onBilling,
1397
1517
  userMenuExtras
1398
1518
  }) {
1399
- const [open, setOpen] = React11.useState(false);
1519
+ const [open, setOpen] = React12.useState(false);
1400
1520
  if (!user) return null;
1401
1521
  const initial = (user.fullName?.trim()?.[0] ?? user.email?.[0] ?? "?").toUpperCase();
1402
1522
  const item = (label, onClick, Icon) => onClick ? /* @__PURE__ */ jsxs(
@@ -1480,7 +1600,7 @@ function getIcon2(name) {
1480
1600
  return ICON_MAP[name] ?? Home;
1481
1601
  }
1482
1602
  function NavDropdown({ item, currentPath, onNavigate }) {
1483
- const [open, setOpen] = React11.useState(false);
1603
+ const [open, setOpen] = React12.useState(false);
1484
1604
  const Icon = getIcon2(item.icon);
1485
1605
  const isChildActive = item.children?.some(
1486
1606
  (child) => currentPath === child.route || currentPath.startsWith(child.route + "/")
@@ -1648,9 +1768,9 @@ function Topbar({
1648
1768
  ] });
1649
1769
  }
1650
1770
  function useSheetDrag({ onDismiss, canDrag }) {
1651
- const [offset, setOffset] = React11.useState(0);
1652
- const [dragging, setDragging] = React11.useState(false);
1653
- const start = React11.useRef(null);
1771
+ const [offset, setOffset] = React12.useState(0);
1772
+ const [dragging, setDragging] = React12.useState(false);
1773
+ const start = React12.useRef(null);
1654
1774
  const onPointerDown = (e) => {
1655
1775
  if (e.pointerType === "mouse") return;
1656
1776
  if (canDrag && !canDrag()) return;
@@ -1684,9 +1804,9 @@ function useSheetDrag({ onDismiss, canDrag }) {
1684
1804
  handlers: { onPointerDown, onPointerMove, onPointerUp: end, onPointerCancel: end }
1685
1805
  };
1686
1806
  }
1687
- var SheetCloseContext = React11.createContext(null);
1807
+ var SheetCloseContext = React12.createContext(null);
1688
1808
  function useSheetClose() {
1689
- const close = React11.useContext(SheetCloseContext);
1809
+ const close = React12.useContext(SheetCloseContext);
1690
1810
  return close ?? (() => {
1691
1811
  });
1692
1812
  }
@@ -1700,9 +1820,9 @@ function BottomSheet({
1700
1820
  className,
1701
1821
  label
1702
1822
  }) {
1703
- const [leaving, setLeaving] = React11.useState(false);
1704
- const scroller = React11.useRef(null);
1705
- const close = React11.useCallback(() => {
1823
+ const [leaving, setLeaving] = React12.useState(false);
1824
+ const scroller = React12.useRef(null);
1825
+ const close = React12.useCallback(() => {
1706
1826
  setLeaving(true);
1707
1827
  window.setTimeout(onClose, 200);
1708
1828
  }, [onClose]);
@@ -1710,7 +1830,7 @@ function BottomSheet({
1710
1830
  onDismiss: close,
1711
1831
  canDrag: () => (scroller.current?.scrollTop ?? 0) <= 0
1712
1832
  });
1713
- React11.useEffect(() => {
1833
+ React12.useEffect(() => {
1714
1834
  const onKey = (e) => {
1715
1835
  if (e.key !== "Escape") return;
1716
1836
  if (onBack) onBack();
@@ -1719,15 +1839,15 @@ function BottomSheet({
1719
1839
  window.addEventListener("keydown", onKey);
1720
1840
  return () => window.removeEventListener("keydown", onKey);
1721
1841
  }, [close, onBack]);
1722
- React11.useEffect(() => {
1842
+ React12.useEffect(() => {
1723
1843
  const previous = document.body.style.overflow;
1724
1844
  document.body.style.overflow = "hidden";
1725
1845
  return () => {
1726
1846
  document.body.style.overflow = previous;
1727
1847
  };
1728
1848
  }, []);
1729
- const [host, setHost] = React11.useState(null);
1730
- React11.useEffect(() => {
1849
+ const [host, setHost] = React12.useState(null);
1850
+ React12.useEffect(() => {
1731
1851
  setHost(document.body);
1732
1852
  }, []);
1733
1853
  if (!host) return null;
@@ -1842,17 +1962,17 @@ function SheetRow({
1842
1962
  }
1843
1963
  );
1844
1964
  }
1845
- var ModuleHeaderSlotContext = React11.createContext(null);
1965
+ var ModuleHeaderSlotContext = React12.createContext(null);
1846
1966
  function useModuleHeaderSlot() {
1847
- return React11.useContext(ModuleHeaderSlotContext);
1967
+ return React12.useContext(ModuleHeaderSlotContext);
1848
1968
  }
1849
- var ModuleHeaderActionsSlotContext = React11.createContext(null);
1969
+ var ModuleHeaderActionsSlotContext = React12.createContext(null);
1850
1970
  function useModuleHeaderActionsSlot() {
1851
- return React11.useContext(ModuleHeaderActionsSlotContext);
1971
+ return React12.useContext(ModuleHeaderActionsSlotContext);
1852
1972
  }
1853
- var PageRailSlotContext = React11.createContext(null);
1973
+ var PageRailSlotContext = React12.createContext(null);
1854
1974
  function usePageRailSlot() {
1855
- return React11.useContext(PageRailSlotContext);
1975
+ return React12.useContext(PageRailSlotContext);
1856
1976
  }
1857
1977
  function isCreateRoute(route) {
1858
1978
  return !!route && /\/(new|create)$/.test(route);
@@ -1939,9 +2059,9 @@ function SidebarLayout({
1939
2059
  const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
1940
2060
  const mobileMenuOpen = useLayoutStore((st) => st.mobileDrawerOpen);
1941
2061
  const setMobileMenuOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
1942
- const [headerSlot, setHeaderSlot] = React11.useState(null);
1943
- const [actionsSlot, setActionsSlot] = React11.useState(null);
1944
- const [pageRailSlot, setPageRailSlot] = React11.useState(null);
2062
+ const [headerSlot, setHeaderSlot] = React12.useState(null);
2063
+ const [actionsSlot, setActionsSlot] = React12.useState(null);
2064
+ const [pageRailSlot, setPageRailSlot] = React12.useState(null);
1945
2065
  const hasPageActions = useHasPageActions();
1946
2066
  return /* @__PURE__ */ jsx(SaveBarProvider, { children: /* @__PURE__ */ jsx(ModuleHeaderSlotContext.Provider, { value: headerSlot, children: /* @__PURE__ */ jsx(ModuleHeaderActionsSlotContext.Provider, { value: actionsSlot, children: /* @__PURE__ */ jsx(PageRailSlotContext.Provider, { value: pageRailSlot, children: /* @__PURE__ */ jsxs("div", { className: cn(
1947
2067
  "shell-enter fz-viewport-h flex overflow-hidden bg-background",
@@ -2014,6 +2134,10 @@ function SidebarLayout({
2014
2134
  // Com `min-h` bastava um controle mais alto de um lado para o cartão
2015
2135
  // daquele lado descer sozinho.
2016
2136
  frame && "fz-on-band md:h-14 md:border-b-0 md:text-sidebar-foreground md:[--accent-foreground:var(--sidebar-accent-foreground)] md:[--accent:var(--sidebar-accent)] md:[--background:var(--sidebar)] md:[--border:var(--sidebar-border)] md:[--card:var(--sidebar)] md:[--foreground:var(--sidebar-foreground)] md:[--muted-foreground:var(--sidebar-muted)] md:[--muted:var(--sidebar-accent)]",
2137
+ // A destination keeps the app controls; a deeper screen keeps its
2138
+ // own title/back row. On phones with complete bottom navigation,
2139
+ // showing both was a two-storey header with no extra way out.
2140
+ barOwnsNav && !pagePrimary && "hidden md:flex",
2017
2141
  // …unless the page put its actions in it. Hiding the bar on mobile
2018
2142
  // used to hide the only "Novo" the screen had.
2019
2143
  mobileHeader !== "minimal" && !hasPageActions && "hidden md:flex",
@@ -2076,16 +2200,52 @@ function SidebarLayout({
2076
2200
  frame && (railOpen ? "md:rounded-r-none md:border-r-0" : "md:mr-2"),
2077
2201
  immersive && "md:overflow-hidden"
2078
2202
  ), children: [
2079
- /* @__PURE__ */ jsxs("div", { className: cn(
2080
- "relative z-20 flex min-h-12 shrink-0 items-center justify-between gap-3 border-b border-border px-3 md:px-6",
2081
- menuOpen && "invisible md:visible"
2082
- ), children: [
2083
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
2084
- !pageHeaderClaimed && /* @__PURE__ */ jsx(ShellPageTitle, { title: pageTitle, back: pageBack, primary: pagePrimary }),
2085
- /* @__PURE__ */ jsx("div", { ref: setTitleSlot, className: "flex min-w-0 items-center empty:hidden" })
2086
- ] }),
2087
- /* @__PURE__ */ jsx("div", { ref: setActionsSlot, className: "flex shrink-0 items-center gap-2" })
2088
- ] }),
2203
+ /* @__PURE__ */ jsxs(
2204
+ "div",
2205
+ {
2206
+ style: {
2207
+ // A RÉGUA NÃO ATRAVESSA A COLUNA DO MÓDULO.
2208
+ //
2209
+ // Ela fecha o cabeçalho, e o cabeçalho termina onde a coluna começa:
2210
+ // sobre a coluna, a mesma linha separava duas coisas que são uma só —
2211
+ // o nome da tela e o menu que pende dele. Tapar o pedaço com um pixel
2212
+ // da cor do papel funcionava num tema e falhava no outro, porque o
2213
+ // papel do cartão e o `--page-surface` nem sempre são a mesma tinta.
2214
+ //
2215
+ // Então ela NASCE depois: a régua é um degradê de 1px que só começa
2216
+ // em `--page-rail-seam` — a largura da coluna mais o raio da curva,
2217
+ // publicado por quem a desenha (ver RailColumn). Sem coluna, a
2218
+ // variável não existe e a régua começa em zero, como sempre.
2219
+ backgroundImage: "linear-gradient(to right, transparent 0 var(--page-rail-seam, 0px), hsl(var(--border)) var(--page-rail-seam, 0px) 100%)",
2220
+ backgroundSize: "100% 1px",
2221
+ backgroundRepeat: "no-repeat",
2222
+ backgroundPosition: "left bottom"
2223
+ },
2224
+ className: cn(
2225
+ // O MESMO vidro da coluna do módulo logo abaixo — uma classe só,
2226
+ // senão as duas superfícies encostadas saem em tons diferentes e
2227
+ // a emenda que acabamos de apagar volta como degrau de cor.
2228
+ "fz-liquid-glass relative z-20 flex min-h-12 shrink-0 items-center justify-between gap-3 px-3 md:px-6",
2229
+ menuOpen && "invisible md:visible",
2230
+ // On a primary phone destination the selected bottom-nav item
2231
+ // already names the page. Declared actions render as a body-level
2232
+ // FAB, so this entire duplicate band can disappear.
2233
+ barOwnsNav && pagePrimary && "hidden md:flex"
2234
+ ),
2235
+ children: [
2236
+ /* @__PURE__ */ jsxs("div", { className: cn(
2237
+ "flex min-w-0 flex-1 items-center gap-3",
2238
+ // Primary destinations are already named by the selected mobile
2239
+ // navigation item. Keep this side only for deeper breadcrumbs.
2240
+ pagePrimary && "hidden md:flex"
2241
+ ), children: [
2242
+ !pageHeaderClaimed && /* @__PURE__ */ jsx(ShellPageTitle, { title: pageTitle, back: pageBack, primary: pagePrimary }),
2243
+ /* @__PURE__ */ jsx("div", { ref: setTitleSlot, className: "flex min-w-0 items-center empty:hidden" })
2244
+ ] }),
2245
+ /* @__PURE__ */ jsx("div", { ref: setActionsSlot, className: "flex shrink-0 items-center gap-2" })
2246
+ ]
2247
+ }
2248
+ ),
2089
2249
  /* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 min-h-0 flex-1 overflow-hidden", children: [
2090
2250
  /* @__PURE__ */ jsx("div", { ref: setPageRailSlot, className: "flex shrink-0 empty:hidden" }),
2091
2251
  /* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 min-h-0 flex-1 flex-col overflow-hidden", children: [
@@ -2182,9 +2342,9 @@ function TopbarLayout({
2182
2342
  }) {
2183
2343
  const mobileMenuOpen = useLayoutStore((st) => st.mobileDrawerOpen);
2184
2344
  const setMobileMenuOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
2185
- const [headerSlot, setHeaderSlot] = React11.useState(null);
2186
- const [actionsSlot, setActionsSlot] = React11.useState(null);
2187
- const [pageRailSlot, setPageRailSlot] = React11.useState(null);
2345
+ const [headerSlot, setHeaderSlot] = React12.useState(null);
2346
+ const [actionsSlot, setActionsSlot] = React12.useState(null);
2347
+ const [pageRailSlot, setPageRailSlot] = React12.useState(null);
2188
2348
  const rawClaimed = usePageHeaderClaimed();
2189
2349
  const setTitleSlot = usePageTitleSlotHost();
2190
2350
  const hasOutlet = useHasPageHeaderOutlet();
@@ -2223,10 +2383,16 @@ function TopbarLayout({
2223
2383
  (pageHeaderClaimed || pageBack || hasPageActions || barOwnsNav) && /* @__PURE__ */ jsxs(
2224
2384
  "div",
2225
2385
  {
2386
+ style: {
2387
+ backgroundImage: "linear-gradient(to right, transparent 0 var(--page-rail-seam, 0px), hsl(var(--border)) var(--page-rail-seam, 0px) 100%)",
2388
+ backgroundSize: "100% 1px",
2389
+ backgroundRepeat: "no-repeat",
2390
+ backgroundPosition: "left bottom"
2391
+ },
2226
2392
  className: cn(
2227
2393
  // `relative` + glass for the same reason as the sidebar
2228
2394
  // layout's band: on a phone this IS the navigation bar.
2229
- "relative flex min-h-[44px] md:min-h-12 shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-2",
2395
+ "relative flex min-h-[44px] md:min-h-12 shrink-0 items-center justify-between gap-3 px-4 py-2",
2230
2396
  menuOpen && "invisible md:visible",
2231
2397
  "fayz-glass-topbar",
2232
2398
  !(pageHeaderClaimed || pageBack || hasPageActions) && "md:hidden"
@@ -2311,17 +2477,16 @@ function MobileMoreScreen({
2311
2477
  orgSwitcher,
2312
2478
  mobileIdentity,
2313
2479
  identity,
2314
- notificationSlot,
2315
2480
  searchLabel,
2316
2481
  sectionLabels,
2317
2482
  leaving = false,
2318
2483
  onDismiss,
2319
2484
  onClose
2320
2485
  }) {
2321
- const [pushed, setPushed] = React11.useState(null);
2322
- const [query, setQuery] = React11.useState("");
2323
- const scroller = React11.useRef(null);
2324
- const close = React11.useCallback(() => {
2486
+ const [pushed, setPushed] = React12.useState(null);
2487
+ const [query, setQuery] = React12.useState("");
2488
+ const scroller = React12.useRef(null);
2489
+ const close = React12.useCallback(() => {
2325
2490
  onClose();
2326
2491
  }, [onClose]);
2327
2492
  const drag = useSheetDrag({
@@ -2330,7 +2495,7 @@ function MobileMoreScreen({
2330
2495
  // a pushed section would dismiss the screen the back button is for.
2331
2496
  canDrag: () => !pushed && (scroller.current?.scrollTop ?? 0) <= 0
2332
2497
  });
2333
- React11.useEffect(() => {
2498
+ React12.useEffect(() => {
2334
2499
  const onKey = (e) => {
2335
2500
  if (e.key !== "Escape") return;
2336
2501
  if (pushed) setPushed(null);
@@ -2339,7 +2504,7 @@ function MobileMoreScreen({
2339
2504
  window.addEventListener("keydown", onKey);
2340
2505
  return () => window.removeEventListener("keydown", onKey);
2341
2506
  }, [close, pushed]);
2342
- React11.useEffect(() => {
2507
+ React12.useEffect(() => {
2343
2508
  const previous = document.body.style.overflow;
2344
2509
  document.body.style.overflow = "hidden";
2345
2510
  return () => {
@@ -2359,13 +2524,13 @@ function MobileMoreScreen({
2359
2524
  else onNavigate?.(route);
2360
2525
  };
2361
2526
  const q = query.trim().toLowerCase();
2362
- const flat = React11.useMemo(
2527
+ const flat = React12.useMemo(
2363
2528
  () => navigation.flatMap((n) => n.children?.length ? n.children : [n]),
2364
2529
  [navigation]
2365
2530
  );
2366
2531
  const searching = q.length > 0;
2367
2532
  const hits = searching ? flat.filter((n) => n.label.toLowerCase().includes(q)) : [];
2368
- const sections = React11.useMemo(() => {
2533
+ const sections = React12.useMemo(() => {
2369
2534
  const out = [];
2370
2535
  for (const key of ["main", "secondary", "settings"]) {
2371
2536
  const items = navigation.filter((n) => n.section === key);
@@ -2386,7 +2551,10 @@ function MobileMoreScreen({
2386
2551
  "div",
2387
2552
  {
2388
2553
  className: cn(
2389
- "fixed inset-0 z-[65] flex flex-col bg-background text-foreground will-change-transform md:hidden",
2554
+ // Isolate the full-screen menu into its own backdrop root. Without it,
2555
+ // the glass header samples the app header underneath and both sets of
2556
+ // controls become visible in the same 44px strip.
2557
+ "fixed inset-0 z-[65] isolate flex flex-col bg-background text-foreground will-change-transform md:hidden",
2390
2558
  leaving ? "fz-sheet-out" : "fz-sheet-in",
2391
2559
  drag.dragging && "transition-none",
2392
2560
  !drag.dragging && !leaving && "transition-transform duration-200 ease-out"
@@ -2410,18 +2578,15 @@ function MobileMoreScreen({
2410
2578
  }
2411
2579
  ) }),
2412
2580
  /* @__PURE__ */ jsx("h1", { className: "truncate px-1 text-[15px] font-semibold", children: pushed?.label ?? "Mais" }),
2413
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center justify-end gap-1", children: [
2414
- !pushed && notificationSlot,
2415
- /* @__PURE__ */ jsx(
2416
- "button",
2417
- {
2418
- type: "button",
2419
- onClick: close,
2420
- className: "fz-ios-tint fz-tap rounded-button px-2 py-1 text-[15px] font-semibold",
2421
- children: "Conclu\xEDdo"
2422
- }
2423
- )
2424
- ] })
2581
+ /* @__PURE__ */ jsx("div", { className: "flex min-w-0 items-center justify-end gap-1", children: /* @__PURE__ */ jsx(
2582
+ "button",
2583
+ {
2584
+ type: "button",
2585
+ onClick: close,
2586
+ className: "fz-ios-tint fz-tap rounded-button px-2 py-1 text-[15px] font-semibold",
2587
+ children: "Conclu\xEDdo"
2588
+ }
2589
+ ) })
2425
2590
  ] }) }),
2426
2591
  /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsxs(
2427
2592
  "div",
@@ -2634,23 +2799,23 @@ function MinimalLayout({
2634
2799
  ] });
2635
2800
  }
2636
2801
  function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
2637
- const [visible, setVisible] = React11.useState(false);
2638
- React11.useEffect(() => {
2802
+ const [visible, setVisible] = React12.useState(false);
2803
+ React12.useEffect(() => {
2639
2804
  const id = requestAnimationFrame(() => setVisible(true));
2640
2805
  return () => cancelAnimationFrame(id);
2641
2806
  }, []);
2642
- const close = React11.useCallback(() => {
2807
+ const close = React12.useCallback(() => {
2643
2808
  setVisible(false);
2644
2809
  window.setTimeout(onClose, 250);
2645
2810
  }, [onClose]);
2646
- React11.useEffect(() => {
2811
+ React12.useEffect(() => {
2647
2812
  const previous = document.body.style.overflow;
2648
2813
  document.body.style.overflow = "hidden";
2649
2814
  return () => {
2650
2815
  document.body.style.overflow = previous;
2651
2816
  };
2652
2817
  }, []);
2653
- React11.useEffect(() => {
2818
+ React12.useEffect(() => {
2654
2819
  const onKey = (e) => {
2655
2820
  if (e.key === "Escape") close();
2656
2821
  };
@@ -2753,11 +2918,11 @@ function MobileBottomNav({
2753
2918
  retracted
2754
2919
  }) {
2755
2920
  const path = currentPath ?? "";
2756
- const [openSheet, setOpenSheet] = React11.useState(null);
2757
- React11.useEffect(() => {
2921
+ const [openSheet, setOpenSheet] = React12.useState(null);
2922
+ React12.useEffect(() => {
2758
2923
  setOpenSheet(null);
2759
2924
  }, [currentPath]);
2760
- React11.useEffect(() => {
2925
+ React12.useEffect(() => {
2761
2926
  if (retracted) setOpenSheet(null);
2762
2927
  }, [retracted]);
2763
2928
  const sheetItem = openSheet != null ? items[openSheet] : void 0;
@@ -2768,12 +2933,8 @@ function MobileBottomNav({
2768
2933
  "aria-label": "Navega\xE7\xE3o principal",
2769
2934
  "aria-hidden": retracted || void 0,
2770
2935
  className: cn(
2771
- // Liquid glass, not a painted strip: the bar sits ON the content, so
2772
- // the content keeps showing through it as a wash. An opaque bar in the
2773
- // page's own colour just cut the screen short; an opaque bar in the
2774
- // RAIL's dark colour made a phone look like it had a second theme.
2775
2936
  "fz-safe-b fixed inset-x-0 bottom-0 z-50 flex min-h-16 items-stretch justify-around md:hidden",
2776
- "fayz-glass-bar text-foreground",
2937
+ "border-t border-sidebar-border bg-sidebar text-sidebar-foreground shadow-[0_-8px_24px_hsl(var(--sidebar)/0.18)]",
2777
2938
  "motion-safe:transition-transform motion-safe:duration-200 motion-safe:ease-out",
2778
2939
  retracted && "pointer-events-none translate-y-full"
2779
2940
  ),
@@ -2826,7 +2987,7 @@ function MobileBottomNav({
2826
2987
  // min-h-[44px] is the floor a finger needs; the bar was letting
2827
2988
  // content decide and landing around 40.
2828
2989
  "relative flex min-h-[44px] flex-1 flex-col items-center justify-center gap-0.5 px-1 py-2 transition-colors",
2829
- isActive ? "text-primary" : "text-muted-foreground"
2990
+ isActive ? "text-sidebar-accent-foreground" : "text-sidebar-muted"
2830
2991
  ),
2831
2992
  children: [
2832
2993
  /* @__PURE__ */ jsx(
@@ -2835,7 +2996,7 @@ function MobileBottomNav({
2835
2996
  "aria-hidden": true,
2836
2997
  className: cn(
2837
2998
  "absolute inset-x-3 top-0 h-0.5 rounded-full transition-opacity",
2838
- isActive ? "bg-primary opacity-100" : "opacity-0"
2999
+ isActive ? "bg-sidebar-accent-foreground opacity-100" : "opacity-0"
2839
3000
  )
2840
3001
  }
2841
3002
  ),
@@ -2933,7 +3094,7 @@ function AppShell({
2933
3094
  const hasBottomNav = !!bottomNav?.length;
2934
3095
  const barOwnsNav = bottomNavReachesAll(bottomNav);
2935
3096
  const menuNavigation = appNavigation ?? navigation;
2936
- const routeLabel = React11.useCallback((path) => {
3097
+ const routeLabel = React12.useCallback((path) => {
2937
3098
  let best;
2938
3099
  const consider = (route, label) => {
2939
3100
  if (!route || !label) return;
@@ -2948,14 +3109,14 @@ function AppShell({
2948
3109
  }
2949
3110
  return best?.label ?? pageTitle ?? "";
2950
3111
  }, [menuNavigation, pageTitle]);
2951
- React11.useEffect(() => {
3112
+ React12.useEffect(() => {
2952
3113
  if (!currentPath) return;
2953
3114
  if (currentPath === MENU_ROUTE) return;
2954
3115
  const label = routeLabel(currentPath);
2955
3116
  if (!label) return;
2956
3117
  recordNavigation(currentPath, label);
2957
3118
  }, [currentPath, routeLabel]);
2958
- const destinationRoutes = React11.useMemo(() => {
3119
+ const destinationRoutes = React12.useMemo(() => {
2959
3120
  const routes = [];
2960
3121
  for (const item of menuNavigation) {
2961
3122
  if (item.route) routes.push(item.route);
@@ -2964,7 +3125,7 @@ function AppShell({
2964
3125
  return routes;
2965
3126
  }, [menuNavigation]);
2966
3127
  const isDestination = !!currentPath && destinationRoutes.includes(currentPath);
2967
- React11.useEffect(() => {
3128
+ React12.useEffect(() => {
2968
3129
  setDestinationRoutes(destinationRoutes);
2969
3130
  }, [destinationRoutes]);
2970
3131
  const pageClaimedBack = useHasPageHeaderBack();
@@ -2972,7 +3133,7 @@ function AppShell({
2972
3133
  const barRetracted = !!pageBack || pageClaimedBack || inSettings;
2973
3134
  const mobileDrawerOpen = useLayoutStore((st) => st.mobileDrawerOpen);
2974
3135
  const setMobileDrawerOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
2975
- React11.useEffect(() => {
3136
+ React12.useEffect(() => {
2976
3137
  if (useLayoutStore.getState().drawerKeepOpenOnce) {
2977
3138
  useLayoutStore.setState({ drawerKeepOpenOnce: false });
2978
3139
  return;
@@ -2980,12 +3141,12 @@ function AppShell({
2980
3141
  setMobileDrawerOpen(false);
2981
3142
  }, [currentPath]);
2982
3143
  const menuRouteOpen = barOwnsNav && currentPath === MENU_ROUTE;
2983
- const firstDestination = React11.useMemo(() => {
3144
+ const firstDestination = React12.useMemo(() => {
2984
3145
  const first = bottomNav?.find((i) => !("kind" in i) || i.kind === "route");
2985
3146
  return first?.route ?? "/";
2986
3147
  }, [bottomNav]);
2987
- const menuOrigin = React11.useRef(void 0);
2988
- const openMenu = React11.useCallback(() => {
3148
+ const menuOrigin = React12.useRef(void 0);
3149
+ const openMenu = React12.useCallback(() => {
2989
3150
  if (!barOwnsNav) {
2990
3151
  setMobileDrawerOpen(true);
2991
3152
  return;
@@ -2996,10 +3157,10 @@ function AppShell({
2996
3157
  menuOrigin.current = currentPath;
2997
3158
  onNavigate?.(MENU_ROUTE);
2998
3159
  }, [barOwnsNav, currentPath, onNavigate, setMobileDrawerOpen]);
2999
- const [menuLeaving, setMenuLeaving] = React11.useState(false);
3000
- const [menuLingering, setMenuLingering] = React11.useState(false);
3001
- const menuTimer = React11.useRef(void 0);
3002
- const dismissMenu = React11.useCallback((navigate) => {
3160
+ const [menuLeaving, setMenuLeaving] = React12.useState(false);
3161
+ const [menuLingering, setMenuLingering] = React12.useState(false);
3162
+ const menuTimer = React12.useRef(void 0);
3163
+ const dismissMenu = React12.useCallback((navigate) => {
3003
3164
  window.clearTimeout(menuTimer.current);
3004
3165
  setMenuLingering(true);
3005
3166
  setMenuLeaving(true);
@@ -3009,8 +3170,8 @@ function AppShell({
3009
3170
  setMenuLingering(false);
3010
3171
  }, 240);
3011
3172
  }, []);
3012
- React11.useEffect(() => () => window.clearTimeout(menuTimer.current), []);
3013
- const closeMenu = React11.useCallback(() => {
3173
+ React12.useEffect(() => () => window.clearTimeout(menuTimer.current), []);
3174
+ const closeMenu = React12.useCallback(() => {
3014
3175
  if (!barOwnsNav) {
3015
3176
  setMobileDrawerOpen(false);
3016
3177
  return;
@@ -3023,7 +3184,7 @@ function AppShell({
3023
3184
  onNavigate?.(back);
3024
3185
  });
3025
3186
  }, [barOwnsNav, setMobileDrawerOpen, onNavigate, firstDestination, dismissMenu]);
3026
- React11.useEffect(() => {
3187
+ React12.useEffect(() => {
3027
3188
  if (!menuRouteOpen || typeof window === "undefined") return;
3028
3189
  const wide = window.matchMedia("(min-width: 768px)");
3029
3190
  const settle = () => {
@@ -3184,13 +3345,13 @@ function SplitWithRightRail({
3184
3345
  maxWidth = 720,
3185
3346
  resizeLabel = "Resize panel"
3186
3347
  }) {
3187
- const [width, setWidth] = React11.useState(defaultWidth);
3188
- const [dragging, setDragging] = React11.useState(false);
3189
- const clamp = React11.useCallback(
3348
+ const [width, setWidth] = React12.useState(defaultWidth);
3349
+ const [dragging, setDragging] = React12.useState(false);
3350
+ const clamp = React12.useCallback(
3190
3351
  (value) => Math.min(maxWidth, Math.max(minWidth, value)),
3191
3352
  [minWidth, maxWidth]
3192
3353
  );
3193
- React11.useEffect(() => {
3354
+ React12.useEffect(() => {
3194
3355
  if (!dragging) return;
3195
3356
  const onMove = (event) => {
3196
3357
  event.preventDefault();
@@ -3212,7 +3373,7 @@ function SplitWithRightRail({
3212
3373
  document.body.style.cursor = previousCursor;
3213
3374
  };
3214
3375
  }, [dragging, clamp]);
3215
- React11.useEffect(() => {
3376
+ React12.useEffect(() => {
3216
3377
  if (dragging) return;
3217
3378
  onWidthChange?.(width);
3218
3379
  }, [dragging]);
@@ -3371,6 +3532,14 @@ function HeaderTabs({
3371
3532
  }
3372
3533
  );
3373
3534
  }
3535
+ var PAGE_BAND_CLASS = "sticky top-0 z-20 -mx-3 -mt-3 mb-4 flex flex-nowrap items-end justify-between gap-3 border-b border-border px-3 pt-2 md:-mx-6 md:-mt-4 md:px-6 md:min-h-[2.5rem]";
3536
+ var PAGE_BAND_SURFACE = { background: "var(--page-surface, hsl(var(--background)))" };
3537
+ function PageBand({ children, actions, className }) {
3538
+ return /* @__PURE__ */ jsxs("div", { style: PAGE_BAND_SURFACE, className: cn(PAGE_BAND_CLASS, "items-center", className), children: [
3539
+ /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-3", children }),
3540
+ actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2 empty:hidden", children: actions })
3541
+ ] });
3542
+ }
3374
3543
  function PageTabs({ actions, className, ...props }) {
3375
3544
  return /* @__PURE__ */ jsxs(
3376
3545
  "div",
@@ -3419,12 +3588,12 @@ function ViewTabs({ value, onChange, options, "aria-label": ariaLabel, className
3419
3588
  );
3420
3589
  }) });
3421
3590
  }
3422
- var NavTransitionContext = React11.createContext("slide");
3591
+ var NavTransitionContext = React12.createContext("slide");
3423
3592
  function NavTransitionProvider({ value, children }) {
3424
3593
  return /* @__PURE__ */ jsx(NavTransitionContext.Provider, { value, children });
3425
3594
  }
3426
3595
  function useNavTransition() {
3427
- return React11.useContext(NavTransitionContext);
3596
+ return React12.useContext(NavTransitionContext);
3428
3597
  }
3429
3598
  function resolveTransitionClass(transition, direction) {
3430
3599
  if (transition === "none") return "";
@@ -3444,26 +3613,26 @@ function PageTransition({
3444
3613
  return /* @__PURE__ */ jsx("div", { className: cn(animClass, className), children }, transitionKey);
3445
3614
  }
3446
3615
  var EMPTY = [];
3447
- var PageTrailContext = React11.createContext(EMPTY);
3616
+ var PageTrailContext = React12.createContext(EMPTY);
3448
3617
  function PageTrail({
3449
3618
  label,
3450
3619
  href,
3451
3620
  onNavigate,
3452
3621
  children
3453
3622
  }) {
3454
- const parent = React11.useContext(PageTrailContext);
3455
- const trail = React11.useMemo(
3623
+ const parent = React12.useContext(PageTrailContext);
3624
+ const trail = React12.useMemo(
3456
3625
  () => [...parent, { label, href, onNavigate }],
3457
3626
  [parent, label, href, onNavigate]
3458
3627
  );
3459
3628
  return /* @__PURE__ */ jsx(PageTrailContext.Provider, { value: trail, children });
3460
3629
  }
3461
3630
  function usePageTrail() {
3462
- return React11.useContext(PageTrailContext);
3631
+ return React12.useContext(PageTrailContext);
3463
3632
  }
3464
3633
  function usePageTrailParent(href) {
3465
- const trail = React11.useContext(PageTrailContext);
3466
- return React11.useMemo(() => {
3634
+ const trail = React12.useContext(PageTrailContext);
3635
+ return React12.useMemo(() => {
3467
3636
  const above = href ? trail.filter((c) => c.href !== href) : trail;
3468
3637
  return above[above.length - 1];
3469
3638
  }, [trail, href]);
@@ -3473,15 +3642,15 @@ function navigateToCrumb(crumb) {
3473
3642
  else window.location.hash = crumb.href;
3474
3643
  }
3475
3644
  function useCurrentRouteHref() {
3476
- const read = () => {
3645
+ const read2 = () => {
3477
3646
  if (typeof window === "undefined") return "";
3478
3647
  const hash = window.location.hash.replace(/^#/, "");
3479
3648
  const clean = hash.split("?")[0];
3480
3649
  return clean.startsWith("/") ? clean : `/${clean}`;
3481
3650
  };
3482
- const [href, setHref] = React11.useState(read);
3483
- React11.useEffect(() => {
3484
- const handler = () => setHref(read());
3651
+ const [href, setHref] = React12.useState(read2);
3652
+ React12.useEffect(() => {
3653
+ const handler = () => setHref(read2());
3485
3654
  window.addEventListener("hashchange", handler);
3486
3655
  handler();
3487
3656
  return () => window.removeEventListener("hashchange", handler);
@@ -3491,11 +3660,246 @@ function useCurrentRouteHref() {
3491
3660
  function useTrailBack(href) {
3492
3661
  const current = useCurrentRouteHref();
3493
3662
  const parent = usePageTrailParent(href ?? current);
3494
- return React11.useMemo(
3663
+ return React12.useMemo(
3495
3664
  () => parent ? { onBack: () => navigateToCrumb(parent), parentLabel: parent.label } : {},
3496
3665
  [parent]
3497
3666
  );
3498
3667
  }
3668
+ var COLUMN_WIDTH = 224;
3669
+ var COLUMN_COLLAPSED_WIDTH = 64;
3670
+ function read(key) {
3671
+ try {
3672
+ return localStorage.getItem(key) === "1";
3673
+ } catch {
3674
+ return false;
3675
+ }
3676
+ }
3677
+ function CollapsibleColumn({
3678
+ children,
3679
+ storageKey,
3680
+ footer,
3681
+ squeezed,
3682
+ autoCollapseKey,
3683
+ autoCollapseMs = 1800,
3684
+ onWidth,
3685
+ className,
3686
+ seamTop = 12,
3687
+ "aria-label": ariaLabel
3688
+ }) {
3689
+ const pinnedKey = `${storageKey}.pinned`;
3690
+ const [collapsed, setCollapsed] = React12.useState(() => read(storageKey));
3691
+ const [pinned, setPinned] = React12.useState(() => read(pinnedKey));
3692
+ const [hovering, setHovering] = React12.useState(false);
3693
+ const hoveringRef = React12.useRef(false);
3694
+ const collapsedRef = React12.useRef(collapsed);
3695
+ collapsedRef.current = collapsed;
3696
+ const autoRef = React12.useRef(false);
3697
+ const open = !collapsed || hovering;
3698
+ const width = open ? COLUMN_WIDTH : COLUMN_COLLAPSED_WIDTH;
3699
+ const setHover = (on) => {
3700
+ hoveringRef.current = on;
3701
+ setHovering(on);
3702
+ };
3703
+ React12.useEffect(() => {
3704
+ onWidth?.(width);
3705
+ }, [width, onWidth]);
3706
+ const setOpenState = React12.useCallback((nextCollapsed) => {
3707
+ setCollapsed(nextCollapsed);
3708
+ setPinned(!nextCollapsed);
3709
+ autoRef.current = false;
3710
+ try {
3711
+ localStorage.setItem(storageKey, nextCollapsed ? "1" : "0");
3712
+ localStorage.setItem(pinnedKey, nextCollapsed ? "0" : "1");
3713
+ } catch {
3714
+ }
3715
+ if (nextCollapsed) setHover(false);
3716
+ }, [storageKey, pinnedKey]);
3717
+ React12.useEffect(() => {
3718
+ if (squeezed === void 0) return;
3719
+ if (squeezed) {
3720
+ if (!collapsedRef.current) {
3721
+ autoRef.current = true;
3722
+ setCollapsed(true);
3723
+ }
3724
+ } else if (autoRef.current) {
3725
+ autoRef.current = false;
3726
+ setCollapsed(false);
3727
+ }
3728
+ }, [squeezed]);
3729
+ const seen = React12.useRef(null);
3730
+ React12.useEffect(() => {
3731
+ if (autoCollapseKey === void 0) return;
3732
+ if (seen.current === null) {
3733
+ seen.current = autoCollapseKey;
3734
+ return;
3735
+ }
3736
+ if (seen.current === autoCollapseKey) return;
3737
+ seen.current = autoCollapseKey;
3738
+ if (collapsed || pinned) return;
3739
+ const t = setTimeout(() => {
3740
+ if (!hoveringRef.current) setCollapsed(true);
3741
+ }, autoCollapseMs);
3742
+ return () => clearTimeout(t);
3743
+ }, [autoCollapseKey, collapsed, pinned, autoCollapseMs]);
3744
+ const scrollRef = React12.useRef(null);
3745
+ const [hasMore, setHasMore] = React12.useState(false);
3746
+ const onScroll = React12.useCallback(() => {
3747
+ const el = scrollRef.current;
3748
+ if (!el) return;
3749
+ setHasMore(el.scrollHeight - el.scrollTop - el.clientHeight > 4);
3750
+ }, []);
3751
+ React12.useEffect(() => {
3752
+ onScroll();
3753
+ const el = scrollRef.current;
3754
+ if (!el) return;
3755
+ const ro = new ResizeObserver(onScroll);
3756
+ ro.observe(el);
3757
+ return () => {
3758
+ ro.disconnect();
3759
+ };
3760
+ }, [onScroll, open, children]);
3761
+ const boxRef = React12.useRef(null);
3762
+ const panelRef = React12.useRef(null);
3763
+ const [seamed, setSeamed] = React12.useState(false);
3764
+ const armedRef = React12.useRef(false);
3765
+ const publish = React12.useCallback(() => {
3766
+ if (!seamTop) return;
3767
+ const el = panelRef.current;
3768
+ const card = el?.closest(".fz-page-surface");
3769
+ const band = card?.firstElementChild;
3770
+ if (!el || !card || !band) return;
3771
+ const root = document.documentElement;
3772
+ const flush = Math.abs(el.getBoundingClientRect().top - band.getBoundingClientRect().bottom) <= 2;
3773
+ setSeamed(flush);
3774
+ if (!flush) {
3775
+ root.style.removeProperty("--page-rail-seam");
3776
+ return;
3777
+ }
3778
+ const x = el.getBoundingClientRect().right - card.getBoundingClientRect().left;
3779
+ if (!armedRef.current) root.style.transition = "none";
3780
+ root.style.setProperty("--page-rail-seam", `${x + seamTop}px`);
3781
+ if (!armedRef.current) {
3782
+ armedRef.current = true;
3783
+ requestAnimationFrame(() => {
3784
+ root.style.transition = "--page-rail-seam 200ms";
3785
+ });
3786
+ }
3787
+ }, [seamTop]);
3788
+ React12.useEffect(() => {
3789
+ publish();
3790
+ }, [publish, width]);
3791
+ React12.useEffect(() => {
3792
+ if (!seamTop) return;
3793
+ const el = panelRef.current;
3794
+ const card = el?.closest(".fz-page-surface");
3795
+ if (!el || !card) return;
3796
+ const root = document.documentElement;
3797
+ const ro = new ResizeObserver(publish);
3798
+ ro.observe(el);
3799
+ ro.observe(card);
3800
+ return () => {
3801
+ ro.disconnect();
3802
+ armedRef.current = false;
3803
+ root.style.transition = "none";
3804
+ root.style.removeProperty("--page-rail-seam");
3805
+ requestAnimationFrame(() => {
3806
+ root.style.removeProperty("transition");
3807
+ });
3808
+ };
3809
+ }, [publish, seamTop]);
3810
+ return (
3811
+ // A caixa RESERVA a largura; a coluna mora dentro dela, posicionada. Sem
3812
+ // isso, reabrir no hover empurraria o conteúdo a cada passada do ponteiro.
3813
+ /* @__PURE__ */ jsxs(
3814
+ "div",
3815
+ {
3816
+ ref: boxRef,
3817
+ className: cn("relative hidden shrink-0 no-print transition-[width] duration-200 md:block", className),
3818
+ style: { width: collapsed ? COLUMN_COLLAPSED_WIDTH : COLUMN_WIDTH },
3819
+ children: [
3820
+ /* @__PURE__ */ jsxs(
3821
+ "nav",
3822
+ {
3823
+ ref: panelRef,
3824
+ "aria-label": ariaLabel,
3825
+ onMouseEnter: () => setHover(true),
3826
+ onMouseLeave: () => setHover(false),
3827
+ onDoubleClick: () => {
3828
+ if (collapsed) setOpenState(false);
3829
+ },
3830
+ style: { width },
3831
+ className: cn(
3832
+ // O vidro é uma classe compartilhada com a faixa do cabeçalho.
3833
+ "fz-liquid-glass absolute inset-y-0 left-0 flex flex-col overflow-hidden p-3 transition-[width] duration-200",
3834
+ collapsed && hovering && "z-30 shadow-xl"
3835
+ ),
3836
+ children: [
3837
+ /* @__PURE__ */ jsx(
3838
+ "span",
3839
+ {
3840
+ "aria-hidden": true,
3841
+ className: "pointer-events-none absolute right-0 w-px",
3842
+ style: { top: seamTop, bottom: 0, background: "hsl(var(--border))" }
3843
+ }
3844
+ ),
3845
+ /* @__PURE__ */ jsxs("div", { className: "relative min-h-0 flex-1", children: [
3846
+ /* @__PURE__ */ jsx("div", { ref: scrollRef, onScroll, className: "scrollbar-none h-full overflow-y-auto overflow-x-hidden", children: children({ collapsed: !open }) }),
3847
+ /* @__PURE__ */ jsx(
3848
+ "div",
3849
+ {
3850
+ "aria-hidden": true,
3851
+ className: cn(
3852
+ "pointer-events-none absolute inset-x-0 bottom-0 h-8 transition-opacity duration-200",
3853
+ hasMore ? "opacity-100" : "opacity-0"
3854
+ ),
3855
+ style: { backgroundImage: "linear-gradient(to top, var(--page-surface, hsl(var(--background))), transparent)" }
3856
+ }
3857
+ )
3858
+ ] }),
3859
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex shrink-0 items-center gap-2 border-t border-border pt-2", children: [
3860
+ open && footer && /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: footer }),
3861
+ /* @__PURE__ */ jsx(
3862
+ "button",
3863
+ {
3864
+ type: "button",
3865
+ onClick: () => setOpenState(!collapsed),
3866
+ "aria-label": collapsed ? "Expandir menu" : "Recolher menu",
3867
+ title: collapsed ? "Expandir menu" : "Recolher menu",
3868
+ "aria-expanded": !collapsed,
3869
+ className: "flex h-8 w-full items-center justify-end rounded-button bg-transparent px-2.5 text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground",
3870
+ children: collapsed ? /* @__PURE__ */ jsx(ChevronsRight, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronsLeft, { className: "h-4 w-4" })
3871
+ }
3872
+ )
3873
+ ] })
3874
+ ]
3875
+ }
3876
+ ),
3877
+ seamed && /* @__PURE__ */ jsx(
3878
+ "svg",
3879
+ {
3880
+ "aria-hidden": true,
3881
+ className: "pointer-events-none absolute top-0",
3882
+ style: { left: `${width - 1}px`, marginTop: "-1px", zIndex: 25, transition: "left 200ms" },
3883
+ width: seamTop,
3884
+ height: seamTop,
3885
+ viewBox: `0 0 ${seamTop} ${seamTop}`,
3886
+ fill: "none",
3887
+ children: /* @__PURE__ */ jsx(
3888
+ "path",
3889
+ {
3890
+ d: `M ${seamTop} 0.5 Q 0.5 0.5 0.5 ${seamTop}`,
3891
+ stroke: "hsl(var(--border))",
3892
+ strokeWidth: "1",
3893
+ fill: "none"
3894
+ }
3895
+ )
3896
+ }
3897
+ )
3898
+ ]
3899
+ }
3900
+ )
3901
+ );
3902
+ }
3499
3903
  function PageRail({ children }) {
3500
3904
  const slot = usePageRailSlot();
3501
3905
  if (slot) return createPortal(children, slot);
@@ -3514,7 +3918,7 @@ function viewBarSubscribe(l) {
3514
3918
  };
3515
3919
  }
3516
3920
  function ViewBarHost() {
3517
- const active = React11.useSyncExternalStore(viewBarSubscribe, () => viewBarCount > 0);
3921
+ const active = React12.useSyncExternalStore(viewBarSubscribe, () => viewBarCount > 0);
3518
3922
  return /* @__PURE__ */ jsx(
3519
3923
  "div",
3520
3924
  {
@@ -3527,8 +3931,8 @@ function ViewBarHost() {
3527
3931
  );
3528
3932
  }
3529
3933
  function PageViewBar({ children }) {
3530
- const slot = React11.useSyncExternalStore(viewBarSubscribe, () => viewBarSlot);
3531
- React11.useEffect(() => {
3934
+ const slot = React12.useSyncExternalStore(viewBarSubscribe, () => viewBarSlot);
3935
+ React12.useEffect(() => {
3532
3936
  viewBarCount++;
3533
3937
  viewBarNotify();
3534
3938
  return () => {
@@ -3539,6 +3943,159 @@ function PageViewBar({ children }) {
3539
3943
  if (slot) return createPortal(children, slot);
3540
3944
  return /* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-end gap-2", children });
3541
3945
  }
3946
+ var SUB_NAV_STYLE = "nested";
3947
+ function RailSections({ sections, search, collapsed }) {
3948
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3949
+ search && !collapsed && /* @__PURE__ */ jsxs("div", { className: "relative mb-2", children: [
3950
+ /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-1 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
3951
+ /* @__PURE__ */ jsx(
3952
+ "input",
3953
+ {
3954
+ type: "search",
3955
+ value: search.value,
3956
+ onChange: (e) => search.onChange(e.target.value),
3957
+ placeholder: search.placeholder,
3958
+ "aria-label": search.placeholder,
3959
+ className: "h-8 w-full border-0 bg-transparent pl-7 pr-2 text-[13px] outline-none placeholder:text-muted-foreground focus:ring-0"
3960
+ }
3961
+ )
3962
+ ] }),
3963
+ sections.map((section, i) => /* @__PURE__ */ jsxs("div", { className: i > 0 ? "mt-3 border-t border-border pt-3" : void 0, children: [
3964
+ section.heading && !collapsed && /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: section.heading }),
3965
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsx(RailNavItem, { item, collapsed }, item.id)) })
3966
+ ] }, section.key ?? i))
3967
+ ] });
3968
+ }
3969
+ var RAIL_COLLAPSED_KEY = "fayz.subnav.collapsed";
3970
+ function RailColumn({ className, "aria-label": ariaLabel, sections, search, footer }) {
3971
+ const boxRef = React12.useRef(null);
3972
+ const [squeezed, setSqueezed] = React12.useState(void 0);
3973
+ React12.useEffect(() => {
3974
+ if (typeof window === "undefined") return;
3975
+ const row = boxRef.current?.parentElement?.parentElement;
3976
+ if (!row) return;
3977
+ const COLLAPSE_BELOW = 560;
3978
+ const RESTORE_ABOVE = 820;
3979
+ let timer;
3980
+ const decide = () => {
3981
+ const content = row.clientWidth - COLUMN_WIDTH;
3982
+ if (content < COLLAPSE_BELOW) setSqueezed(true);
3983
+ else if (content > RESTORE_ABOVE) setSqueezed(false);
3984
+ };
3985
+ const apply = () => {
3986
+ if (timer) clearTimeout(timer);
3987
+ timer = setTimeout(decide, 180);
3988
+ };
3989
+ apply();
3990
+ const ro = new ResizeObserver(apply);
3991
+ ro.observe(row);
3992
+ window.addEventListener("resize", apply);
3993
+ return () => {
3994
+ if (timer) clearTimeout(timer);
3995
+ ro.disconnect();
3996
+ window.removeEventListener("resize", apply);
3997
+ };
3998
+ }, []);
3999
+ const activeKey = sections.flatMap((sec) => sec.items).filter((i) => i.active).map((i) => i.id).join("|");
4000
+ return /* @__PURE__ */ jsx("div", { ref: boxRef, className: "contents", children: /* @__PURE__ */ jsx(
4001
+ CollapsibleColumn,
4002
+ {
4003
+ "aria-label": ariaLabel,
4004
+ storageKey: RAIL_COLLAPSED_KEY,
4005
+ className,
4006
+ footer,
4007
+ squeezed,
4008
+ autoCollapseKey: activeKey,
4009
+ children: ({ collapsed }) => /* @__PURE__ */ jsx(RailSections, { sections, search, collapsed })
4010
+ }
4011
+ ) });
4012
+ }
4013
+ var published = [];
4014
+ var subNavHosts = 0;
4015
+ var subNavListeners = /* @__PURE__ */ new Set();
4016
+ var subNavNotify = () => subNavListeners.forEach((l) => l());
4017
+ var subNavSubscribe = (l) => {
4018
+ subNavListeners.add(l);
4019
+ return () => {
4020
+ subNavListeners.delete(l);
4021
+ };
4022
+ };
4023
+ function publishSubNav(entry) {
4024
+ const i = published.findIndex((p) => p.id === entry.id);
4025
+ published = i < 0 ? [...published, entry] : published.map((p, n) => n === i ? entry : p);
4026
+ subNavNotify();
4027
+ }
4028
+ function unpublishSubNav(id) {
4029
+ published = published.filter((p) => p.id !== id);
4030
+ subNavNotify();
4031
+ }
4032
+ function useSubNavPublished() {
4033
+ return React12.useSyncExternalStore(subNavSubscribe, () => published, () => published);
4034
+ }
4035
+ function useSubNavHost() {
4036
+ React12.useEffect(() => {
4037
+ subNavHosts++;
4038
+ subNavNotify();
4039
+ return () => {
4040
+ subNavHosts--;
4041
+ subNavNotify();
4042
+ };
4043
+ }, []);
4044
+ }
4045
+ function useHasSubNavHost() {
4046
+ return React12.useSyncExternalStore(subNavSubscribe, () => subNavHosts > 0, () => false);
4047
+ }
4048
+ function SubNavBand({ sections, "aria-label": ariaLabel, className }) {
4049
+ const items = sections.flatMap((s) => s.items);
4050
+ const value = items.find((i) => i.active)?.id ?? items[0]?.id;
4051
+ if (!value) return null;
4052
+ return /* @__PURE__ */ jsx(
4053
+ ViewTabs,
4054
+ {
4055
+ className,
4056
+ "aria-label": ariaLabel,
4057
+ options: items.map((i) => ({ value: i.id, label: i.label })),
4058
+ value,
4059
+ onChange: (id) => items.find((i) => i.id === id)?.onClick?.()
4060
+ }
4061
+ );
4062
+ }
4063
+ function SubNavBandHost({ leading, label }) {
4064
+ useSubNavHost();
4065
+ const pubs = useSubNavPublished();
4066
+ const sections = leading ?? pubs.flatMap((p) => p.sections);
4067
+ if (sections.length === 0) return null;
4068
+ return /* @__PURE__ */ jsx(
4069
+ "div",
4070
+ {
4071
+ style: { marginTop: "0.5rem" },
4072
+ className: "flex min-w-0 items-center gap-3",
4073
+ children: /* @__PURE__ */ jsx(SubNavBand, { sections, "aria-label": leading ? label : pubs[0]?.label })
4074
+ }
4075
+ );
4076
+ }
4077
+ function PageSubNav({ items, sections, search, footer, style, "aria-label": ariaLabel }) {
4078
+ const id = React12.useId();
4079
+ const hasHost = useHasSubNavHost();
4080
+ const resolved = sections ?? (items ? [{ items }] : []);
4081
+ const ref = React12.useRef(resolved);
4082
+ ref.current = resolved;
4083
+ const signature = JSON.stringify(resolved.map((s) => [s.key, s.heading, s.items.map((i) => [i.id, i.label, i.icon, !!i.active, !!i.premium])]));
4084
+ React12.useEffect(() => {
4085
+ publishSubNav({ id, label: ariaLabel, sections: ref.current });
4086
+ return () => unpublishSubNav(id);
4087
+ }, [id, ariaLabel, signature]);
4088
+ if (resolved.every((s) => s.items.length === 0)) return null;
4089
+ if (hasHost) return null;
4090
+ const asRail = (style ?? SUB_NAV_STYLE) === "nested";
4091
+ if (!asRail) {
4092
+ return /* @__PURE__ */ jsx("div", { className: "mb-4 flex min-w-0 items-center gap-3", children: /* @__PURE__ */ jsx(SubNavBand, { sections: resolved, "aria-label": ariaLabel }) });
4093
+ }
4094
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4095
+ /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsx(RailColumn, { sections: resolved, search, footer, "aria-label": ariaLabel }) }),
4096
+ /* @__PURE__ */ jsx("div", { className: "mb-4 flex min-w-0 items-center gap-3 md:hidden", children: /* @__PURE__ */ jsx(SubNavBand, { sections: resolved, "aria-label": ariaLabel }) })
4097
+ ] });
4098
+ }
3542
4099
  function PageHeaderActions({ children }) {
3543
4100
  const outlet = usePageActionsOutletSlot();
3544
4101
  const shellSlot = useModuleHeaderActionsSlot();
@@ -3552,15 +4109,18 @@ function PremiumBadge({ className }) {
3552
4109
  const tip = t("upgrade.badgeTooltip");
3553
4110
  return /* @__PURE__ */ jsx("span", { title: tip, "aria-label": tip, className: cn("inline-flex shrink-0", className), children: /* @__PURE__ */ jsx(Crown, { className: "h-3.5 w-3.5 text-amber-500", "aria-hidden": true }) });
3554
4111
  }
3555
- var ModuleLayoutContext = React11.createContext("rail");
4112
+ var ModuleLayoutContext = React12.createContext("rail");
3556
4113
  function ModuleLayoutProvider({ variant, children }) {
3557
4114
  return /* @__PURE__ */ jsx(ModuleLayoutContext.Provider, { value: variant, children });
3558
4115
  }
3559
4116
  function useModuleLayout() {
3560
- return React11.useContext(ModuleLayoutContext);
4117
+ return React12.useContext(ModuleLayoutContext);
3561
4118
  }
3562
- function RailNavItem({ item }) {
3563
- const [expanded, setExpanded] = React11.useState(true);
4119
+ function RailNavItem({ item, collapsed }) {
4120
+ const [expanded, setExpanded] = React12.useState(false);
4121
+ React12.useEffect(() => {
4122
+ if (collapsed) setExpanded(false);
4123
+ }, [collapsed]);
3564
4124
  const Icon = item.icon ? ICON_MAP[item.icon] ?? null : null;
3565
4125
  const hasChildren = item.children && item.children.length > 0;
3566
4126
  const hasActiveChild = hasChildren && item.children.some((c) => c.active);
@@ -3571,36 +4131,53 @@ function RailNavItem({ item }) {
3571
4131
  {
3572
4132
  type: "button",
3573
4133
  "data-tour": `modnav.${item.id}`,
3574
- onClick: () => hasChildren ? setExpanded(!expanded) : item.onClick?.(),
4134
+ onClick: () => hasChildren && !collapsed ? setExpanded(!expanded) : item.onClick?.(),
4135
+ title: collapsed ? item.label : void 0,
3575
4136
  className: cn(
3576
- "flex items-center gap-2 w-full rounded-md px-2.5 py-1.5 text-sm transition-colors",
4137
+ // `px-2.5` NOS DOIS estados: centralizado, o ícone da tira ficava 2px
4138
+ // à direita do mesmo ícone com a coluna aberta, e todos eles davam um
4139
+ // pulinho lateral quando o ponteiro chegava. O recuo é o mesmo; o que
4140
+ // muda é só o rótulo aparecer.
4141
+ // ALTURA FIXA. Com `py-1.5` a linha media o que tinha dentro: 32px com
4142
+ // rótulo (a entrelinha do texto) e 28px só com o ícone — então cada
4143
+ // linha da tira caía num y diferente do da coluna aberta, e a lista
4144
+ // inteira escorregava quando o ponteiro chegava. `h-8` nos dois.
4145
+ "flex h-8 w-full items-center gap-2 rounded-md px-2.5 text-sm transition-colors",
3577
4146
  isActive ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
3578
4147
  ),
3579
4148
  children: [
3580
4149
  Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
3581
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: item.label }),
3582
- item.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" }),
3583
- hasChildren && (expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }))
4150
+ !collapsed && /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: item.label }),
4151
+ !collapsed && item.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" }),
4152
+ !collapsed && hasChildren && (expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }))
3584
4153
  ]
3585
4154
  }
3586
4155
  ),
3587
- hasChildren && expanded && /* @__PURE__ */ jsx("div", { className: "ml-4 mt-0.5 space-y-0.5 border-l pl-2", children: item.children.map((child) => /* @__PURE__ */ jsxs(
3588
- "button",
3589
- {
3590
- type: "button",
3591
- "data-tour": `modnav.${child.id}`,
3592
- onClick: child.onClick,
3593
- className: cn(
3594
- "flex items-center w-full rounded-md px-2.5 py-1 text-xs transition-colors",
3595
- child.active ? "text-primary font-medium bg-primary/5" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
3596
- ),
3597
- children: [
3598
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: child.label }),
3599
- child.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" })
3600
- ]
3601
- },
3602
- child.id
3603
- )) })
4156
+ hasChildren && expanded && !collapsed && /* @__PURE__ */ jsx("div", { className: "relative mt-0.5 text-muted-foreground/45", children: item.children.map((child, i) => {
4157
+ const activeIndex = item.children.findIndex((c) => c.active);
4158
+ return /* @__PURE__ */ jsxs("div", { className: "relative h-8", children: [
4159
+ /* @__PURE__ */ jsx(NavChildConnector, { onPath: activeIndex >= 0 && i < activeIndex, active: !!child.active }),
4160
+ /* @__PURE__ */ jsxs(
4161
+ "button",
4162
+ {
4163
+ type: "button",
4164
+ "data-tour": `modnav.${child.id}`,
4165
+ onClick: child.onClick,
4166
+ className: cn(
4167
+ // `pl-11` passa da ponta da seta (~24px) com folga, para as
4168
+ // filhas lerem como UMA coluna indentada em vez de apertarem
4169
+ // a linha que aponta para elas.
4170
+ "flex h-8 w-full items-center rounded-button pl-11 pr-1 text-sm transition-colors",
4171
+ child.active ? "font-medium text-primary" : "text-muted-foreground hover:text-foreground"
4172
+ ),
4173
+ children: [
4174
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: child.label }),
4175
+ child.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" })
4176
+ ]
4177
+ }
4178
+ )
4179
+ ] }, child.id);
4180
+ }) })
3604
4181
  ] });
3605
4182
  }
3606
4183
  function defaultChildOf(item) {
@@ -3608,9 +4185,9 @@ function defaultChildOf(item) {
3608
4185
  return kids.find((c) => c.defaultChild) ?? kids.find((c) => /(^|-)list$/i.test(c.id)) ?? kids.find((c) => !/(^|-)(new|novo|nova|create)$/i.test(c.id)) ?? kids[0];
3609
4186
  }
3610
4187
  function MobileTabs({ nav }) {
3611
- const scrollRef = React11.useRef(null);
3612
- const [expandedId, setExpandedId] = React11.useState(null);
3613
- React11.useEffect(() => {
4188
+ const scrollRef = React12.useRef(null);
4189
+ const [expandedId, setExpandedId] = React12.useState(null);
4190
+ React12.useEffect(() => {
3614
4191
  const container = scrollRef.current;
3615
4192
  if (!container) return;
3616
4193
  const activeEl = container.querySelector('[data-active="true"]');
@@ -3683,12 +4260,12 @@ function MobileTabs({ nav }) {
3683
4260
  })()
3684
4261
  ] });
3685
4262
  }
3686
- var BackStyleContext = React11.createContext("link");
4263
+ var BackStyleContext = React12.createContext("link");
3687
4264
  function BackStyleProvider({ style, children }) {
3688
4265
  return /* @__PURE__ */ jsx(BackStyleContext.Provider, { value: style, children });
3689
4266
  }
3690
4267
  function useBackStyle() {
3691
- return React11.useContext(BackStyleContext);
4268
+ return React12.useContext(BackStyleContext);
3692
4269
  }
3693
4270
  function SubpageHeader({ title, subtitle, description, icon, onBack, parentLabel, actions, backStyle, inline }) {
3694
4271
  const t = useTranslation();
@@ -3796,11 +4373,18 @@ function ShellSubpageHeader({
3796
4373
  /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx("div", { className: "no-print flex shrink-0 items-center gap-2", children: actions }) })
3797
4374
  ] });
3798
4375
  }
4376
+ function ModuleSubBand({ nav }) {
4377
+ useSubNavHost();
4378
+ const pubs = useSubNavPublished();
4379
+ const activeItem = nav.find((item) => item.active || item.children?.some((c) => c.active));
4380
+ const kids = (activeItem?.children ?? []).filter((c) => c.kind !== "action");
4381
+ kids.find((c) => c.active)?.id ?? kids[0]?.id;
4382
+ const own = [];
4383
+ const sections = own.length ? own : pubs.flatMap((p) => p.sections);
4384
+ if (sections.every((sec) => sec.items.length === 0)) return null;
4385
+ return /* @__PURE__ */ jsx(PageBand, { actions: /* @__PURE__ */ jsx(ViewBarHost, {}), children: /* @__PURE__ */ jsx(SubNavBand, { sections, "aria-label": own.length ? activeItem?.label : pubs[0]?.label }) });
4386
+ }
3799
4387
  function ModuleHeader({ nav }) {
3800
- function defaultChild(item) {
3801
- const kids2 = (item.children ?? []).filter((c) => c.kind !== "action");
3802
- return kids2.find((c) => /list/i.test(c.id) || /^list$/i.test(c.label)) ?? kids2[kids2.length - 1];
3803
- }
3804
4388
  const activeItem = nav.find((item) => item.active || item.children?.some((c) => c.active));
3805
4389
  const tabs = nav.map((item) => ({
3806
4390
  value: item.id,
@@ -3814,23 +4398,12 @@ function ModuleHeader({ nav }) {
3814
4398
  const item = nav.find((n) => n.id === id);
3815
4399
  if (!item) return;
3816
4400
  const hasChildren = item.children && item.children.length > 0;
3817
- if (hasChildren) defaultChild(item)?.onClick?.();
4401
+ if (hasChildren) defaultChildOf(item)?.onClick?.();
3818
4402
  else item.onClick?.();
3819
4403
  };
3820
4404
  const kids = (activeItem?.children ?? []).filter((c) => c.kind !== "action");
3821
4405
  const activeKid = kids.find((c) => c.active)?.id ?? kids[0]?.id;
3822
- const childControl = kids.length > 1 && activeKid ? /* @__PURE__ */ jsxs(PageViewBar, { children: [
3823
- /* @__PURE__ */ jsx(
3824
- ViewTabs,
3825
- {
3826
- "aria-label": activeItem?.label,
3827
- options: kids.map((c) => ({ value: c.id, label: c.label })),
3828
- value: activeKid,
3829
- onChange: (id) => kids.find((c) => c.id === id)?.onClick?.()
3830
- }
3831
- ),
3832
- /* @__PURE__ */ jsx("span", {})
3833
- ] }) : void 0;
4406
+ const childNav = kids.length > 1 && activeKid ? [{ items: kids.map((c) => ({ id: c.id, label: c.label, icon: c.icon, premium: c.premium, active: c.id === activeKid, onClick: c.onClick })) }] : void 0;
3834
4407
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3835
4408
  /* @__PURE__ */ jsx(
3836
4409
  PageTabs,
@@ -3842,14 +4415,14 @@ function ModuleHeader({ nav }) {
3842
4415
  actions: /* @__PURE__ */ jsx(ViewBarHost, {})
3843
4416
  }
3844
4417
  ),
3845
- childControl
4418
+ /* @__PURE__ */ jsx(SubNavBandHost, { leading: childNav, label: activeItem?.label })
3846
4419
  ] });
3847
4420
  }
3848
4421
  function ModulePage({ title: _title, subtitle, nav, children, className, headerAction, showHeader = true, sidebarFooter, navVariant, viewKey, direction, navFilterPlaceholder }) {
3849
4422
  const ctxVariant = useModuleLayout();
3850
4423
  const variant = navVariant ?? ctxVariant;
3851
- const [navQuery, setNavQuery] = React11.useState("");
3852
- const filteredNav = React11.useMemo(() => {
4424
+ const [navQuery, setNavQuery] = React12.useState("");
4425
+ const filteredNav = React12.useMemo(() => {
3853
4426
  const q = navQuery.trim().toLowerCase();
3854
4427
  if (!q) return nav;
3855
4428
  const hit = (label) => label.toLowerCase().includes(q);
@@ -3861,6 +4434,16 @@ function ModulePage({ title: _title, subtitle, nav, children, className, headerA
3861
4434
  }, [nav, navQuery]);
3862
4435
  const transitionKey = viewKey ?? "view";
3863
4436
  const onSubpage = useHasPageHeaderBack();
4437
+ const activeLabel = React12.useMemo(() => {
4438
+ if (onSubpage) return null;
4439
+ for (const item of nav) {
4440
+ const kid = item.children?.find((c) => c.active);
4441
+ if (kid) return kid.label === item.label ? item.label : `${item.label} \u203A ${kid.label}`;
4442
+ if (item.active) return item.label;
4443
+ }
4444
+ return null;
4445
+ }, [nav, onSubpage]);
4446
+ usePublishModuleViewLabel(activeLabel);
3864
4447
  if (variant === "sidebar") {
3865
4448
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3866
4449
  showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
@@ -3875,32 +4458,23 @@ function ModulePage({ title: _title, subtitle, nav, children, className, headerA
3875
4458
  ] });
3876
4459
  }
3877
4460
  return /* @__PURE__ */ jsxs("div", { className: cn("min-w-0", className), children: [
3878
- /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsxs("div", { className: "hidden w-48 shrink-0 flex-col overflow-y-auto border-r border-border p-3 no-print md:flex", children: [
3879
- navFilterPlaceholder && /* @__PURE__ */ jsxs("div", { className: "relative mb-2", children: [
3880
- /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-1 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
3881
- /* @__PURE__ */ jsx(
3882
- "input",
3883
- {
3884
- type: "search",
3885
- value: navQuery,
3886
- onChange: (e) => setNavQuery(e.target.value),
3887
- placeholder: navFilterPlaceholder,
3888
- "aria-label": navFilterPlaceholder,
3889
- className: "h-8 w-full border-0 bg-transparent pl-7 pr-2 text-[13px] outline-none placeholder:text-muted-foreground focus:ring-0"
3890
- }
3891
- )
3892
- ] }),
3893
- /* @__PURE__ */ jsx("nav", { className: "space-y-0.5", children: filteredNav.map((item) => /* @__PURE__ */ jsx(RailNavItem, { item }, item.id)) }),
3894
- sidebarFooter && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-3", children: sidebarFooter })
3895
- ] }) }),
4461
+ /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsx(
4462
+ RailColumn,
4463
+ {
4464
+ sections: [{ items: filteredNav }],
4465
+ search: navFilterPlaceholder ? { value: navQuery, onChange: setNavQuery, placeholder: navFilterPlaceholder } : void 0,
4466
+ footer: sidebarFooter
4467
+ }
4468
+ ) }),
3896
4469
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
3897
4470
  showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
3898
4471
  !onSubpage && /* @__PURE__ */ jsx(MobileTabs, { nav }),
4472
+ !onSubpage && /* @__PURE__ */ jsx(ModuleSubBand, { nav }),
3899
4473
  /* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, children })
3900
4474
  ] })
3901
4475
  ] });
3902
4476
  }
3903
4477
 
3904
- export { AppShell, BackStyleProvider, BottomSheet, HeaderTabs, Hint, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeader, PageHeaderActions, PageHeaderCrumb, PageHeaderOutlet, PageRail, PageTabs, PageTitlePortal, PageTrail, PageTransition, PageViewBar, RailNavItem, SaveBar, SaveBarProvider, SheetCard, SheetRow, ShellSearch, Sidebar, SubpageHeader, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Topbar, ViewTabs, bottomNavReachesAll, isCreateRoute, navigateToCrumb, useBackHandler, useBackStyle, useCrossModuleBack, useCurrentRouteHref, useHasPageActions, useHasPageHeaderBack, useHasPageHeaderHost, useHasPageHeaderOutlet, useLayoutStore, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useNavTransition, usePageHeader, usePageHeaderClaimed, usePageHeaderHost, usePageTrail, usePageTrailParent, useRailRow, useRegisterPageActions, useSaveBar, useSaveBarVisible, useSheetClose, useSheetDrag, useTrailBack };
3905
- //# sourceMappingURL=chunk-PL5CUWNE.js.map
3906
- //# sourceMappingURL=chunk-PL5CUWNE.js.map
4478
+ export { AppShell, BackStyleProvider, BottomSheet, COLUMN_WIDTH, CollapsibleColumn, HeaderTabs, Hint, Modal, ModalBody, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeader, PageHeaderActions, PageHeaderCrumb, PageHeaderOutlet, PageRail, PageSubNav, PageTabs, PageTitlePortal, PageTrail, PageTransition, PageViewBar, RailColumn, RailNavItem, SUB_NAV_STYLE, SaveBar, SaveBarProvider, SheetCard, SheetRow, ShellSearch, Sidebar, SubpageHeader, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Topbar, ViewTabs, bottomNavReachesAll, isCreateRoute, navigateToCrumb, useBackHandler, useBackStyle, useCrossModuleBack, useCurrentRouteHref, useHasPageActions, useHasPageHeaderBack, useHasPageHeaderHost, useHasPageHeaderOutlet, useLayoutStore, useModalHost, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useModuleViewLabel, useNavTransition, usePageHeader, usePageHeaderClaimed, usePageHeaderHost, usePageTrail, usePageTrailParent, usePublishModuleViewLabel, useRailRow, useRegisterPageActions, useSaveBar, useSaveBarVisible, useSheetClose, useSheetDrag, useTrailBack };
4479
+ //# sourceMappingURL=chunk-63BB2CNP.js.map
4480
+ //# sourceMappingURL=chunk-63BB2CNP.js.map