@loafmarkets/ui 0.1.42 → 0.1.43

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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React5 = require('react');
3
+ var React9 = require('react');
4
4
  var reactSlot = require('@radix-ui/react-slot');
5
5
  var classVarianceAuthority = require('class-variance-authority');
6
6
  var clsx = require('clsx');
@@ -33,7 +33,7 @@ function _interopNamespace(e) {
33
33
  return Object.freeze(n);
34
34
  }
35
35
 
36
- var React5__namespace = /*#__PURE__*/_interopNamespace(React5);
36
+ var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
37
37
  var styled24__default = /*#__PURE__*/_interopDefault(styled24);
38
38
  var LightweightCharts__namespace = /*#__PURE__*/_interopNamespace(LightweightCharts);
39
39
 
@@ -75,7 +75,7 @@ var buttonVariants = classVarianceAuthority.cva(
75
75
  }
76
76
  }
77
77
  );
78
- var Button = React5__namespace.forwardRef(
78
+ var Button = React9__namespace.forwardRef(
79
79
  ({ className, variant, size, radius, asChild = false, ...props }, ref) => {
80
80
  const Comp = asChild ? reactSlot.Slot : "button";
81
81
  const coercedRadius = radius ?? (variant === "onboarding" || variant === "onboardingOutline" ? "square" : void 0);
@@ -114,11 +114,11 @@ var badgeVariants = classVarianceAuthority.cva(
114
114
  }
115
115
  }
116
116
  );
117
- var Badge = React5__namespace.forwardRef(
117
+ var Badge = React9__namespace.forwardRef(
118
118
  ({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
119
119
  );
120
120
  Badge.displayName = "Badge";
121
- var Card = React5__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
121
+ var Card = React9__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
122
122
  "div",
123
123
  {
124
124
  ref,
@@ -130,11 +130,11 @@ var Card = React5__namespace.forwardRef(({ className, ...props }, ref) => /* @__
130
130
  }
131
131
  ));
132
132
  Card.displayName = "Card";
133
- var CardHeader = React5__namespace.forwardRef(
133
+ var CardHeader = React9__namespace.forwardRef(
134
134
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
135
135
  );
136
136
  CardHeader.displayName = "CardHeader";
137
- var CardTitle = React5__namespace.forwardRef(
137
+ var CardTitle = React9__namespace.forwardRef(
138
138
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
139
139
  "h3",
140
140
  {
@@ -145,15 +145,15 @@ var CardTitle = React5__namespace.forwardRef(
145
145
  )
146
146
  );
147
147
  CardTitle.displayName = "CardTitle";
148
- var CardDescription = React5__namespace.forwardRef(
148
+ var CardDescription = React9__namespace.forwardRef(
149
149
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-slate-500", className), ...props })
150
150
  );
151
151
  CardDescription.displayName = "CardDescription";
152
- var CardContent = React5__namespace.forwardRef(
152
+ var CardContent = React9__namespace.forwardRef(
153
153
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("px-6 pb-6 pt-2 text-sm text-slate-600", className), ...props })
154
154
  );
155
155
  CardContent.displayName = "CardContent";
156
- var CardFooter = React5__namespace.forwardRef(
156
+ var CardFooter = React9__namespace.forwardRef(
157
157
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex items-center border-t border-slate-100 px-6 py-4", className), ...props })
158
158
  );
159
159
  CardFooter.displayName = "CardFooter";
@@ -171,7 +171,7 @@ var defaultFormatSignedCurrency = (value) => {
171
171
  const sign = value >= 0 ? "+" : "-";
172
172
  return `${sign}${defaultFormatCurrency(Math.abs(value))}`;
173
173
  };
174
- var PortfolioSummary = React5__namespace.forwardRef(
174
+ var PortfolioSummary = React9__namespace.forwardRef(
175
175
  ({
176
176
  availableCash,
177
177
  portfolioValue,
@@ -321,23 +321,23 @@ function HousePositionSlider({
321
321
  className,
322
322
  ...props
323
323
  }) {
324
- const [orderMode, setOrderMode] = React5__namespace.useState("none");
325
- const [buyTrackingMode, setBuyTrackingMode] = React5__namespace.useState("dollars");
326
- const [deltaDollars, setDeltaDollars] = React5__namespace.useState(0);
327
- const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
328
- const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
329
- const [_isDragging, setIsDragging] = React5__namespace.useState(false);
330
- const [visualTargetPct, setVisualTargetPct] = React5__namespace.useState(null);
331
- const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
332
- const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
333
- const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
334
- const [limitPriceDirty, setLimitPriceDirty] = React5__namespace.useState(false);
335
- const [ownershipInput, setOwnershipInput] = React5__namespace.useState("");
336
- const [tokenAmountInput, setTokenAmountInput] = React5__namespace.useState("");
337
- const houseRef = React5__namespace.useRef(null);
324
+ const [orderMode, setOrderMode] = React9__namespace.useState("none");
325
+ const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
326
+ const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
327
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
328
+ const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
329
+ const [_isDragging, setIsDragging] = React9__namespace.useState(false);
330
+ const [visualTargetPct, setVisualTargetPct] = React9__namespace.useState(null);
331
+ const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
332
+ const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
333
+ const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
334
+ const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
335
+ const [ownershipInput, setOwnershipInput] = React9__namespace.useState("");
336
+ const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
337
+ const houseRef = React9__namespace.useRef(null);
338
338
  const asks = orderbook?.asks ?? [];
339
339
  const bids = orderbook?.bids ?? [];
340
- React5__namespace.useEffect(() => {
340
+ React9__namespace.useEffect(() => {
341
341
  if (orderType !== "limit") return;
342
342
  if (limitPriceDirty) return;
343
343
  setLimitPrice(currentPrice);
@@ -412,7 +412,7 @@ function HousePositionSlider({
412
412
  const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
413
413
  const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
414
414
  const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
415
- const resetOrder = React5__namespace.useCallback(() => {
415
+ const resetOrder = React9__namespace.useCallback(() => {
416
416
  setOrderMode("none");
417
417
  setBuyTrackingMode("dollars");
418
418
  setDeltaDollars(0);
@@ -420,7 +420,7 @@ function HousePositionSlider({
420
420
  setDeltaTokensSell(0);
421
421
  setVisualTargetPct(null);
422
422
  }, []);
423
- const updateOrderFromTargetValue = React5__namespace.useCallback(
423
+ const updateOrderFromTargetValue = React9__namespace.useCallback(
424
424
  (newTargetValue) => {
425
425
  const newDeltaValue = newTargetValue - holdingsValue;
426
426
  if (newDeltaValue > 0) {
@@ -444,7 +444,7 @@ function HousePositionSlider({
444
444
  },
445
445
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, resetOrder, tokensHeld]
446
446
  );
447
- const updateOrderFromOwnership = React5__namespace.useCallback(
447
+ const updateOrderFromOwnership = React9__namespace.useCallback(
448
448
  (newOwnershipPercent) => {
449
449
  const nextOwnership = clamp(newOwnershipPercent, 0, 100);
450
450
  const newTargetTokens = nextOwnership / 100 * totalTokens;
@@ -453,7 +453,7 @@ function HousePositionSlider({
453
453
  },
454
454
  [effectivePrice, totalTokens, updateOrderFromTargetValue]
455
455
  );
456
- const updateOrderFromTokenAmount = React5__namespace.useCallback(
456
+ const updateOrderFromTokenAmount = React9__namespace.useCallback(
457
457
  (tokenAmountSigned) => {
458
458
  if (tokenAmountSigned > 0) {
459
459
  const maxTokens = effectiveAvailableCash / (effectivePrice || 1);
@@ -476,7 +476,7 @@ function HousePositionSlider({
476
476
  },
477
477
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, resetOrder]
478
478
  );
479
- const updateOrderFromSlider = React5__namespace.useCallback(
479
+ const updateOrderFromSlider = React9__namespace.useCallback(
480
480
  (pct) => {
481
481
  const normalized = (pct - 50) / 50;
482
482
  const magnitude = Math.min(Math.abs(normalized), 1);
@@ -520,7 +520,7 @@ function HousePositionSlider({
520
520
  },
521
521
  [effectiveAvailableCash, effectiveTokensHeld, resetOrder]
522
522
  );
523
- const handleDragAtClientY = React5__namespace.useCallback(
523
+ const handleDragAtClientY = React9__namespace.useCallback(
524
524
  (clientY) => {
525
525
  if (!houseRef.current) return;
526
526
  const rect = houseRef.current.getBoundingClientRect();
@@ -1036,18 +1036,18 @@ function HousePositionSliderMobile({
1036
1036
  className,
1037
1037
  ...props
1038
1038
  }) {
1039
- const [orderMode, setOrderMode] = React5__namespace.useState("none");
1040
- const [deltaDollars, setDeltaDollars] = React5__namespace.useState(0);
1041
- const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
1042
- const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
1043
- const [buyTrackingMode, setBuyTrackingMode] = React5__namespace.useState("dollars");
1044
- const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
1045
- const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
1046
- const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
1047
- const [limitPriceDirty, setLimitPriceDirty] = React5__namespace.useState(false);
1048
- const [tokenAmountInput, setTokenAmountInput] = React5__namespace.useState("");
1049
- const houseRef = React5__namespace.useRef(null);
1050
- React5__namespace.useEffect(() => {
1039
+ const [orderMode, setOrderMode] = React9__namespace.useState("none");
1040
+ const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
1041
+ const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
1042
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
1043
+ const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
1044
+ const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
1045
+ const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
1046
+ const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
1047
+ const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
1048
+ const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
1049
+ const houseRef = React9__namespace.useRef(null);
1050
+ React9__namespace.useEffect(() => {
1051
1051
  if (orderType !== "limit") return;
1052
1052
  if (limitPriceDirty) return;
1053
1053
  setLimitPrice(currentPrice);
@@ -1089,7 +1089,7 @@ function HousePositionSliderMobile({
1089
1089
  const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
1090
1090
  const targetOwnership = totalTokens > 0 ? targetTokens / totalTokens * 100 : 0;
1091
1091
  const estFeeTokens = effectivePrice > 0 ? Math.abs(deltaValue) * 5e-3 / effectivePrice : 0;
1092
- const updateOrderFromTargetValue = React5__namespace.useCallback(
1092
+ const updateOrderFromTargetValue = React9__namespace.useCallback(
1093
1093
  (newTargetValue) => {
1094
1094
  const newDeltaValue = newTargetValue - holdingsValue;
1095
1095
  if (newDeltaValue > 0.01) {
@@ -1117,7 +1117,7 @@ function HousePositionSliderMobile({
1117
1117
  },
1118
1118
  [holdingsValue, availableCash, effectivePrice, tokensHeld]
1119
1119
  );
1120
- const updateOrderFromTokenAmount = React5__namespace.useCallback(
1120
+ const updateOrderFromTokenAmount = React9__namespace.useCallback(
1121
1121
  (tokenAmount) => {
1122
1122
  if (tokenAmount > 0) {
1123
1123
  const maxTokens = effectivePrice > 0 ? availableCash / effectivePrice : 0;
@@ -1144,14 +1144,14 @@ function HousePositionSliderMobile({
1144
1144
  },
1145
1145
  [effectivePrice, availableCash, tokensHeld]
1146
1146
  );
1147
- const handleMarkerClick = React5__namespace.useCallback(
1147
+ const handleMarkerClick = React9__namespace.useCallback(
1148
1148
  (pct) => {
1149
1149
  const newTargetValue = pct / 100 * totalCapacity;
1150
1150
  updateOrderFromTargetValue(newTargetValue);
1151
1151
  },
1152
1152
  [totalCapacity, updateOrderFromTargetValue]
1153
1153
  );
1154
- const onMouseDown = React5__namespace.useCallback(
1154
+ const onMouseDown = React9__namespace.useCallback(
1155
1155
  (e) => {
1156
1156
  e.preventDefault();
1157
1157
  const move = (ev) => {
@@ -1171,7 +1171,7 @@ function HousePositionSliderMobile({
1171
1171
  },
1172
1172
  [totalCapacity, updateOrderFromTargetValue]
1173
1173
  );
1174
- const onTouchStart = React5__namespace.useCallback(
1174
+ const onTouchStart = React9__namespace.useCallback(
1175
1175
  (e) => {
1176
1176
  e.preventDefault();
1177
1177
  e.stopPropagation();
@@ -1729,7 +1729,7 @@ var LiquidityText = styled24__default.default.span`
1729
1729
  letter-spacing: 0.1px;
1730
1730
  }
1731
1731
  `;
1732
- var LoafLiquidityBadge = React5__namespace.forwardRef(
1732
+ var LoafLiquidityBadge = React9__namespace.forwardRef(
1733
1733
  ({ className, isGlowing, onClick, children, ...props }, ref) => {
1734
1734
  return /* @__PURE__ */ jsxRuntime.jsxs(
1735
1735
  LogoContainer,
@@ -1757,9 +1757,34 @@ var LoafLiquidityBadge = React5__namespace.forwardRef(
1757
1757
  }
1758
1758
  );
1759
1759
  LoafLiquidityBadge.displayName = "LoafLiquidityBadge";
1760
+ var toSize = (v, fallback) => v == null ? fallback : typeof v === "number" ? `${v}px` : v;
1761
+ var Skeleton = React9__namespace.forwardRef(
1762
+ ({ width, height, radius, className, style, ...props }, ref) => {
1763
+ return /* @__PURE__ */ jsxRuntime.jsx(
1764
+ "div",
1765
+ {
1766
+ ref,
1767
+ "aria-busy": "true",
1768
+ "aria-live": "polite",
1769
+ className: cn(
1770
+ "inline-block align-middle bg-white/10 animate-pulse",
1771
+ className
1772
+ ),
1773
+ style: {
1774
+ width: toSize(width, "100%"),
1775
+ height: toSize(height, "1em"),
1776
+ borderRadius: toSize(radius, "6px"),
1777
+ ...style
1778
+ },
1779
+ ...props
1780
+ }
1781
+ );
1782
+ }
1783
+ );
1784
+ Skeleton.displayName = "Skeleton";
1760
1785
  function useViewportCompact(breakpoint) {
1761
- const [isCompact, setIsCompact] = React5__namespace.useState(false);
1762
- React5__namespace.useEffect(() => {
1786
+ const [isCompact, setIsCompact] = React9__namespace.useState(false);
1787
+ React9__namespace.useEffect(() => {
1763
1788
  if (typeof window === "undefined") return;
1764
1789
  const check = () => setIsCompact(window.innerWidth <= breakpoint);
1765
1790
  check();
@@ -1769,16 +1794,119 @@ function useViewportCompact(breakpoint) {
1769
1794
  return isCompact;
1770
1795
  }
1771
1796
  var formatNumber = (value, precision) => value.toFixed(precision);
1797
+ var FLASH_DURATION_MS = 450;
1798
+ var FLASH_UP_COLOR = "rgba(14, 203, 129, 0.35)";
1799
+ var FLASH_DOWN_COLOR = "rgba(246, 70, 93, 0.35)";
1800
+ function getTradeKey(trade, fallbackIndex) {
1801
+ if (trade.tradeId != null) return `id-${trade.tradeId}`;
1802
+ if (trade.time != null) return `t-${trade.time}-${trade.type}-${trade.price}-${trade.amount}`;
1803
+ return `idx-${fallbackIndex}-${trade.type}-${trade.price}-${trade.amount}`;
1804
+ }
1805
+ function useAmountChangeFlash(ref, amount) {
1806
+ const prevAmountRef = React9__namespace.useRef(amount);
1807
+ React9__namespace.useEffect(() => {
1808
+ const prev = prevAmountRef.current;
1809
+ const node = ref.current;
1810
+ if (prev !== amount && node && typeof node.animate === "function") {
1811
+ const color = amount > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1812
+ node.animate(
1813
+ [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1814
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1815
+ );
1816
+ }
1817
+ prevAmountRef.current = amount;
1818
+ }, [amount, ref]);
1819
+ }
1820
+ function useMidPriceFlash(ref, midPrice, restBgColor) {
1821
+ const prevMidRef = React9__namespace.useRef(midPrice);
1822
+ React9__namespace.useEffect(() => {
1823
+ const prev = prevMidRef.current;
1824
+ const node = ref.current;
1825
+ if (prev !== midPrice && prev > 0 && midPrice > 0 && node && typeof node.animate === "function") {
1826
+ const color = midPrice > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1827
+ node.animate(
1828
+ [{ backgroundColor: color }, { backgroundColor: restBgColor }],
1829
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1830
+ );
1831
+ }
1832
+ prevMidRef.current = midPrice;
1833
+ }, [midPrice, ref, restBgColor]);
1834
+ }
1835
+ function TradeRow({
1836
+ trade,
1837
+ tradeKey,
1838
+ precision,
1839
+ amountPrecision,
1840
+ seenTradeKeysRef,
1841
+ compact
1842
+ }) {
1843
+ const rowRef = React9__namespace.useRef(null);
1844
+ const { type } = trade;
1845
+ React9__namespace.useEffect(() => {
1846
+ if (seenTradeKeysRef.current.has(tradeKey)) return;
1847
+ seenTradeKeysRef.current.add(tradeKey);
1848
+ const node = rowRef.current;
1849
+ if (!node || typeof node.animate !== "function") return;
1850
+ const color = type === "buy" ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1851
+ node.animate(
1852
+ [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1853
+ { duration: FLASH_DURATION_MS, easing: "ease-out" }
1854
+ );
1855
+ }, [tradeKey, seenTradeKeysRef, type]);
1856
+ if (compact) {
1857
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1858
+ "div",
1859
+ {
1860
+ ref: rowRef,
1861
+ className: "grid",
1862
+ style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
1863
+ children: [
1864
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 }, children: [
1865
+ "$",
1866
+ formatNumber(trade.price, precision)
1867
+ ] }),
1868
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
1869
+ ]
1870
+ }
1871
+ );
1872
+ }
1873
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1874
+ "div",
1875
+ {
1876
+ ref: rowRef,
1877
+ className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
1878
+ children: [
1879
+ /* @__PURE__ */ jsxRuntime.jsxs(
1880
+ "div",
1881
+ {
1882
+ className: cn(
1883
+ "tabular-nums",
1884
+ trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
1885
+ ),
1886
+ children: [
1887
+ "$",
1888
+ formatNumber(trade.price, precision)
1889
+ ]
1890
+ }
1891
+ ),
1892
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
1893
+ ]
1894
+ }
1895
+ );
1896
+ }
1772
1897
  function DepthRow({
1773
1898
  side,
1774
1899
  price,
1775
1900
  amount,
1776
1901
  depthPct,
1777
1902
  precision,
1778
- amountPrecision
1903
+ amountPrecision,
1904
+ hasUserOrder
1779
1905
  }) {
1780
1906
  const isAsk = side === "ask";
1781
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
1907
+ const rowRef = React9__namespace.useRef(null);
1908
+ useAmountChangeFlash(rowRef, amount);
1909
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rowRef, className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
1782
1910
  /* @__PURE__ */ jsxRuntime.jsx(
1783
1911
  "div",
1784
1912
  {
@@ -1786,9 +1914,16 @@ function DepthRow({
1786
1914
  "absolute inset-y-0 right-0",
1787
1915
  isAsk ? "bg-rose-900/30" : "bg-emerald-900/30"
1788
1916
  ),
1789
- style: { width: `${clamp3(depthPct, 0, 100)}%` }
1917
+ style: { width: `${clamp3(depthPct, 0, 100)}%`, transition: "width 300ms ease-out" }
1790
1918
  }
1791
1919
  ),
1920
+ hasUserOrder ? /* @__PURE__ */ jsxRuntime.jsx(
1921
+ "span",
1922
+ {
1923
+ "aria-label": "Your order at this price",
1924
+ className: "absolute left-0 top-0 bottom-0 z-[2] w-[3px] rounded-r-sm bg-[#C9A227] shadow-[0_0_6px_rgba(201,162,39,0.6)]"
1925
+ }
1926
+ ) : null,
1792
1927
  /* @__PURE__ */ jsxRuntime.jsxs(
1793
1928
  "div",
1794
1929
  {
@@ -1808,7 +1943,7 @@ var DEPTH_ROW_HEIGHT_PX = 34;
1808
1943
  var COMPACT_ROWS_VISIBLE = 5;
1809
1944
  var COMPACT_ROW_HEIGHT_PX = 30;
1810
1945
  var COMPACT_BREAKPOINT_PX = 1024;
1811
- var Orderbook = React5__namespace.forwardRef(
1946
+ var Orderbook = React9__namespace.forwardRef(
1812
1947
  ({
1813
1948
  asks,
1814
1949
  bids,
@@ -1823,13 +1958,44 @@ var Orderbook = React5__namespace.forwardRef(
1823
1958
  onTabChange,
1824
1959
  rightHeader = /* @__PURE__ */ jsxRuntime.jsx(LoafLiquidityBadge, { className: "text-[0.6rem]" }),
1825
1960
  variant = "auto",
1961
+ userOrderPrices,
1962
+ isLoading = false,
1826
1963
  className,
1827
1964
  ...props
1828
1965
  }, ref) => {
1829
- const [tab, setTab] = React5__namespace.useState(defaultTab);
1830
- const [tradeFilter, setTradeFilter] = React5__namespace.useState("all");
1966
+ const [tab, setTab] = React9__namespace.useState(defaultTab);
1967
+ const [tradeFilter, setTradeFilter] = React9__namespace.useState("all");
1831
1968
  const viewportCompact = useViewportCompact(COMPACT_BREAKPOINT_PX);
1832
- React5__namespace.useEffect(() => {
1969
+ const { userAskPrices, userBidPrices } = React9__namespace.useMemo(() => {
1970
+ const ask = /* @__PURE__ */ new Set();
1971
+ const bid = /* @__PURE__ */ new Set();
1972
+ if (!userOrderPrices) return { userAskPrices: ask, userBidPrices: bid };
1973
+ for (const entry of userOrderPrices) {
1974
+ if (entry.side === "SELL") ask.add(entry.price);
1975
+ else bid.add(entry.price);
1976
+ }
1977
+ return { userAskPrices: ask, userBidPrices: bid };
1978
+ }, [userOrderPrices]);
1979
+ const seenTradeKeysRef = React9__namespace.useRef(/* @__PURE__ */ new Set());
1980
+ const initializedRef = React9__namespace.useRef(false);
1981
+ if (!initializedRef.current && trades.length > 0) {
1982
+ for (let i = 0; i < trades.length; i++) {
1983
+ seenTradeKeysRef.current.add(getTradeKey(trades[i], i));
1984
+ }
1985
+ initializedRef.current = true;
1986
+ }
1987
+ React9__namespace.useEffect(() => {
1988
+ if (!initializedRef.current) return;
1989
+ const live = /* @__PURE__ */ new Set();
1990
+ for (let i = 0; i < trades.length; i++) {
1991
+ live.add(getTradeKey(trades[i], i));
1992
+ }
1993
+ const seen = seenTradeKeysRef.current;
1994
+ for (const key of seen) {
1995
+ if (!live.has(key)) seen.delete(key);
1996
+ }
1997
+ }, [trades]);
1998
+ React9__namespace.useEffect(() => {
1833
1999
  setTab(defaultTab);
1834
2000
  }, [defaultTab]);
1835
2001
  const handleTab = (next) => {
@@ -1860,7 +2026,11 @@ var Orderbook = React5__namespace.forwardRef(
1860
2026
  midPrice,
1861
2027
  midChangePercent,
1862
2028
  midClass,
1863
- sectionHeight
2029
+ sectionHeight,
2030
+ userAskPrices,
2031
+ userBidPrices,
2032
+ isLoading,
2033
+ seenTradeKeysRef
1864
2034
  };
1865
2035
  return /* @__PURE__ */ jsxRuntime.jsx(
1866
2036
  Card,
@@ -1878,6 +2048,29 @@ var Orderbook = React5__namespace.forwardRef(
1878
2048
  }
1879
2049
  );
1880
2050
  Orderbook.displayName = "Orderbook";
2051
+ function SkeletonRow({ compact }) {
2052
+ if (compact) {
2053
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2054
+ "div",
2055
+ {
2056
+ style: {
2057
+ display: "grid",
2058
+ gridTemplateColumns: "1.2fr 0.8fr",
2059
+ padding: "0.2rem 0",
2060
+ alignItems: "center"
2061
+ },
2062
+ children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "60%", height: 10 }) }),
2064
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 10 }) })
2065
+ ]
2066
+ }
2067
+ );
2068
+ }
2069
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
2070
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "60%", height: 12 }),
2071
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: "50%", height: 12 }) })
2072
+ ] });
2073
+ }
1881
2074
  function DesktopOrderbookLayout({
1882
2075
  tab,
1883
2076
  handleTab,
@@ -1896,8 +2089,14 @@ function DesktopOrderbookLayout({
1896
2089
  midPrice,
1897
2090
  midChangePercent,
1898
2091
  midClass,
1899
- sectionHeight
2092
+ sectionHeight,
2093
+ userAskPrices,
2094
+ userBidPrices,
2095
+ isLoading,
2096
+ seenTradeKeysRef
1900
2097
  }) {
2098
+ const midRef = React9__namespace.useRef(null);
2099
+ useMidPriceFlash(midRef, midPrice, "#0b1a24");
1901
2100
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1902
2101
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pt-4", children: [
1903
2102
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
@@ -1981,29 +2180,20 @@ function DesktopOrderbookLayout({
1981
2180
  {
1982
2181
  className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
1983
2182
  style: { scrollbarGutter: "stable" },
1984
- children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1985
- "div",
1986
- {
1987
- className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
1988
- children: [
1989
- /* @__PURE__ */ jsxRuntime.jsxs(
1990
- "div",
1991
- {
1992
- className: cn(
1993
- "tabular-nums",
1994
- trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
1995
- ),
1996
- children: [
1997
- "$",
1998
- formatNumber(trade.price, precision)
1999
- ]
2000
- }
2001
- ),
2002
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
2003
- ]
2004
- },
2005
- `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
2006
- )) })
2183
+ children: isLoading && tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `trade-skel-${i}`)) }) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => {
2184
+ const tradeKey = getTradeKey(trade, i);
2185
+ return /* @__PURE__ */ jsxRuntime.jsx(
2186
+ TradeRow,
2187
+ {
2188
+ trade,
2189
+ tradeKey,
2190
+ precision,
2191
+ amountPrecision,
2192
+ seenTradeKeysRef
2193
+ },
2194
+ tradeKey
2195
+ );
2196
+ }) })
2007
2197
  }
2008
2198
  ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col min-h-0", children: [
2009
2199
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2011,7 +2201,7 @@ function DesktopOrderbookLayout({
2011
2201
  {
2012
2202
  className: "flex flex-col justify-end divide-y divide-white/5 overflow-y-auto",
2013
2203
  style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
2014
- children: asks.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2204
+ children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `ask-skel-${i}`)) : asks.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2015
2205
  DepthRow,
2016
2206
  {
2017
2207
  side: "ask",
@@ -2019,30 +2209,38 @@ function DesktopOrderbookLayout({
2019
2209
  amount: l.amount,
2020
2210
  depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
2021
2211
  precision,
2022
- amountPrecision
2212
+ amountPrecision,
2213
+ hasUserOrder: userAskPrices.has(l.price)
2023
2214
  },
2024
- `ask-${idx}-${l.price}-${l.amount}`
2215
+ `ask-${l.price}`
2025
2216
  ))
2026
2217
  }
2027
2218
  ),
2028
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2", children: [
2029
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: [
2030
- "$",
2031
- formatNumber(midPrice, precision),
2032
- midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2033
- midChangePercent >= 0 ? "+" : "",
2034
- midChangePercent.toFixed(2),
2035
- "%"
2036
- ] })
2037
- ] }),
2038
- /* @__PURE__ */ jsxRuntime.jsx("div", {})
2039
- ] }),
2219
+ /* @__PURE__ */ jsxRuntime.jsxs(
2220
+ "div",
2221
+ {
2222
+ ref: midRef,
2223
+ className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2",
2224
+ children: [
2225
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 20 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2226
+ "$",
2227
+ formatNumber(midPrice, precision),
2228
+ midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2229
+ midChangePercent >= 0 ? "+" : "",
2230
+ midChangePercent.toFixed(2),
2231
+ "%"
2232
+ ] })
2233
+ ] }) }),
2234
+ /* @__PURE__ */ jsxRuntime.jsx("div", {})
2235
+ ]
2236
+ }
2237
+ ),
2040
2238
  /* @__PURE__ */ jsxRuntime.jsx(
2041
2239
  "div",
2042
2240
  {
2043
2241
  className: "divide-y divide-white/5 overflow-y-auto",
2044
2242
  style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
2045
- children: bids.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2243
+ children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `bid-skel-${i}`)) : bids.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2046
2244
  DepthRow,
2047
2245
  {
2048
2246
  side: "bid",
@@ -2050,9 +2248,10 @@ function DesktopOrderbookLayout({
2050
2248
  amount: l.amount,
2051
2249
  depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
2052
2250
  precision,
2053
- amountPrecision
2251
+ amountPrecision,
2252
+ hasUserOrder: userBidPrices.has(l.price)
2054
2253
  },
2055
- `bid-${idx}-${l.price}-${l.amount}`
2254
+ `bid-${l.price}`
2056
2255
  ))
2057
2256
  }
2058
2257
  )
@@ -2078,10 +2277,16 @@ function MobileOrderbookLayout({
2078
2277
  midPrice,
2079
2278
  midChangePercent,
2080
2279
  midClass,
2081
- sectionHeight: _sectionHeight
2280
+ sectionHeight: _sectionHeight,
2281
+ userAskPrices,
2282
+ userBidPrices,
2283
+ isLoading,
2284
+ seenTradeKeysRef
2082
2285
  }) {
2083
- const visibleAsks = React5__namespace.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
2084
- const visibleBids = React5__namespace.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
2286
+ const midRef = React9__namespace.useRef(null);
2287
+ useMidPriceFlash(midRef, midPrice, "transparent");
2288
+ const visibleAsks = React9__namespace.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
2289
+ const visibleBids = React9__namespace.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
2085
2290
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2086
2291
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2087
2292
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
@@ -2150,7 +2355,7 @@ function MobileOrderbookLayout({
2150
2355
  ]
2151
2356
  }
2152
2357
  ),
2153
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: visibleAsks.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2358
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-ask-skel-${i}`)) : visibleAsks.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2154
2359
  MobileDepthRow,
2155
2360
  {
2156
2361
  side: "ask",
@@ -2158,13 +2363,15 @@ function MobileOrderbookLayout({
2158
2363
  amount: l.amount,
2159
2364
  depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
2160
2365
  precision,
2161
- amountPrecision
2366
+ amountPrecision,
2367
+ hasUserOrder: userAskPrices.has(l.price)
2162
2368
  },
2163
- `mobile-ask-${idx}-${l.price}-${l.amount}`
2369
+ `mobile-ask-${l.price}`
2164
2370
  )) }),
2165
2371
  /* @__PURE__ */ jsxRuntime.jsxs(
2166
2372
  "div",
2167
2373
  {
2374
+ ref: midRef,
2168
2375
  className: "grid",
2169
2376
  style: {
2170
2377
  gridTemplateColumns: "1.2fr 0.8fr",
@@ -2174,12 +2381,12 @@ function MobileOrderbookLayout({
2174
2381
  borderBottom: "1px solid rgba(255,255,255,0.1)"
2175
2382
  },
2176
2383
  children: [
2177
- /* @__PURE__ */ jsxRuntime.jsxs(
2384
+ /* @__PURE__ */ jsxRuntime.jsx(
2178
2385
  "div",
2179
2386
  {
2180
2387
  style: { fontWeight: "bold", display: "flex", alignItems: "center", gap: "8px" },
2181
2388
  className: midClass,
2182
- children: [
2389
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 90, height: 16 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2183
2390
  "$",
2184
2391
  formatNumber(midPrice, precision),
2185
2392
  midChangePercent != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-[0.75rem] font-semibold tabular-nums", midClass), children: [
@@ -2187,14 +2394,14 @@ function MobileOrderbookLayout({
2187
2394
  midChangePercent.toFixed(2),
2188
2395
  "%"
2189
2396
  ] })
2190
- ]
2397
+ ] })
2191
2398
  }
2192
2399
  ),
2193
2400
  /* @__PURE__ */ jsxRuntime.jsx("div", {})
2194
2401
  ]
2195
2402
  }
2196
2403
  ),
2197
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: visibleBids.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
2404
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-bid-skel-${i}`)) : visibleBids.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
2198
2405
  MobileDepthRow,
2199
2406
  {
2200
2407
  side: "bid",
@@ -2202,9 +2409,10 @@ function MobileOrderbookLayout({
2202
2409
  amount: l.amount,
2203
2410
  depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
2204
2411
  precision,
2205
- amountPrecision
2412
+ amountPrecision,
2413
+ hasUserOrder: userBidPrices.has(l.price)
2206
2414
  },
2207
- `mobile-bid-${idx}-${l.price}-${l.amount}`
2415
+ `mobile-bid-${l.price}`
2208
2416
  )) })
2209
2417
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden px-3 pb-2", children: [
2210
2418
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2218,27 +2426,21 @@ function MobileOrderbookLayout({
2218
2426
  ]
2219
2427
  }
2220
2428
  ),
2221
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2222
- "div",
2223
- {
2224
- className: "grid",
2225
- style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
2226
- children: [
2227
- /* @__PURE__ */ jsxRuntime.jsxs(
2228
- "div",
2229
- {
2230
- style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 },
2231
- children: [
2232
- "$",
2233
- formatNumber(trade.price, precision)
2234
- ]
2235
- }
2236
- ),
2237
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
2238
- ]
2239
- },
2240
- `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
2241
- )) })
2429
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: isLoading && tradeFiltered.length === 0 ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, { compact: true }, `m-trade-skel-${i}`)) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => {
2430
+ const tradeKey = getTradeKey(trade, i);
2431
+ return /* @__PURE__ */ jsxRuntime.jsx(
2432
+ TradeRow,
2433
+ {
2434
+ trade,
2435
+ tradeKey,
2436
+ precision,
2437
+ amountPrecision,
2438
+ seenTradeKeysRef,
2439
+ compact: true
2440
+ },
2441
+ tradeKey
2442
+ );
2443
+ }) })
2242
2444
  ] })
2243
2445
  ] });
2244
2446
  }
@@ -2248,12 +2450,16 @@ function MobileDepthRow({
2248
2450
  amount,
2249
2451
  depthPct,
2250
2452
  precision,
2251
- amountPrecision
2453
+ amountPrecision,
2454
+ hasUserOrder
2252
2455
  }) {
2253
2456
  const isAsk = side === "ask";
2457
+ const rowRef = React9__namespace.useRef(null);
2458
+ useAmountChangeFlash(rowRef, amount);
2254
2459
  return /* @__PURE__ */ jsxRuntime.jsxs(
2255
2460
  "div",
2256
2461
  {
2462
+ ref: rowRef,
2257
2463
  style: {
2258
2464
  display: "grid",
2259
2465
  gridTemplateColumns: "1.2fr 0.8fr",
@@ -2262,6 +2468,24 @@ function MobileDepthRow({
2262
2468
  position: "relative"
2263
2469
  },
2264
2470
  children: [
2471
+ hasUserOrder ? /* @__PURE__ */ jsxRuntime.jsx(
2472
+ "span",
2473
+ {
2474
+ "aria-label": "Your order at this price",
2475
+ style: {
2476
+ position: "absolute",
2477
+ left: 0,
2478
+ top: 0,
2479
+ bottom: 0,
2480
+ width: "3px",
2481
+ backgroundColor: "#C9A227",
2482
+ boxShadow: "0 0 6px rgba(201,162,39,0.6)",
2483
+ borderTopRightRadius: "2px",
2484
+ borderBottomRightRadius: "2px",
2485
+ zIndex: 2
2486
+ }
2487
+ }
2488
+ ) : null,
2265
2489
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1, color: isAsk ? "#f6465d" : "#0ecb81" }, children: [
2266
2490
  "$",
2267
2491
  formatNumber(price, precision)
@@ -2278,7 +2502,8 @@ function MobileDepthRow({
2278
2502
  width: `${clamp3(depthPct, 0, 100)}%`,
2279
2503
  backgroundColor: isAsk ? "#f6465d" : "#0ecb81",
2280
2504
  opacity: 0.1,
2281
- zIndex: 0
2505
+ zIndex: 0,
2506
+ transition: "width 300ms ease-out"
2282
2507
  }
2283
2508
  }
2284
2509
  )
@@ -2286,7 +2511,7 @@ function MobileDepthRow({
2286
2511
  }
2287
2512
  );
2288
2513
  }
2289
- var PropertyTour = React5__namespace.forwardRef(
2514
+ var PropertyTour = React9__namespace.forwardRef(
2290
2515
  ({
2291
2516
  className,
2292
2517
  title,
@@ -2299,8 +2524,8 @@ var PropertyTour = React5__namespace.forwardRef(
2299
2524
  playsInline = true,
2300
2525
  ...props
2301
2526
  }, ref) => {
2302
- const videoRef = React5__namespace.useRef(null);
2303
- React5__namespace.useEffect(() => {
2527
+ const videoRef = React9__namespace.useRef(null);
2528
+ React9__namespace.useEffect(() => {
2304
2529
  const video = videoRef.current;
2305
2530
  if (!video) return;
2306
2531
  const handleFullscreenChange = () => {
@@ -2432,7 +2657,7 @@ var formatTimeAgo = (timestamp) => {
2432
2657
  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
2433
2658
  return `${Math.floor(diff / 3600)}h ago`;
2434
2659
  };
2435
- var PropertyNewsUpdates = React5__namespace.forwardRef(
2660
+ var PropertyNewsUpdates = React9__namespace.forwardRef(
2436
2661
  ({
2437
2662
  className,
2438
2663
  heading,
@@ -2449,15 +2674,15 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
2449
2674
  const isPurchaseVariant = variant === "purchases";
2450
2675
  const isHomeVariant = variant === "home";
2451
2676
  const resolvedHeading = heading ?? (isPurchaseVariant ? "Live Purchases" : "Property News & Headlines");
2452
- const [homeTab, setHomeTab] = React5__namespace.useState("all");
2677
+ const [homeTab, setHomeTab] = React9__namespace.useState("all");
2453
2678
  const purchaseItems = purchasesProp ?? [];
2454
- const [page, setPage] = React5__namespace.useState(0);
2455
- React5__namespace.useEffect(() => {
2679
+ const [page, setPage] = React9__namespace.useState(0);
2680
+ React9__namespace.useEffect(() => {
2456
2681
  ensureAnimationsInjected();
2457
2682
  }, []);
2458
2683
  const hasItems = Array.isArray(items) && items.length > 0;
2459
- const totalPages = React5__namespace.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
2460
- React5__namespace.useEffect(() => {
2684
+ const totalPages = React9__namespace.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
2685
+ React9__namespace.useEffect(() => {
2461
2686
  setPage((prev) => Math.min(prev, totalPages - 1));
2462
2687
  }, [totalPages]);
2463
2688
  const paginatedItems = hasItems ? items.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
@@ -2765,7 +2990,7 @@ var defaultFormat = (value) => new Intl.NumberFormat("en-US", {
2765
2990
  notation: value >= 1e5 ? "compact" : "standard",
2766
2991
  maximumFractionDigits: value >= 1e3 ? 0 : 2
2767
2992
  }).format(value);
2768
- var TradingSlider = React5__namespace.forwardRef(
2993
+ var TradingSlider = React9__namespace.forwardRef(
2769
2994
  ({
2770
2995
  label = "Trade size",
2771
2996
  helperText = "Drag to pick the desired notional.",
@@ -2783,7 +3008,7 @@ var TradingSlider = React5__namespace.forwardRef(
2783
3008
  ...rest
2784
3009
  }, ref) => {
2785
3010
  const isControlled = value !== void 0;
2786
- const [internalValue, setInternalValue] = React5__namespace.useState(
3011
+ const [internalValue, setInternalValue] = React9__namespace.useState(
2787
3012
  defaultValue ?? (typeof min === "number" ? min : 0)
2788
3013
  );
2789
3014
  const currentValue = isControlled ? Number(value) : internalValue;
@@ -2886,7 +3111,7 @@ var MobileToggleButton = styled24__default.default.button`
2886
3111
  padding: 0.6rem 0.5rem;
2887
3112
  }
2888
3113
  `;
2889
- var MobileTradeNav = React5__namespace.forwardRef(
3114
+ var MobileTradeNav = React9__namespace.forwardRef(
2890
3115
  ({ className, items, activeId, onChange, ...props }, ref) => {
2891
3116
  return /* @__PURE__ */ jsxRuntime.jsx(MobileToggleContainer, { ref, className: cn(className), ...props, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
2892
3117
  MobileToggleButton,
@@ -3537,7 +3762,7 @@ var formatPercent = (value, fractionDigits = 2) => {
3537
3762
  if (value == null || Number.isNaN(value)) return "\u2014";
3538
3763
  return `${value.toFixed(fractionDigits)}%`;
3539
3764
  };
3540
- var YourOrders = React5__namespace.forwardRef(
3765
+ var YourOrders = React9__namespace.forwardRef(
3541
3766
  ({
3542
3767
  className,
3543
3768
  title,
@@ -3550,10 +3775,10 @@ var YourOrders = React5__namespace.forwardRef(
3550
3775
  pageSize: pageSizeOverride,
3551
3776
  ...props
3552
3777
  }, ref) => {
3553
- const [internalActiveTab, setInternalActiveTab] = React5__namespace.useState(tabs?.[0]?.id ?? "portfolio");
3554
- const [page, setPage] = React5__namespace.useState(0);
3778
+ const [internalActiveTab, setInternalActiveTab] = React9__namespace.useState(tabs?.[0]?.id ?? "portfolio");
3779
+ const [page, setPage] = React9__namespace.useState(0);
3555
3780
  const effectiveActiveTabId = activeTabId ?? internalActiveTab;
3556
- React5__namespace.useEffect(() => {
3781
+ React9__namespace.useEffect(() => {
3557
3782
  setPage(0);
3558
3783
  }, [effectiveActiveTabId]);
3559
3784
  const handleTabChange = (tabId) => {
@@ -3935,7 +4160,7 @@ function createCandlestickSeries(chart, options) {
3935
4160
  }
3936
4161
  throw new Error("Candlestick series API is not available in the current lightweight-charts version.");
3937
4162
  }
3938
- var PriceChart = React5__namespace.forwardRef(
4163
+ var PriceChart = React9__namespace.forwardRef(
3939
4164
  ({
3940
4165
  className,
3941
4166
  title = "Price Chart",
@@ -3949,18 +4174,18 @@ var PriceChart = React5__namespace.forwardRef(
3949
4174
  height = 301.52,
3950
4175
  ...props
3951
4176
  }, ref) => {
3952
- const containerRef = React5__namespace.useRef(null);
3953
- const chartRef = React5__namespace.useRef(null);
3954
- const seriesRef = React5__namespace.useRef(null);
3955
- const priceLineRef = React5__namespace.useRef(null);
3956
- const [hoveredRange, setHoveredRange] = React5__namespace.useState(null);
3957
- const [dropdownOpen, setDropdownOpen] = React5__namespace.useState(false);
3958
- const dropdownRef = React5__namespace.useRef(null);
3959
- const isAutoScrollRef = React5__namespace.useRef(true);
4177
+ const containerRef = React9__namespace.useRef(null);
4178
+ const chartRef = React9__namespace.useRef(null);
4179
+ const seriesRef = React9__namespace.useRef(null);
4180
+ const priceLineRef = React9__namespace.useRef(null);
4181
+ const [hoveredRange, setHoveredRange] = React9__namespace.useState(null);
4182
+ const [dropdownOpen, setDropdownOpen] = React9__namespace.useState(false);
4183
+ const dropdownRef = React9__namespace.useRef(null);
4184
+ const isAutoScrollRef = React9__namespace.useRef(true);
3960
4185
  const visibleRanges = ranges.slice(0, VISIBLE_RANGE_COUNT);
3961
4186
  const dropdownRanges = ranges.slice(VISIBLE_RANGE_COUNT);
3962
4187
  const selectedInDropdown = dropdownRanges.includes(selectedRange);
3963
- React5__namespace.useEffect(() => {
4188
+ React9__namespace.useEffect(() => {
3964
4189
  const handleClickOutside = (e) => {
3965
4190
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
3966
4191
  setDropdownOpen(false);
@@ -3969,25 +4194,25 @@ var PriceChart = React5__namespace.forwardRef(
3969
4194
  document.addEventListener("mousedown", handleClickOutside);
3970
4195
  return () => document.removeEventListener("mousedown", handleClickOutside);
3971
4196
  }, []);
3972
- const resolvedPrice = React5__namespace.useMemo(() => {
4197
+ const resolvedPrice = React9__namespace.useMemo(() => {
3973
4198
  if (price != null) return price;
3974
4199
  const last = data.at(-1);
3975
4200
  return last?.close;
3976
4201
  }, [data, price]);
3977
- const inferredChangePercent = React5__namespace.useMemo(() => {
4202
+ const inferredChangePercent = React9__namespace.useMemo(() => {
3978
4203
  if (changePercent != null) return changePercent;
3979
4204
  const first = data[0]?.open;
3980
4205
  const last = data.at(-1)?.close;
3981
4206
  if (first == null || last == null || first === 0) return void 0;
3982
4207
  return (last - first) / first * 100;
3983
4208
  }, [changePercent, data]);
3984
- const dollarChange = React5__namespace.useMemo(() => {
4209
+ const dollarChange = React9__namespace.useMemo(() => {
3985
4210
  const first = data[0]?.open;
3986
4211
  const last = data.at(-1)?.close;
3987
4212
  if (first == null || last == null) return void 0;
3988
4213
  return last - first;
3989
4214
  }, [data]);
3990
- React5__namespace.useEffect(() => {
4215
+ React9__namespace.useEffect(() => {
3991
4216
  const el = containerRef.current;
3992
4217
  if (!el) return;
3993
4218
  const chart = LightweightCharts__namespace.createChart(el, {
@@ -4032,7 +4257,7 @@ var PriceChart = React5__namespace.forwardRef(
4032
4257
  chart.remove();
4033
4258
  };
4034
4259
  }, []);
4035
- React5__namespace.useEffect(() => {
4260
+ React9__namespace.useEffect(() => {
4036
4261
  const chart = chartRef.current;
4037
4262
  if (!chart) return;
4038
4263
  const effectiveRange = selectedRange ?? ranges?.[0] ?? "1D";
@@ -4040,7 +4265,7 @@ var PriceChart = React5__namespace.forwardRef(
4040
4265
  timeScale: getTimeScaleOptions(effectiveRange)
4041
4266
  });
4042
4267
  }, [selectedRange, ranges]);
4043
- React5__namespace.useEffect(() => {
4268
+ React9__namespace.useEffect(() => {
4044
4269
  const chart = chartRef.current;
4045
4270
  const series = seriesRef.current;
4046
4271
  if (!chart || !series) return;
@@ -4245,7 +4470,7 @@ var formatPrice3 = (value, currencySymbol) => {
4245
4470
  maximumFractionDigits: 3
4246
4471
  })}`;
4247
4472
  };
4248
- var PropertyHeroHeader = React5__namespace.forwardRef(
4473
+ var PropertyHeroHeader = React9__namespace.forwardRef(
4249
4474
  ({
4250
4475
  className,
4251
4476
  imageUrl,
@@ -4266,14 +4491,15 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4266
4491
  makeOfferDisabled = false,
4267
4492
  hideMakeOfferButton = false,
4268
4493
  statusBadge,
4494
+ isLoading = false,
4269
4495
  ...props
4270
4496
  }, ref) => {
4271
4497
  const isPositive = changePercent == null ? void 0 : changePercent >= 0;
4272
4498
  const accentColor = "#e6c87e";
4273
4499
  const tradeHoverColor = "#f5dd9a";
4274
- const [isTradeInteracting, setIsTradeInteracting] = React5__namespace.useState(false);
4275
- const [isOfferInteracting, setIsOfferInteracting] = React5__namespace.useState(false);
4276
- const hasAmenities = beds != null || baths != null || cars != null || propertyTypeLabel != null;
4500
+ const [isTradeInteracting, setIsTradeInteracting] = React9__namespace.useState(false);
4501
+ const [isOfferInteracting, setIsOfferInteracting] = React9__namespace.useState(false);
4502
+ const hasAmenities = isLoading || beds != null || baths != null || cars != null || propertyTypeLabel != null;
4277
4503
  const isTradeDisabled = !onTrade;
4278
4504
  const isMakeOfferButtonDisabled = makeOfferDisabled || !onMakeOffer;
4279
4505
  const showMakeOfferButton = !hideMakeOfferButton;
@@ -4313,7 +4539,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4313
4539
  /* @__PURE__ */ jsxRuntime.jsx("h1", { style: headingStyle, className: "break-words", children: name }),
4314
4540
  /* @__PURE__ */ jsxRuntime.jsxs(InfoRow, { className: "mb-3 max-[768px]:mb-[0.6rem] max-[480px]:mb-[0.5rem]", children: [
4315
4541
  /* @__PURE__ */ jsxRuntime.jsx(LocationText, { children: location }),
4316
- price == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(PriceBlock, { children: [
4542
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(PriceBlock, { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 18 }) }) : price == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(PriceBlock, { children: [
4317
4543
  formatPrice3(price, currencySymbol),
4318
4544
  changePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(
4319
4545
  "span",
@@ -4343,7 +4569,21 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4343
4569
  ] })
4344
4570
  ] })
4345
4571
  ] }),
4346
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: [
4572
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4573
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4574
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4575
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 52, height: 14 })
4576
+ ] }),
4577
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4578
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bath, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4579
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 56, height: 14 })
4580
+ ] }),
4581
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4582
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CarFront, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
4583
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 50, height: 14 })
4584
+ ] }),
4585
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 60, height: 14 })
4586
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4347
4587
  beds == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
4348
4588
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "mr-2 h-[18px] w-[18px]" }),
4349
4589
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
@@ -4366,7 +4606,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4366
4606
  ] })
4367
4607
  ] }),
4368
4608
  propertyTypeLabel == null ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { children: propertyTypeLabel })
4369
- ] })
4609
+ ] }) })
4370
4610
  ] }),
4371
4611
  /* @__PURE__ */ jsxRuntime.jsxs(ActionButtons, { children: [
4372
4612
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4428,7 +4668,21 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4428
4668
  ] })
4429
4669
  ] }) })
4430
4670
  ] }),
4431
- hasAmenities ? /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenities, { children: [
4671
+ hasAmenities ? /* @__PURE__ */ jsxRuntime.jsx(MobileAmenities, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4672
+ /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4673
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "h-4 w-4 opacity-60" }),
4674
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 40, height: 12 })
4675
+ ] }),
4676
+ /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4677
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bath, { className: "h-4 w-4 opacity-60" }),
4678
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 44, height: 12 })
4679
+ ] }),
4680
+ /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4681
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CarFront, { className: "h-4 w-4 opacity-60" }),
4682
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 42, height: 12 })
4683
+ ] }),
4684
+ /* @__PURE__ */ jsxRuntime.jsx(MobileAmenity, { children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 52, height: 12 }) })
4685
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4432
4686
  beds == null ? null : /* @__PURE__ */ jsxRuntime.jsxs(MobileAmenity, { children: [
4433
4687
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BedDouble, { className: "h-4 w-4" }),
4434
4688
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
@@ -4451,7 +4705,7 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4451
4705
  ] })
4452
4706
  ] }),
4453
4707
  propertyTypeLabel == null ? null : /* @__PURE__ */ jsxRuntime.jsx(MobileAmenity, { children: propertyTypeLabel })
4454
- ] }) : null
4708
+ ] }) }) : null
4455
4709
  ] });
4456
4710
  }
4457
4711
  );
@@ -4688,12 +4942,21 @@ var Header = ({
4688
4942
  onWalletNavigate: _onWalletNavigate,
4689
4943
  showTradeTab = true
4690
4944
  }) => {
4691
- const [isUserMenuOpen, setIsUserMenuOpen] = React5.useState(false);
4692
- const [isMobileMenuOpen, setIsMobileMenuOpen] = React5.useState(false);
4693
- const [isMoreMenuOpen, setIsMoreMenuOpen] = React5.useState(false);
4694
- const [showLoginPopup, setShowLoginPopup] = React5.useState(false);
4695
- const [loginPopupInitialView, setLoginPopupInitialView] = React5.useState(void 0);
4696
- React5.useEffect(() => {
4945
+ const [isUserMenuOpen, setIsUserMenuOpen] = React9.useState(false);
4946
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = React9.useState(false);
4947
+ const [isMoreMenuOpen, setIsMoreMenuOpen] = React9.useState(false);
4948
+ const [showLoginPopup, setShowLoginPopup] = React9.useState(false);
4949
+ const [loginPopupInitialView, setLoginPopupInitialView] = React9.useState(void 0);
4950
+ React9.useEffect(() => {
4951
+ if (typeof window === "undefined") return;
4952
+ const ua = navigator.userAgent;
4953
+ const isTelegram = /Telegram/i.test(ua);
4954
+ const isIOS = /iPhone|iPad|iPod/.test(ua);
4955
+ if (isTelegram && isIOS) {
4956
+ document.documentElement.style.setProperty("--telegram-safe-top", "59px");
4957
+ }
4958
+ }, []);
4959
+ React9.useEffect(() => {
4697
4960
  const handleClickOutside = (event) => {
4698
4961
  const target = event.target;
4699
4962
  if (!target) return;
@@ -4713,7 +4976,7 @@ var Header = ({
4713
4976
  document.removeEventListener("mousedown", handleClickOutside);
4714
4977
  };
4715
4978
  }, [isUserMenuOpen, isMobileMenuOpen, isMoreMenuOpen]);
4716
- React5.useEffect(() => {
4979
+ React9.useEffect(() => {
4717
4980
  if (typeof window === "undefined") return;
4718
4981
  const handleExternalLoginPopup = (event) => {
4719
4982
  const customEvent = event;
@@ -4843,7 +5106,7 @@ var Header = ({
4843
5106
  setShowLoginPopup(true);
4844
5107
  }
4845
5108
  };
4846
- const handleLoginPopupClose = React5__namespace.default.useCallback(() => {
5109
+ const handleLoginPopupClose = React9__namespace.default.useCallback(() => {
4847
5110
  setShowLoginPopup(false);
4848
5111
  setLoginPopupInitialView(void 0);
4849
5112
  }, []);
@@ -5131,8 +5394,8 @@ var SafeAreaCover = styled24__default.default.div`
5131
5394
  top: 0;
5132
5395
  left: 0;
5133
5396
  right: 0;
5134
- height: env(safe-area-inset-top, 0px);
5135
- min-height: env(safe-area-inset-top, 0px);
5397
+ height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5398
+ min-height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5136
5399
  background-color: #0d1117;
5137
5400
  z-index: 1001;
5138
5401
  pointer-events: none;
@@ -5186,7 +5449,7 @@ var HeaderContainer = styled24__default.default.header`
5186
5449
  /* Split padding so browsers that don't support env() inside shorthand
5187
5450
  still get the horizontal padding — only the top falls back to 0 */
5188
5451
  padding: 0 2rem;
5189
- padding-top: env(safe-area-inset-top, 0px);
5452
+ padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5190
5453
  background-color: #0d1117;
5191
5454
  border-bottom: 1px solid #232a32;
5192
5455
  position: fixed;
@@ -5197,18 +5460,18 @@ var HeaderContainer = styled24__default.default.header`
5197
5460
  width: 100%;
5198
5461
  /* Fallback min-height for browsers that can't evaluate calc+env */
5199
5462
  min-height: 56px;
5200
- min-height: calc(56px + env(safe-area-inset-top, 0px));
5463
+ min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5201
5464
  box-sizing: border-box;
5202
5465
 
5203
5466
  @media (max-width: 768px) {
5204
5467
  padding: 0 1rem;
5205
- padding-top: env(safe-area-inset-top, 0px);
5468
+ padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
5206
5469
  }
5207
5470
  `;
5208
5471
  var HeaderSpacer = styled24__default.default.div`
5209
5472
  width: 100%;
5210
5473
  min-height: 56px;
5211
- min-height: calc(56px + env(safe-area-inset-top, 0px));
5474
+ min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5212
5475
  flex-shrink: 0;
5213
5476
  `;
5214
5477
  var Logo = styled24__default.default.div`
@@ -5263,12 +5526,12 @@ var Nav = styled24__default.default.nav`
5263
5526
  @media (max-width: 1300px) {
5264
5527
  position: fixed;
5265
5528
  top: 56px;
5266
- top: calc(56px + env(safe-area-inset-top, 0px));
5529
+ top: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5267
5530
  right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
5268
5531
  width: 280px;
5269
5532
  max-width: 280px;
5270
5533
  height: calc(100vh - 56px);
5271
- height: calc(100vh - 56px - env(safe-area-inset-top, 0px));
5534
+ height: calc(100vh - 56px - max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
5272
5535
  background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
5273
5536
  z-index: 1000;
5274
5537
  transition: right 0.3s ease;
@@ -5541,10 +5804,10 @@ var MobileNavItem = styled24__default.default.div`
5541
5804
  padding-left: 24px;
5542
5805
  }
5543
5806
  `;
5544
- var PropertySubheader = React5__namespace.forwardRef(
5807
+ var PropertySubheader = React9__namespace.forwardRef(
5545
5808
  ({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
5546
- const tabsContainerRef = React5__namespace.useRef(null);
5547
- React5__namespace.useEffect(() => {
5809
+ const tabsContainerRef = React9__namespace.useRef(null);
5810
+ React9__namespace.useEffect(() => {
5548
5811
  const container = tabsContainerRef.current;
5549
5812
  if (!container) return;
5550
5813
  const isMobile = window.innerWidth <= 768;
@@ -5686,27 +5949,27 @@ var LoginPopup = ({
5686
5949
  onFundWallet,
5687
5950
  initialView
5688
5951
  }) => {
5689
- const [view, setView] = React5.useState(() => initialView ?? "main");
5690
- const [email, setEmail] = React5.useState("");
5691
- const [handle, setHandle] = React5.useState("");
5692
- const [otp, setOtp] = React5.useState(Array(OTP_INPUT_LENGTH).fill(""));
5693
- const [error, setError] = React5.useState("");
5694
- const [loading, setLoading] = React5.useState(false);
5695
- const [isSignUp, setIsSignUp] = React5.useState(false);
5696
- const [fundingAmount] = React5.useState("");
5697
- const [kycLoading, setKycLoading] = React5.useState(false);
5698
- const [showKycWidget, setShowKycWidget] = React5.useState(false);
5699
- const [cryptoFundingLoading, setCryptoFundingLoading] = React5.useState(false);
5700
- const [fiatFundingLoading, setFiatFundingLoading] = React5.useState(false);
5701
- const [fundingError, setFundingError] = React5.useState("");
5702
- const [transakWidgetUrl, setTransakWidgetUrl] = React5.useState(null);
5703
- const suppressAutoCloseRef = React5__namespace.default.useRef(false);
5704
- React5.useEffect(() => {
5952
+ const [view, setView] = React9.useState(() => initialView ?? "main");
5953
+ const [email, setEmail] = React9.useState("");
5954
+ const [handle, setHandle] = React9.useState("");
5955
+ const [otp, setOtp] = React9.useState(Array(OTP_INPUT_LENGTH).fill(""));
5956
+ const [error, setError] = React9.useState("");
5957
+ const [loading, setLoading] = React9.useState(false);
5958
+ const [isSignUp, setIsSignUp] = React9.useState(false);
5959
+ const [fundingAmount] = React9.useState("");
5960
+ const [kycLoading, setKycLoading] = React9.useState(false);
5961
+ const [showKycWidget, setShowKycWidget] = React9.useState(false);
5962
+ const [cryptoFundingLoading, setCryptoFundingLoading] = React9.useState(false);
5963
+ const [fiatFundingLoading, setFiatFundingLoading] = React9.useState(false);
5964
+ const [fundingError, setFundingError] = React9.useState("");
5965
+ const [transakWidgetUrl, setTransakWidgetUrl] = React9.useState(null);
5966
+ const suppressAutoCloseRef = React9__namespace.default.useRef(false);
5967
+ React9.useEffect(() => {
5705
5968
  if (typeof initialView === "string") {
5706
5969
  setView(initialView);
5707
5970
  }
5708
5971
  }, [initialView]);
5709
- React5.useEffect(() => {
5972
+ React9.useEffect(() => {
5710
5973
  if (!transakWidgetUrl) return;
5711
5974
  const handleTransakMessage = (event) => {
5712
5975
  if (!event.origin.includes("transak.com") && !event.origin.includes("global.transak.com")) {
@@ -5731,7 +5994,7 @@ var LoginPopup = ({
5731
5994
  window.addEventListener("message", handleTransakMessage);
5732
5995
  return () => window.removeEventListener("message", handleTransakMessage);
5733
5996
  }, [transakWidgetUrl, onClose]);
5734
- React5.useEffect(() => {
5997
+ React9.useEffect(() => {
5735
5998
  if (!autoCloseOnAuth) {
5736
5999
  return;
5737
6000
  }
@@ -6703,8 +6966,8 @@ var TransakIframe = styled24__default.default.iframe`
6703
6966
  border-radius: var(--border-radius, 12px);
6704
6967
  `;
6705
6968
  var MiniLiveFeed = () => {
6706
- const [purchases, setPurchases] = React5.useState([]);
6707
- React5.useEffect(() => {
6969
+ const [purchases, setPurchases] = React9.useState([]);
6970
+ React9.useEffect(() => {
6708
6971
  const handles = [
6709
6972
  "Landlord",
6710
6973
  "PropertyKing",
@@ -6880,7 +7143,7 @@ var MiniLiveFeed = () => {
6880
7143
  );
6881
7144
  };
6882
7145
  LoginPopup.displayName = "LoginPopup";
6883
- var PropertyCompareBar = React5__namespace.forwardRef(
7146
+ var PropertyCompareBar = React9__namespace.forwardRef(
6884
7147
  ({
6885
7148
  className,
6886
7149
  addresses,
@@ -6891,7 +7154,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
6891
7154
  price,
6892
7155
  ...props
6893
7156
  }, ref) => {
6894
- const normalizedAddresses = React5__namespace.useMemo(() => {
7157
+ const normalizedAddresses = React9__namespace.useMemo(() => {
6895
7158
  return addresses.map(
6896
7159
  (option) => typeof option === "string" ? { id: option, label: option } : option
6897
7160
  );
@@ -6899,11 +7162,11 @@ var PropertyCompareBar = React5__namespace.forwardRef(
6899
7162
  const hasAddresses = normalizedAddresses.length > 0;
6900
7163
  const firstAddressId = normalizedAddresses[0]?.id;
6901
7164
  const isControlled = selectedAddressId !== void 0;
6902
- const [internalSelectedId, setInternalSelectedId] = React5__namespace.useState(
7165
+ const [internalSelectedId, setInternalSelectedId] = React9__namespace.useState(
6903
7166
  () => isControlled ? void 0 : firstAddressId
6904
7167
  );
6905
7168
  const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
6906
- React5__namespace.useEffect(() => {
7169
+ React9__namespace.useEffect(() => {
6907
7170
  if (!isControlled) {
6908
7171
  setInternalSelectedId((current) => {
6909
7172
  if (current != null && normalizedAddresses.some((option) => option.id === current)) {
@@ -6914,9 +7177,9 @@ var PropertyCompareBar = React5__namespace.forwardRef(
6914
7177
  }
6915
7178
  }, [firstAddressId, isControlled, normalizedAddresses]);
6916
7179
  const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
6917
- const [isDropdownOpen, setIsDropdownOpen] = React5__namespace.useState(false);
6918
- const dropdownRef = React5__namespace.useRef(null);
6919
- React5__namespace.useEffect(() => {
7180
+ const [isDropdownOpen, setIsDropdownOpen] = React9__namespace.useState(false);
7181
+ const dropdownRef = React9__namespace.useRef(null);
7182
+ React9__namespace.useEffect(() => {
6920
7183
  if (!isDropdownOpen) return;
6921
7184
  const handleClick = (event) => {
6922
7185
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@@ -7319,11 +7582,11 @@ function GalleryMapSection({
7319
7582
  autoPlay = true,
7320
7583
  autoPlayInterval = 4e3
7321
7584
  }) {
7322
- const [carouselIndex, setCarouselIndex] = React5.useState(0);
7323
- const [showVideo, setShowVideo] = React5.useState(false);
7324
- const [autoPlaying, setAutoPlaying] = React5.useState(autoPlay);
7585
+ const [carouselIndex, setCarouselIndex] = React9.useState(0);
7586
+ const [showVideo, setShowVideo] = React9.useState(false);
7587
+ const [autoPlaying, setAutoPlaying] = React9.useState(autoPlay);
7325
7588
  const resolvedMapUrl = mapUrl ?? (tokenName ? `/map/${tokenName}?embed=true&zoom=14&hideOthers=true` : "about:blank");
7326
- React5.useEffect(() => {
7589
+ React9.useEffect(() => {
7327
7590
  if (!autoPlaying || images.length <= 1) return;
7328
7591
  const interval = setInterval(() => {
7329
7592
  setCarouselIndex((p) => (p + 1) % images.length);
@@ -7639,9 +7902,10 @@ function PropertyOverview({
7639
7902
  bathrooms,
7640
7903
  carSpaces,
7641
7904
  propertyTypeLabel,
7642
- tokensIssued: tokensIssuedProp
7905
+ tokensIssued: tokensIssuedProp,
7906
+ isLoading = false
7643
7907
  }) {
7644
- const [isDescExpanded, setDescExpanded] = React5.useState(false);
7908
+ const [isDescExpanded, setDescExpanded] = React9.useState(false);
7645
7909
  const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
7646
7910
  const landSize = landProp ?? overviewData?.landSizeSqm ?? null;
7647
7911
  const buildingSize = buildingProp ?? overviewData?.buildingSizeSqm ?? null;
@@ -7677,13 +7941,14 @@ function PropertyOverview({
7677
7941
  const weeklyRent = overviewData?.weeklyRent ?? 0;
7678
7942
  const annualRent = weeklyRent * 52;
7679
7943
  const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
7944
+ const loadingSkeleton = /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 90, height: 18 });
7680
7945
  const financialItems = financialItemsProp ?? [
7681
- { label: "Token Price", value: tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
7682
- { label: "Property Value", value: resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
7683
- { label: "Weekly Rent", value: weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
7684
- { label: "Dividend Yield", value: dividendYield ? `${dividendYield}%` : "N/A" },
7685
- { label: "Total Tokens", value: resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
7686
- { label: "Indicative Listing", value: overviewData?.indicativeListing ?? "N/A" }
7946
+ { label: "Token Price", value: isLoading && tokenPriceValue == null ? loadingSkeleton : tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
7947
+ { label: "Property Value", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
7948
+ { label: "Weekly Rent", value: isLoading && !overviewData ? loadingSkeleton : weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
7949
+ { label: "Dividend Yield", value: isLoading && dividendYield == null && resolvedValuation == null ? loadingSkeleton : dividendYield ? `${dividendYield}%` : "N/A" },
7950
+ { label: "Total Tokens", value: isLoading && resolvedTokensIssued == null ? loadingSkeleton : resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
7951
+ { label: "Indicative Listing", value: isLoading && !overviewData ? loadingSkeleton : overviewData?.indicativeListing ?? "N/A" }
7687
7952
  ];
7688
7953
  const galleryImages = images ?? [];
7689
7954
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -7987,8 +8252,8 @@ var OfferPricePulse = styled24__default.default.span`
7987
8252
  `;
7988
8253
  var eventTypes = ["Leased", "Renovated", "Extended", "Rebuilt", "Rezoned", "DA Approval"];
7989
8254
  function PropertyHistory() {
7990
- const [historyFilter, setHistoryFilter] = React5.useState("all");
7991
- const pastSales = React5.useMemo(() => generateMockPastSales(), []);
8255
+ const [historyFilter, setHistoryFilter] = React9.useState("all");
8256
+ const pastSales = React9.useMemo(() => generateMockPastSales(), []);
7992
8257
  const loafListing = pastSales.find((sale) => sale.type === "Listed");
7993
8258
  const loafEvents = pastSales.filter(
7994
8259
  (sale) => sale.ownershipPeriod === "current" && sale.type !== "Listed" && (sale.id === "leased-current" || sale.id === "da-approval")
@@ -8125,7 +8390,7 @@ function PropertyHistory() {
8125
8390
  ] });
8126
8391
  }
8127
8392
  function EventDetails({ event }) {
8128
- const [expanded, setExpanded] = React5.useState(false);
8393
+ const [expanded, setExpanded] = React9.useState(false);
8129
8394
  const toggleExpand = () => {
8130
8395
  setExpanded((prev) => !prev);
8131
8396
  };
@@ -8913,7 +9178,7 @@ function AssetSelectorBar({
8913
9178
  selectorItems,
8914
9179
  onSelect
8915
9180
  }) {
8916
- const [isDropdownOpen, setIsDropdownOpen] = React5.useState(false);
9181
+ const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
8917
9182
  const hasItems = selectorItems && selectorItems.length > 0;
8918
9183
  const metrics = metricsProp ?? [
8919
9184
  ...tokenPrice != null ? [{ label: "Unit Price", value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, accent: true }] : [],
@@ -9182,15 +9447,15 @@ function OfferingProgressCard({
9182
9447
  targetAmount,
9183
9448
  isPrivateClient = false
9184
9449
  }) {
9185
- const [currentTime, setCurrentTime] = React5.useState(/* @__PURE__ */ new Date());
9186
- const [countdown, setCountdown] = React5.useState(null);
9450
+ const [currentTime, setCurrentTime] = React9.useState(/* @__PURE__ */ new Date());
9451
+ const [countdown, setCountdown] = React9.useState(null);
9187
9452
  const computedRaised = raisedAmount ?? totalSold * tokenPrice;
9188
9453
  const computedTarget = targetAmount ?? supplyToSell * tokenPrice;
9189
- React5.useEffect(() => {
9454
+ React9.useEffect(() => {
9190
9455
  const timer = setInterval(() => setCurrentTime(/* @__PURE__ */ new Date()), 1e3);
9191
9456
  return () => clearInterval(timer);
9192
9457
  }, []);
9193
- React5.useEffect(() => {
9458
+ React9.useEffect(() => {
9194
9459
  if (!opensAt) {
9195
9460
  setCountdown(null);
9196
9461
  return;
@@ -9527,14 +9792,19 @@ var formatTimeAgo2 = (timestamp) => {
9527
9792
  };
9528
9793
  function VideoActivitySection({
9529
9794
  ipoStarted,
9795
+ ipoEnded = false,
9796
+ isLoading = false,
9530
9797
  recentOrders = [],
9531
9798
  ordersAllocated = 0,
9532
9799
  tokenPrice = 0
9533
9800
  }) {
9534
- const sortedOrders = React5.useMemo(
9801
+ const sortedOrders = React9.useMemo(
9535
9802
  () => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
9536
9803
  [recentOrders]
9537
9804
  );
9805
+ const headerStatusText = ipoEnded ? `Sale ended${ordersAllocated > 0 ? ` \xB7 ${ordersAllocated.toLocaleString()} orders` : ""}` : ipoStarted ? isLoading && sortedOrders.length === 0 ? "Loading orders\u2026" : `Active orders: ${ordersAllocated.toLocaleString()}` : "Waiting for Offer to Open";
9806
+ const showSkeletonFeed = ipoStarted && isLoading && sortedOrders.length === 0;
9807
+ const showOrderFeed = !showSkeletonFeed && (ipoStarted || ipoEnded && sortedOrders.length > 0);
9538
9808
  return /* @__PURE__ */ jsxRuntime.jsxs(Section3, { children: [
9539
9809
  /* @__PURE__ */ jsxRuntime.jsxs(VideoPanel, { children: [
9540
9810
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "section-header", children: /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Musgrave" }) }),
@@ -9546,31 +9816,40 @@ function VideoActivitySection({
9546
9816
  /* @__PURE__ */ jsxRuntime.jsxs(ActivityPanel, { children: [
9547
9817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "section-header", children: [
9548
9818
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { children: [
9549
- /* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted }),
9819
+ /* @__PURE__ */ jsxRuntime.jsx(LiveIndicatorDot, { $active: ipoStarted && !ipoEnded }),
9550
9820
  "Recent Order Activity"
9551
9821
  ] }),
9552
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: ipoStarted ? `Active orders: ${ordersAllocated.toLocaleString()}` : "Waiting for Offer to Open" })
9822
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: headerStatusText })
9553
9823
  ] }),
9554
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-content", children: ipoStarted ? /* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: sortedOrders.map((order, index) => {
9555
- const amount = tokenPrice * order.quantity;
9556
- const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
9557
- const isAlternate = index % 2 === 1;
9558
- return /* @__PURE__ */ jsxRuntime.jsxs(
9559
- PurchaseItem,
9560
- {
9561
- $barWidth: `${barPercent}%`,
9562
- $isAlternate: isAlternate,
9563
- children: [
9564
- /* @__PURE__ */ jsxRuntime.jsxs(PurchaseInfo, { children: [
9565
- /* @__PURE__ */ jsxRuntime.jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
9566
- /* @__PURE__ */ jsxRuntime.jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
9567
- ] }),
9568
- /* @__PURE__ */ jsxRuntime.jsx(PurchaseAmount, { children: formatCurrency4(amount) })
9569
- ]
9570
- },
9571
- order.txHash
9572
- );
9573
- }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "activity-empty", children: [
9824
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-content", children: showSkeletonFeed ? /* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(SkeletonFeedRow, { children: [
9825
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "info-col", children: [
9826
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 14 }),
9827
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 56, height: 10 })
9828
+ ] }),
9829
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 70, height: 14 })
9830
+ ] }, `feed-skel-${i}`)) }) : showOrderFeed ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9831
+ ipoEnded && /* @__PURE__ */ jsxRuntime.jsx(EndedBanner, { children: "Sale ended \u2014 final allocations" }),
9832
+ /* @__PURE__ */ jsxRuntime.jsx(FeedList, { children: sortedOrders.map((order, index) => {
9833
+ const amount = tokenPrice * order.quantity;
9834
+ const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
9835
+ const isAlternate = index % 2 === 1;
9836
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9837
+ PurchaseItem,
9838
+ {
9839
+ $barWidth: `${barPercent}%`,
9840
+ $isAlternate: isAlternate,
9841
+ children: [
9842
+ /* @__PURE__ */ jsxRuntime.jsxs(PurchaseInfo, { children: [
9843
+ /* @__PURE__ */ jsxRuntime.jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
9844
+ /* @__PURE__ */ jsxRuntime.jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
9845
+ ] }),
9846
+ /* @__PURE__ */ jsxRuntime.jsx(PurchaseAmount, { children: formatCurrency4(amount) })
9847
+ ]
9848
+ },
9849
+ order.txHash
9850
+ );
9851
+ }) })
9852
+ ] }) : ipoEnded ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "activity-empty", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Sale ended \u2014 no orders were placed." }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "activity-empty", children: [
9574
9853
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner" }),
9575
9854
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Activity will appear once the Offering opens" })
9576
9855
  ] }) })
@@ -9711,6 +9990,43 @@ var ActivityPanel = styled24__default.default.div`
9711
9990
  to { transform: rotate(360deg); }
9712
9991
  }
9713
9992
  `;
9993
+ var SkeletonFeedRow = styled24__default.default.div`
9994
+ padding: 0.625rem 0.75rem;
9995
+ border-bottom: 1px solid rgba(255,255,255,0.04);
9996
+ display: flex;
9997
+ justify-content: space-between;
9998
+ align-items: center;
9999
+ gap: 1rem;
10000
+
10001
+ &:last-child {
10002
+ border-bottom: none;
10003
+ }
10004
+
10005
+ .info-col {
10006
+ display: flex;
10007
+ flex-direction: column;
10008
+ gap: 0.3rem;
10009
+ min-width: 0;
10010
+ flex: 1;
10011
+ }
10012
+
10013
+ @media (max-width: 768px) {
10014
+ padding: 0.4rem 0.6rem;
10015
+ }
10016
+ `;
10017
+ var EndedBanner = styled24__default.default.div`
10018
+ font-size: 0.7rem;
10019
+ font-weight: 600;
10020
+ letter-spacing: 0.04em;
10021
+ text-transform: uppercase;
10022
+ color: rgba(255, 255, 255, 0.55);
10023
+ background: rgba(255, 255, 255, 0.04);
10024
+ border: 1px solid rgba(255, 255, 255, 0.08);
10025
+ border-radius: 6px;
10026
+ padding: 0.4rem 0.6rem;
10027
+ margin-bottom: 0.5rem;
10028
+ text-align: center;
10029
+ `;
9714
10030
  var FeedList = styled24__default.default.div`
9715
10031
  width: 100%;
9716
10032
  overflow-y: auto;
@@ -9828,10 +10144,10 @@ function OrderPanel({
9828
10144
  tokenDisplayName,
9829
10145
  tokenSymbol
9830
10146
  }) {
9831
- const [payInputValue, setPayInputValue] = React5.useState("");
9832
- const [receiveInputValue, setReceiveInputValue] = React5.useState("");
9833
- const [isPayInputFocused, setIsPayInputFocused] = React5.useState(false);
9834
- const [isReceiveInputFocused, setIsReceiveInputFocused] = React5.useState(false);
10147
+ const [payInputValue, setPayInputValue] = React9.useState("");
10148
+ const [receiveInputValue, setReceiveInputValue] = React9.useState("");
10149
+ const [isPayInputFocused, setIsPayInputFocused] = React9.useState(false);
10150
+ const [isReceiveInputFocused, setIsReceiveInputFocused] = React9.useState(false);
9835
10151
  const handlePayBlur = () => {
9836
10152
  setIsPayInputFocused(false);
9837
10153
  const parsed = parseInt(payInputValue.replace(/[^0-9]/g, ""), 10) || 0;
@@ -10677,9 +10993,9 @@ function PortfolioActivityPanel({
10677
10993
  style
10678
10994
  }) {
10679
10995
  const resolvedDefaultTab = defaultTab ?? (showPositionsTab ? "positions" : "subscriptions");
10680
- const [activeTab, setActiveTab] = React5.useState(resolvedDefaultTab);
10681
- const [activityPage, setActivityPage] = React5.useState(0);
10682
- const activeTabTotal = React5.useMemo(() => {
10996
+ const [activeTab, setActiveTab] = React9.useState(resolvedDefaultTab);
10997
+ const [activityPage, setActivityPage] = React9.useState(0);
10998
+ const activeTabTotal = React9.useMemo(() => {
10683
10999
  switch (activeTab) {
10684
11000
  case "positions":
10685
11001
  return positions.length;
@@ -10697,6 +11013,22 @@ function PortfolioActivityPanel({
10697
11013
  return 0;
10698
11014
  }
10699
11015
  }, [activeTab, positions.length, offeringOrders.length, openOrders.length, orderHistory.length, tradeHistory.length, transfers.length]);
11016
+ const positionsCount = positions.length;
11017
+ const openOrdersCount = React9.useMemo(
11018
+ () => openOrders.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
11019
+ [openOrders]
11020
+ );
11021
+ const pendingHistoryCount = React9.useMemo(
11022
+ () => orderHistory.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
11023
+ [orderHistory]
11024
+ );
11025
+ const pendingOfferingsCount = React9.useMemo(
11026
+ () => offeringOrders.filter((o) => {
11027
+ const s = o.status.toUpperCase();
11028
+ return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
11029
+ }).length,
11030
+ [offeringOrders]
11031
+ );
10700
11032
  const activityTotalPages = Math.ceil(activeTabTotal / pageSize);
10701
11033
  const pageSlice = (arr) => arr.slice(activityPage * pageSize, (activityPage + 1) * pageSize);
10702
11034
  const handleTabChange = (tab) => {
@@ -10706,10 +11038,38 @@ function PortfolioActivityPanel({
10706
11038
  return /* @__PURE__ */ jsxRuntime.jsxs(Container2, { className, style, children: [
10707
11039
  /* @__PURE__ */ jsxRuntime.jsx(PanelTitle, { children: "Activity" }),
10708
11040
  /* @__PURE__ */ jsxRuntime.jsxs(TabContainer, { children: [
10709
- showPositionsTab && /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: "Positions" }),
10710
- /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: "Initial Offerings" }),
10711
- /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: "Open Orders" }),
10712
- /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: "Order History" }),
11041
+ showPositionsTab && /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: [
11042
+ "Positions",
11043
+ positionsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11044
+ " (",
11045
+ positionsCount,
11046
+ ")"
11047
+ ] })
11048
+ ] }),
11049
+ /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: [
11050
+ "Initial Offerings",
11051
+ pendingOfferingsCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11052
+ " (",
11053
+ pendingOfferingsCount,
11054
+ ")"
11055
+ ] })
11056
+ ] }),
11057
+ /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: [
11058
+ "Open Orders",
11059
+ openOrdersCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11060
+ " (",
11061
+ openOrdersCount,
11062
+ ")"
11063
+ ] })
11064
+ ] }),
11065
+ /* @__PURE__ */ jsxRuntime.jsxs(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: [
11066
+ "Order History",
11067
+ pendingHistoryCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs(TabCount, { children: [
11068
+ " (",
11069
+ pendingHistoryCount,
11070
+ ")"
11071
+ ] })
11072
+ ] }),
10713
11073
  /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "trades", onClick: () => handleTabChange("trades"), children: "Trade History" }),
10714
11074
  /* @__PURE__ */ jsxRuntime.jsx(Tab, { $active: activeTab === "transfers", onClick: () => handleTabChange("transfers"), children: "Transfers" })
10715
11075
  ] }),
@@ -10794,8 +11154,10 @@ function PortfolioActivityPanel({
10794
11154
  openOrders.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "Open orders will appear here while they are working in the market." }),
10795
11155
  pageSlice(openOrders).map((order) => {
10796
11156
  const meta = getOrderStatusMeta(order.status);
10797
- const priceDisplay = order.price ? formatCurrency5(order.price) : "Market";
10798
- const amountDisplay = order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
11157
+ const isMarket = order.type === "MARKET";
11158
+ const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
11159
+ const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
11160
+ const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
10799
11161
  const isCancelling = cancellingOrderId === order.id;
10800
11162
  return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
10801
11163
  /* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
@@ -10805,9 +11167,10 @@ function PortfolioActivityPanel({
10805
11167
  formatNumber2(order.quantity),
10806
11168
  " tokens \xB7 ",
10807
11169
  prettyLabel(order.type),
11170
+ priceSegment,
10808
11171
  " \xB7 ",
10809
- priceDisplay,
10810
- " \xB7 ",
11172
+ filledPercent,
11173
+ "% filled \xB7 ",
10811
11174
  formatTimestamp(order.createdAt)
10812
11175
  ] })
10813
11176
  ] }),
@@ -10834,8 +11197,10 @@ function PortfolioActivityPanel({
10834
11197
  orderHistory.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: "No orders yet. Place a trade to see it appear here." }),
10835
11198
  pageSlice(orderHistory).map((order) => {
10836
11199
  const meta = getOrderStatusMeta(order.status);
10837
- const priceDisplay = order.price ? formatCurrency5(order.price) : "Market";
10838
- const amountDisplay = order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
11200
+ const isMarket = order.type === "MARKET";
11201
+ const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
11202
+ const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
11203
+ const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
10839
11204
  return /* @__PURE__ */ jsxRuntime.jsxs(ActivityRow, { children: [
10840
11205
  /* @__PURE__ */ jsxRuntime.jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
10841
11206
  /* @__PURE__ */ jsxRuntime.jsxs(ActivityInfo, { children: [
@@ -10844,9 +11209,10 @@ function PortfolioActivityPanel({
10844
11209
  formatNumber2(order.quantity),
10845
11210
  " tokens \xB7 ",
10846
11211
  prettyLabel(order.type),
11212
+ priceSegment,
10847
11213
  " \xB7 ",
10848
- priceDisplay,
10849
- " \xB7 ",
11214
+ filledPercent,
11215
+ "% filled \xB7 ",
10850
11216
  formatTimestamp(order.createdAt)
10851
11217
  ] })
10852
11218
  ] }),
@@ -10988,6 +11354,12 @@ var Tab = styled24__default.default.button`
10988
11354
  color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
10989
11355
  }
10990
11356
  `;
11357
+ var TabCount = styled24__default.default.span`
11358
+ color: inherit;
11359
+ opacity: 0.7;
11360
+ font-weight: 500;
11361
+ margin-left: 2px;
11362
+ `;
10991
11363
  var ActivityRow = styled24__default.default.div`
10992
11364
  display: grid;
10993
11365
  grid-template-columns: auto 1fr auto auto;
@@ -11631,23 +12003,24 @@ function PropertyBuy({
11631
12003
  recentOrders = [],
11632
12004
  ordersAllocated = 0,
11633
12005
  subscribers = 0,
12006
+ isLoadingActivity = false,
11634
12007
  selectorItems,
11635
12008
  onSelectorSelect,
11636
12009
  portfolioActivity
11637
12010
  }) {
11638
- const [sliderValue, setSliderValue] = React5.useState(0);
11639
- const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 0);
11640
- const [manualOrderAmount, setManualOrderAmount] = React5.useState(null);
11641
- const [ownedTokens, setOwnedTokens] = React5.useState(0);
11642
- const [displayedOwnedTokens, setDisplayedOwnedTokens] = React5.useState(0);
11643
- const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React5.useState(false);
11644
- const [lastOrderQuantity, setLastOrderQuantity] = React5.useState(0);
11645
- const [orderPendingAllocation, setOrderPendingAllocation] = React5.useState(false);
11646
- const [orderPlacedSuccess, setOrderPlacedSuccess] = React5.useState(false);
11647
- const [lastOrderDetails, setLastOrderDetails] = React5.useState(null);
11648
- const [showOrderConfirmModal, setShowOrderConfirmModal] = React5.useState(false);
11649
- const [, setLiveNewsIndex] = React5.useState(0);
11650
- const [newsItems, setNewsItems] = React5.useState(
12011
+ const [sliderValue, setSliderValue] = React9.useState(0);
12012
+ const [availableBalance, setAvailableBalance] = React9.useState(walletUsdcBalance ?? 0);
12013
+ const [manualOrderAmount, setManualOrderAmount] = React9.useState(null);
12014
+ const [ownedTokens, setOwnedTokens] = React9.useState(0);
12015
+ const [displayedOwnedTokens, setDisplayedOwnedTokens] = React9.useState(0);
12016
+ const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React9.useState(false);
12017
+ const [lastOrderQuantity, setLastOrderQuantity] = React9.useState(0);
12018
+ const [orderPendingAllocation, setOrderPendingAllocation] = React9.useState(false);
12019
+ const [orderPlacedSuccess, setOrderPlacedSuccess] = React9.useState(false);
12020
+ const [lastOrderDetails, setLastOrderDetails] = React9.useState(null);
12021
+ const [showOrderConfirmModal, setShowOrderConfirmModal] = React9.useState(false);
12022
+ const [, setLiveNewsIndex] = React9.useState(0);
12023
+ const [newsItems, setNewsItems] = React9.useState(
11651
12024
  () => allNewsItems.slice(0, 4).map((item, index) => ({
11652
12025
  ...item,
11653
12026
  displayId: `${item.id}-initial-${index}`,
@@ -11663,6 +12036,7 @@ function PropertyBuy({
11663
12036
  const offeringValuation = saleData?.offeringValuation ?? tokenPrice * supplyToSell;
11664
12037
  const ipoStatus = saleData?.status ?? "PENDING";
11665
12038
  const ipoStarted = ipoStatus === "LIVE" || isPrivateClient && ipoStatus === "PENDING";
12039
+ const ipoEnded = ipoStatus === "CLOSED" || ipoStatus === "CANCELLED";
11666
12040
  const statusLabel = ipoStatus;
11667
12041
  const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
11668
12042
  const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
@@ -11673,12 +12047,12 @@ function PropertyBuy({
11673
12047
  const orderTotal = tokenQuantity * tokenPrice + feeInUsd;
11674
12048
  const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
11675
12049
  const hasInsufficientFunds = orderTotal > availableBalance;
11676
- React5.useEffect(() => {
12050
+ React9.useEffect(() => {
11677
12051
  if (walletUsdcBalance != null) {
11678
12052
  setAvailableBalance(walletUsdcBalance);
11679
12053
  }
11680
12054
  }, [walletUsdcBalance]);
11681
- React5.useEffect(() => {
12055
+ React9.useEffect(() => {
11682
12056
  if (walletPropertyTokenBalance != null) {
11683
12057
  setOwnedTokens(walletPropertyTokenBalance);
11684
12058
  setDisplayedOwnedTokens(walletPropertyTokenBalance);
@@ -11690,13 +12064,13 @@ function PropertyBuy({
11690
12064
  }
11691
12065
  setShowOrderConfirmModal(true);
11692
12066
  };
11693
- React5.useEffect(() => {
12067
+ React9.useEffect(() => {
11694
12068
  if (purchaseStatus === "success" && orderPendingAllocation) {
11695
12069
  setOrderPendingAllocation(false);
11696
12070
  setOrderPlacedSuccess(true);
11697
12071
  }
11698
12072
  }, [purchaseStatus, orderPendingAllocation]);
11699
- const handlePlaceAnotherOrder = React5.useCallback(() => {
12073
+ const handlePlaceAnotherOrder = React9.useCallback(() => {
11700
12074
  setOrderPlacedSuccess(false);
11701
12075
  setOrderPendingAllocation(false);
11702
12076
  }, []);
@@ -11753,7 +12127,7 @@ function PropertyBuy({
11753
12127
  setSliderValue(0);
11754
12128
  setManualOrderAmount(null);
11755
12129
  };
11756
- React5.useEffect(() => {
12130
+ React9.useEffect(() => {
11757
12131
  const newsInterval = setInterval(() => {
11758
12132
  setLiveNewsIndex((prev) => {
11759
12133
  const nextIndex = (prev + 1) % allNewsItems.length;
@@ -11813,6 +12187,8 @@ function PropertyBuy({
11813
12187
  VideoActivitySection,
11814
12188
  {
11815
12189
  ipoStarted,
12190
+ ipoEnded,
12191
+ isLoading: isLoadingActivity,
11816
12192
  recentOrders,
11817
12193
  ordersAllocated,
11818
12194
  tokenPrice
@@ -12047,7 +12423,7 @@ function PaymentPopup({
12047
12423
  userTokenHoldings,
12048
12424
  propertyName
12049
12425
  }) {
12050
- const [selectedPaymentMethod, setSelectedPaymentMethod] = React5.useState(
12426
+ const [selectedPaymentMethod, setSelectedPaymentMethod] = React9.useState(
12051
12427
  "tokens"
12052
12428
  );
12053
12429
  if (!isOpen) return null;
@@ -12226,20 +12602,20 @@ function PaymentPopup({
12226
12602
  var payment_popup_default = PaymentPopup;
12227
12603
  var SUMMER_MONTHS = /* @__PURE__ */ new Set([11, 0, 1]);
12228
12604
  var OwnerBooking = ({ propertyName, token }) => {
12229
- const today = React5.useMemo(() => {
12605
+ const today = React9.useMemo(() => {
12230
12606
  const base = /* @__PURE__ */ new Date();
12231
12607
  base.setHours(0, 0, 0, 0);
12232
12608
  return base;
12233
12609
  }, []);
12234
- const [currentYear, setCurrentYear] = React5.useState(today.getFullYear());
12235
- const [currentMonth, setCurrentMonth] = React5.useState(today.getMonth());
12236
- const [dateRanges, setDateRanges] = React5.useState([]);
12237
- const [selectedDates, setSelectedDates] = React5.useState([]);
12238
- const [hoverDate, setHoverDate] = React5.useState(null);
12239
- const [isDateSelectorOpen, setIsDateSelectorOpen] = React5.useState(false);
12240
- const [selectorYear, setSelectorYear] = React5.useState(today.getFullYear());
12241
- const [isPaymentPopupOpen, setIsPaymentPopupOpen] = React5.useState(false);
12242
- const dateSelectorRef = React5.useRef(null);
12610
+ const [currentYear, setCurrentYear] = React9.useState(today.getFullYear());
12611
+ const [currentMonth, setCurrentMonth] = React9.useState(today.getMonth());
12612
+ const [dateRanges, setDateRanges] = React9.useState([]);
12613
+ const [selectedDates, setSelectedDates] = React9.useState([]);
12614
+ const [hoverDate, setHoverDate] = React9.useState(null);
12615
+ const [isDateSelectorOpen, setIsDateSelectorOpen] = React9.useState(false);
12616
+ const [selectorYear, setSelectorYear] = React9.useState(today.getFullYear());
12617
+ const [isPaymentPopupOpen, setIsPaymentPopupOpen] = React9.useState(false);
12618
+ const dateSelectorRef = React9.useRef(null);
12243
12619
  const tokenPrice = token.price ?? 700;
12244
12620
  const userTokenHoldings = 2.2;
12245
12621
  const MIN_NIGHTS = 3;
@@ -12249,25 +12625,25 @@ var OwnerBooking = ({ propertyName, token }) => {
12249
12625
  { bg: "rgba(230, 126, 34, 0.25)", border: "rgba(230, 126, 34, 0.6)" },
12250
12626
  { bg: "rgba(46, 204, 113, 0.25)", border: "rgba(46, 204, 113, 0.6)" }
12251
12627
  ];
12252
- const calculateTokensPerDayOwner = React5.useCallback(() => {
12628
+ const calculateTokensPerDayOwner = React9.useCallback(() => {
12253
12629
  if (tokenPrice <= 0) return 0;
12254
12630
  const target = 650;
12255
12631
  const raw = target / tokenPrice;
12256
12632
  return Math.ceil(raw * 1e4) / 1e4;
12257
12633
  }, [tokenPrice]);
12258
- const calculateTokensPerDayMarket = React5.useCallback(() => {
12634
+ const calculateTokensPerDayMarket = React9.useCallback(() => {
12259
12635
  if (tokenPrice <= 0) return 0;
12260
12636
  const target = 900;
12261
12637
  const raw = target / tokenPrice;
12262
12638
  return Math.ceil(raw * 1e4) / 1e4;
12263
12639
  }, [tokenPrice]);
12264
12640
  const qualifiesForOwnerRate = userTokenHoldings >= 0.1;
12265
- const getTokensPerDay = React5.useCallback(
12641
+ const getTokensPerDay = React9.useCallback(
12266
12642
  () => calculateTokensPerDayOwner() ,
12267
12643
  [qualifiesForOwnerRate, calculateTokensPerDayOwner, calculateTokensPerDayMarket]
12268
12644
  );
12269
12645
  const getRateLabel = () => "Owner's Rate" ;
12270
- const selectionStats = React5.useMemo(() => {
12646
+ const selectionStats = React9.useMemo(() => {
12271
12647
  if (selectedDates.length !== 2) return null;
12272
12648
  const [a, b] = selectedDates;
12273
12649
  const start = a < b ? a : b;
@@ -12278,10 +12654,10 @@ var OwnerBooking = ({ propertyName, token }) => {
12278
12654
  const usd = tokens * tokenPrice;
12279
12655
  return { nights, tokensPerDay, tokens, usd, start, end };
12280
12656
  }, [selectedDates, getTokensPerDay, tokenPrice]);
12281
- const totalNights = React5.useMemo(() => dateRanges.reduce((sum, r) => sum + r.nights, 0), [dateRanges]);
12282
- const totalTokens = React5.useMemo(() => dateRanges.reduce((sum, r) => sum + r.tokens, 0), [dateRanges]);
12657
+ const totalNights = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.nights, 0), [dateRanges]);
12658
+ const totalTokens = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.tokens, 0), [dateRanges]);
12283
12659
  const totalUSD = totalTokens * tokenPrice;
12284
- const generateCalendarDays = React5.useCallback(
12660
+ const generateCalendarDays = React9.useCallback(
12285
12661
  (year, month) => {
12286
12662
  const first = new Date(year, month, 1);
12287
12663
  const last = new Date(year, month + 1, 0);
@@ -12310,11 +12686,11 @@ var OwnerBooking = ({ propertyName, token }) => {
12310
12686
  },
12311
12687
  [today]
12312
12688
  );
12313
- const calendarDays = React5.useMemo(
12689
+ const calendarDays = React9.useMemo(
12314
12690
  () => generateCalendarDays(currentYear, currentMonth),
12315
12691
  [currentYear, currentMonth, generateCalendarDays]
12316
12692
  );
12317
- const isDateReserved = React5.useCallback(
12693
+ const isDateReserved = React9.useCallback(
12318
12694
  (date) => dateRanges.some((r) => date >= r.arrival && date <= r.departure),
12319
12695
  [dateRanges]
12320
12696
  );
@@ -12408,14 +12784,14 @@ var OwnerBooking = ({ propertyName, token }) => {
12408
12784
  "December"
12409
12785
  ];
12410
12786
  const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
12411
- const setMonthYear = React5.useCallback(
12787
+ const setMonthYear = React9.useCallback(
12412
12788
  (month, year) => {
12413
12789
  setCurrentMonth(month);
12414
12790
  setCurrentYear(year);
12415
12791
  },
12416
12792
  [setCurrentMonth, setCurrentYear]
12417
12793
  );
12418
- const shiftMonth = React5.useCallback(
12794
+ const shiftMonth = React9.useCallback(
12419
12795
  (direction) => {
12420
12796
  const delta = direction === "prev" ? -1 : 1;
12421
12797
  let newMonth = currentMonth + delta;
@@ -12432,7 +12808,7 @@ var OwnerBooking = ({ propertyName, token }) => {
12432
12808
  },
12433
12809
  [currentMonth, currentYear, setMonthYear]
12434
12810
  );
12435
- const jumpToNextAvailable = React5.useCallback(() => {
12811
+ const jumpToNextAvailable = React9.useCallback(() => {
12436
12812
  for (let offset = 1; offset <= 12; offset++) {
12437
12813
  const candidateMonth = (currentMonth + offset) % 12;
12438
12814
  if (!SUMMER_MONTHS.has(candidateMonth)) continue;
@@ -12449,7 +12825,7 @@ var OwnerBooking = ({ propertyName, token }) => {
12449
12825
  setMonthYear(month, selectorYear);
12450
12826
  setIsDateSelectorOpen(false);
12451
12827
  };
12452
- React5.useEffect(() => {
12828
+ React9.useEffect(() => {
12453
12829
  const handleClickOutside = (event) => {
12454
12830
  if (dateSelectorRef.current && !dateSelectorRef.current.contains(event.target)) {
12455
12831
  setIsDateSelectorOpen(false);
@@ -12893,21 +13269,21 @@ function PropertyValuation({
12893
13269
  loading = false,
12894
13270
  error = null
12895
13271
  }) {
12896
- const now = React5.useMemo(() => /* @__PURE__ */ new Date(), []);
12897
- const lastPrice = React5.useMemo(() => {
13272
+ const now = React9.useMemo(() => /* @__PURE__ */ new Date(), []);
13273
+ const lastPrice = React9.useMemo(() => {
12898
13274
  const fallback = Number.isFinite(tokenPrice) && tokenPrice > 0 ? tokenPrice : 0;
12899
13275
  if (!summary?.lastPrice || summary.lastPrice <= 0) {
12900
13276
  return fallback;
12901
13277
  }
12902
13278
  return summary.lastPrice;
12903
13279
  }, [summary, tokenPrice]);
12904
- const fairValue = React5.useMemo(() => {
13280
+ const fairValue = React9.useMemo(() => {
12905
13281
  if (summary?.fairValue && summary.fairValue > 0) {
12906
13282
  return summary.fairValue;
12907
13283
  }
12908
13284
  return lastPrice || 1;
12909
13285
  }, [summary, lastPrice]);
12910
- const tokensOutstanding = React5.useMemo(() => {
13286
+ const tokensOutstanding = React9.useMemo(() => {
12911
13287
  if (summary?.totalTokens && summary.totalTokens > 0) {
12912
13288
  return summary.totalTokens;
12913
13289
  }
@@ -12922,8 +13298,8 @@ function PropertyValuation({
12922
13298
  const valuationStatus = summary?.valuationStatus ?? (lastPrice < fairValue ? "Undervalued" : lastPrice > fairValue ? "Overvalued" : "Fair Value");
12923
13299
  const valuationDelta = summary?.valuationDeltaPercent ?? (lastPrice - fairValue) / fairValue * 100;
12924
13300
  const valuationDeltaFormatted = `${valuationDelta >= 0 ? "+" : ""}${valuationDelta.toFixed(1)}%`;
12925
- const { valuationPath, fairValuePath, axisLabels } = React5.useMemo(() => buildChartPaths(history, fairValue), [history, fairValue]);
12926
- const recentSales = React5.useMemo(() => {
13301
+ const { valuationPath, fairValuePath, axisLabels } = React9.useMemo(() => buildChartPaths(history, fairValue), [history, fairValue]);
13302
+ const recentSales = React9.useMemo(() => {
12927
13303
  if (summary?.recentSales?.length) {
12928
13304
  return summary.recentSales;
12929
13305
  }
@@ -14075,19 +14451,19 @@ function PropertyPhotoGallery({
14075
14451
  );
14076
14452
  }
14077
14453
  function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose }) {
14078
- const [currentIndex, setCurrentIndex] = React5.useState(() => clampIndex(startIndex, galleryImages.length));
14079
- const [activeHotspotId, setActiveHotspotId] = React5.useState(null);
14080
- const sliderRef = React5.useRef(null);
14081
- const [isDragging, setIsDragging] = React5.useState(false);
14082
- const wasDraggingRef = React5.useRef(false);
14083
- const touchStartX = React5.useRef(null);
14084
- const touchStartY = React5.useRef(null);
14085
- const isSwiping = React5.useRef(false);
14086
- const progress = React5.useMemo(() => {
14454
+ const [currentIndex, setCurrentIndex] = React9.useState(() => clampIndex(startIndex, galleryImages.length));
14455
+ const [activeHotspotId, setActiveHotspotId] = React9.useState(null);
14456
+ const sliderRef = React9.useRef(null);
14457
+ const [isDragging, setIsDragging] = React9.useState(false);
14458
+ const wasDraggingRef = React9.useRef(false);
14459
+ const touchStartX = React9.useRef(null);
14460
+ const touchStartY = React9.useRef(null);
14461
+ const isSwiping = React9.useRef(false);
14462
+ const progress = React9.useMemo(() => {
14087
14463
  if (galleryImages.length <= 1) return 0;
14088
14464
  return currentIndex / (galleryImages.length - 1) * 100;
14089
14465
  }, [currentIndex, galleryImages.length]);
14090
- React5.useEffect(() => {
14466
+ React9.useEffect(() => {
14091
14467
  document.body.style.overflow = "hidden";
14092
14468
  document.body.style.touchAction = "none";
14093
14469
  return () => {
@@ -14095,7 +14471,7 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
14095
14471
  document.body.style.touchAction = "";
14096
14472
  };
14097
14473
  }, []);
14098
- React5.useEffect(() => {
14474
+ React9.useEffect(() => {
14099
14475
  const handleKey = (event) => {
14100
14476
  if (event.key === "Escape") onClose();
14101
14477
  if (event.key === "ArrowLeft") setCurrentIndex((i) => i === 0 ? galleryImages.length - 1 : i - 1);
@@ -14368,13 +14744,13 @@ function truncateHash(hash) {
14368
14744
  return `${hash.slice(0, 6)}\u2026${hash.slice(-4)}`;
14369
14745
  }
14370
14746
  function ToastItem({ toast, onDismiss }) {
14371
- const [exiting, setExiting] = React5.useState(false);
14372
- const timerRef = React5.useRef(null);
14373
- const dismiss = React5.useCallback(() => {
14747
+ const [exiting, setExiting] = React9.useState(false);
14748
+ const timerRef = React9.useRef(null);
14749
+ const dismiss = React9.useCallback(() => {
14374
14750
  setExiting(true);
14375
14751
  setTimeout(() => onDismiss(toast.id), 280);
14376
14752
  }, [onDismiss, toast.id]);
14377
- React5.useEffect(() => {
14753
+ React9.useEffect(() => {
14378
14754
  const duration2 = toast.duration ?? 6e3;
14379
14755
  if (duration2 > 0) {
14380
14756
  timerRef.current = setTimeout(dismiss, duration2);
@@ -14403,15 +14779,15 @@ function ToastItem({ toast, onDismiss }) {
14403
14779
  duration > 0 && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { $color: accent, $duration: duration })
14404
14780
  ] });
14405
14781
  }
14406
- var ToastContext = React5.createContext(null);
14782
+ var ToastContext = React9.createContext(null);
14407
14783
  function ToastProvider({ children }) {
14408
- const [toasts, setToasts] = React5.useState([]);
14409
- const addToast = React5.useCallback((data) => {
14784
+ const [toasts, setToasts] = React9.useState([]);
14785
+ const addToast = React9.useCallback((data) => {
14410
14786
  const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
14411
14787
  setToasts((prev) => [...prev, { ...data, id }]);
14412
14788
  return id;
14413
14789
  }, []);
14414
- const dismiss = React5.useCallback((id) => {
14790
+ const dismiss = React9.useCallback((id) => {
14415
14791
  setToasts((prev) => prev.filter((t) => t.id !== id));
14416
14792
  }, []);
14417
14793
  return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast: addToast, dismiss }, children: [
@@ -14420,10 +14796,71 @@ function ToastProvider({ children }) {
14420
14796
  ] });
14421
14797
  }
14422
14798
  function useToast() {
14423
- const ctx = React5.useContext(ToastContext);
14799
+ const ctx = React9.useContext(ToastContext);
14424
14800
  if (!ctx) throw new Error("useToast must be used within a ToastProvider");
14425
14801
  return ctx;
14426
14802
  }
14803
+ var INTERVALS = [1e3, 2e3, 4e3, 5e3, 7e3, 1e4, 12e3];
14804
+ function useAdaptivePolling({ enabled, onPoll }) {
14805
+ const onPollRef = React9.useRef(onPoll);
14806
+ onPollRef.current = onPoll;
14807
+ React9.useEffect(() => {
14808
+ if (!enabled) return;
14809
+ let cancelled = false;
14810
+ let timeoutId = null;
14811
+ let step = 0;
14812
+ const clear = () => {
14813
+ if (timeoutId) {
14814
+ clearTimeout(timeoutId);
14815
+ timeoutId = null;
14816
+ }
14817
+ };
14818
+ const isHidden = () => typeof document !== "undefined" && document.visibilityState === "hidden";
14819
+ const tick = async () => {
14820
+ if (cancelled) return;
14821
+ if (isHidden()) {
14822
+ return;
14823
+ }
14824
+ try {
14825
+ await onPollRef.current();
14826
+ } catch {
14827
+ }
14828
+ if (cancelled) return;
14829
+ step = Math.min(step + 1, INTERVALS.length - 1);
14830
+ timeoutId = setTimeout(tick, INTERVALS[step]);
14831
+ };
14832
+ const onVisibility = () => {
14833
+ if (document.visibilityState === "visible") {
14834
+ step = 0;
14835
+ clear();
14836
+ timeoutId = setTimeout(tick, 0);
14837
+ }
14838
+ };
14839
+ if (typeof document !== "undefined") {
14840
+ document.addEventListener("visibilitychange", onVisibility);
14841
+ }
14842
+ timeoutId = setTimeout(tick, INTERVALS[0]);
14843
+ return () => {
14844
+ cancelled = true;
14845
+ clear();
14846
+ if (typeof document !== "undefined") {
14847
+ document.removeEventListener("visibilitychange", onVisibility);
14848
+ }
14849
+ };
14850
+ }, [enabled]);
14851
+ }
14852
+ function hasPendingActivity(data) {
14853
+ if (!data) return false;
14854
+ const openPending = data.openOrders?.some((o) => {
14855
+ const s = o.status.toUpperCase();
14856
+ return s === "OPEN" || s === "PARTIALLY_FILLED";
14857
+ }) ?? false;
14858
+ if (openPending) return true;
14859
+ return data.offeringOrders?.some((o) => {
14860
+ const s = o.status.toUpperCase();
14861
+ return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
14862
+ }) ?? false;
14863
+ }
14427
14864
 
14428
14865
  exports.AssetSelectorBar = AssetSelectorBar;
14429
14866
  exports.Badge = Badge;
@@ -14460,12 +14897,15 @@ exports.PropertyPhotoGallery = PropertyPhotoGallery;
14460
14897
  exports.PropertySubheader = PropertySubheader;
14461
14898
  exports.PropertyTour = PropertyTour;
14462
14899
  exports.PropertyValuation = PropertyValuation;
14900
+ exports.Skeleton = Skeleton;
14463
14901
  exports.ToastProvider = ToastProvider;
14464
14902
  exports.TradeConfirmationModal = TradeConfirmationModal;
14465
14903
  exports.TradingSlider = TradingSlider;
14466
14904
  exports.YourOrders = YourOrders;
14467
14905
  exports.badgeVariants = badgeVariants;
14468
14906
  exports.buttonVariants = buttonVariants;
14907
+ exports.hasPendingActivity = hasPendingActivity;
14908
+ exports.useAdaptivePolling = useAdaptivePolling;
14469
14909
  exports.useToast = useToast;
14470
14910
  //# sourceMappingURL=index.js.map
14471
14911
  //# sourceMappingURL=index.js.map