@loafmarkets/ui 0.1.414 → 0.1.416

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,13 +1,13 @@
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');
7
7
  var tailwindMerge = require('tailwind-merge');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
- var styled10 = require('styled-components');
10
9
  var ReactDOM = require('react-dom');
10
+ var styled10 = require('styled-components');
11
11
  var lucideReact = require('lucide-react');
12
12
  var LightweightCharts = require('lightweight-charts');
13
13
  var md = require('react-icons/md');
@@ -36,9 +36,9 @@ function _interopNamespace(e) {
36
36
  return Object.freeze(n);
37
37
  }
38
38
 
39
- var React5__namespace = /*#__PURE__*/_interopNamespace(React5);
40
- var styled10__default = /*#__PURE__*/_interopDefault(styled10);
39
+ var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
41
40
  var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
41
+ var styled10__default = /*#__PURE__*/_interopDefault(styled10);
42
42
  var LightweightCharts__namespace = /*#__PURE__*/_interopNamespace(LightweightCharts);
43
43
 
44
44
  // src/components/button.tsx
@@ -79,7 +79,7 @@ var buttonVariants = classVarianceAuthority.cva(
79
79
  }
80
80
  }
81
81
  );
82
- var Button = React5__namespace.forwardRef(
82
+ var Button = React9__namespace.forwardRef(
83
83
  ({ className, variant, size, radius, asChild = false, ...props }, ref) => {
84
84
  const Comp = asChild ? reactSlot.Slot : "button";
85
85
  const coercedRadius = radius ?? (variant === "onboarding" || variant === "onboardingOutline" ? "square" : void 0);
@@ -118,11 +118,11 @@ var badgeVariants = classVarianceAuthority.cva(
118
118
  }
119
119
  }
120
120
  );
121
- var Badge = React5__namespace.forwardRef(
121
+ var Badge = React9__namespace.forwardRef(
122
122
  ({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
123
123
  );
124
124
  Badge.displayName = "Badge";
125
- var Card = React5__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
125
+ var Card = React9__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
126
126
  "div",
127
127
  {
128
128
  ref,
@@ -134,11 +134,11 @@ var Card = React5__namespace.forwardRef(({ className, ...props }, ref) => /* @__
134
134
  }
135
135
  ));
136
136
  Card.displayName = "Card";
137
- var CardHeader = React5__namespace.forwardRef(
137
+ var CardHeader = React9__namespace.forwardRef(
138
138
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
139
139
  );
140
140
  CardHeader.displayName = "CardHeader";
141
- var CardTitle = React5__namespace.forwardRef(
141
+ var CardTitle = React9__namespace.forwardRef(
142
142
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
143
143
  "h3",
144
144
  {
@@ -149,15 +149,15 @@ var CardTitle = React5__namespace.forwardRef(
149
149
  )
150
150
  );
151
151
  CardTitle.displayName = "CardTitle";
152
- var CardDescription = React5__namespace.forwardRef(
152
+ var CardDescription = React9__namespace.forwardRef(
153
153
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-slate-500", className), ...props })
154
154
  );
155
155
  CardDescription.displayName = "CardDescription";
156
- var CardContent = React5__namespace.forwardRef(
156
+ var CardContent = React9__namespace.forwardRef(
157
157
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("px-6 pb-6 pt-2 text-sm text-slate-600", className), ...props })
158
158
  );
159
159
  CardContent.displayName = "CardContent";
160
- var CardFooter = React5__namespace.forwardRef(
160
+ var CardFooter = React9__namespace.forwardRef(
161
161
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex items-center border-t border-slate-100 px-6 py-4", className), ...props })
162
162
  );
163
163
  CardFooter.displayName = "CardFooter";
@@ -175,7 +175,7 @@ var defaultFormatSignedCurrency = (value) => {
175
175
  const sign = value >= 0 ? "+" : "-";
176
176
  return `${sign}${defaultFormatCurrency(Math.abs(value))}`;
177
177
  };
178
- var PortfolioSummary = React5__namespace.forwardRef(
178
+ var PortfolioSummary = React9__namespace.forwardRef(
179
179
  ({
180
180
  availableCash,
181
181
  portfolioValue,
@@ -325,23 +325,23 @@ function HousePositionSlider({
325
325
  className,
326
326
  ...props
327
327
  }) {
328
- const [orderMode, setOrderMode] = React5__namespace.useState("none");
329
- const [buyTrackingMode, setBuyTrackingMode] = React5__namespace.useState("dollars");
330
- const [deltaDollars, setDeltaDollars] = React5__namespace.useState(0);
331
- const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
332
- const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
333
- const [_isDragging, setIsDragging] = React5__namespace.useState(false);
334
- const [visualTargetPct, setVisualTargetPct] = React5__namespace.useState(null);
335
- const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
336
- const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
337
- const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
338
- const [limitPriceDirty, setLimitPriceDirty] = React5__namespace.useState(false);
339
- const [ownershipInput, setOwnershipInput] = React5__namespace.useState("");
340
- const [tokenAmountInput, setTokenAmountInput] = React5__namespace.useState("");
341
- const houseRef = React5__namespace.useRef(null);
328
+ const [orderMode, setOrderMode] = React9__namespace.useState("none");
329
+ const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
330
+ const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
331
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
332
+ const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
333
+ const [_isDragging, setIsDragging] = React9__namespace.useState(false);
334
+ const [visualTargetPct, setVisualTargetPct] = React9__namespace.useState(null);
335
+ const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
336
+ const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
337
+ const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
338
+ const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
339
+ const [ownershipInput, setOwnershipInput] = React9__namespace.useState("");
340
+ const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
341
+ const houseRef = React9__namespace.useRef(null);
342
342
  const asks = orderbook?.asks ?? [];
343
343
  const bids = orderbook?.bids ?? [];
344
- React5__namespace.useEffect(() => {
344
+ React9__namespace.useEffect(() => {
345
345
  if (orderType !== "limit") return;
346
346
  if (limitPriceDirty) return;
347
347
  setLimitPrice(currentPrice);
@@ -416,7 +416,7 @@ function HousePositionSlider({
416
416
  const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
417
417
  const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
418
418
  const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
419
- const resetOrder = React5__namespace.useCallback(() => {
419
+ const resetOrder = React9__namespace.useCallback(() => {
420
420
  setOrderMode("none");
421
421
  setBuyTrackingMode("dollars");
422
422
  setDeltaDollars(0);
@@ -424,7 +424,7 @@ function HousePositionSlider({
424
424
  setDeltaTokensSell(0);
425
425
  setVisualTargetPct(null);
426
426
  }, []);
427
- const updateOrderFromTargetValue = React5__namespace.useCallback(
427
+ const updateOrderFromTargetValue = React9__namespace.useCallback(
428
428
  (newTargetValue) => {
429
429
  const newDeltaValue = newTargetValue - holdingsValue;
430
430
  if (newDeltaValue > 0) {
@@ -448,7 +448,7 @@ function HousePositionSlider({
448
448
  },
449
449
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, resetOrder, tokensHeld]
450
450
  );
451
- const updateOrderFromOwnership = React5__namespace.useCallback(
451
+ const updateOrderFromOwnership = React9__namespace.useCallback(
452
452
  (newOwnershipPercent) => {
453
453
  const nextOwnership = clamp(newOwnershipPercent, 0, 100);
454
454
  const newTargetTokens = nextOwnership / 100 * totalTokens;
@@ -457,7 +457,7 @@ function HousePositionSlider({
457
457
  },
458
458
  [effectivePrice, totalTokens, updateOrderFromTargetValue]
459
459
  );
460
- const updateOrderFromTokenAmount = React5__namespace.useCallback(
460
+ const updateOrderFromTokenAmount = React9__namespace.useCallback(
461
461
  (tokenAmountSigned) => {
462
462
  if (tokenAmountSigned > 0) {
463
463
  const maxTokens = effectiveAvailableCash / (effectivePrice || 1);
@@ -480,7 +480,7 @@ function HousePositionSlider({
480
480
  },
481
481
  [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, resetOrder]
482
482
  );
483
- const updateOrderFromSlider = React5__namespace.useCallback(
483
+ const updateOrderFromSlider = React9__namespace.useCallback(
484
484
  (pct) => {
485
485
  const normalized = (pct - 50) / 50;
486
486
  const magnitude = Math.min(Math.abs(normalized), 1);
@@ -524,7 +524,7 @@ function HousePositionSlider({
524
524
  },
525
525
  [effectiveAvailableCash, effectiveTokensHeld, resetOrder]
526
526
  );
527
- const handleDragAtClientY = React5__namespace.useCallback(
527
+ const handleDragAtClientY = React9__namespace.useCallback(
528
528
  (clientY) => {
529
529
  if (!houseRef.current) return;
530
530
  const rect = houseRef.current.getBoundingClientRect();
@@ -1040,18 +1040,18 @@ function HousePositionSliderMobile({
1040
1040
  className,
1041
1041
  ...props
1042
1042
  }) {
1043
- const [orderMode, setOrderMode] = React5__namespace.useState("none");
1044
- const [deltaDollars, setDeltaDollars] = React5__namespace.useState(0);
1045
- const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
1046
- const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
1047
- const [buyTrackingMode, setBuyTrackingMode] = React5__namespace.useState("dollars");
1048
- const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
1049
- const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
1050
- const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
1051
- const [limitPriceDirty, setLimitPriceDirty] = React5__namespace.useState(false);
1052
- const [tokenAmountInput, setTokenAmountInput] = React5__namespace.useState("");
1053
- const houseRef = React5__namespace.useRef(null);
1054
- React5__namespace.useEffect(() => {
1043
+ const [orderMode, setOrderMode] = React9__namespace.useState("none");
1044
+ const [deltaDollars, setDeltaDollars] = React9__namespace.useState(0);
1045
+ const [deltaTokensSell, setDeltaTokensSell] = React9__namespace.useState(0);
1046
+ const [deltaTokensBuy, setDeltaTokensBuy] = React9__namespace.useState(0);
1047
+ const [buyTrackingMode, setBuyTrackingMode] = React9__namespace.useState("dollars");
1048
+ const [orderType, setOrderType] = React9__namespace.useState(defaultOrderType);
1049
+ const [limitPrice, setLimitPrice] = React9__namespace.useState(currentPrice);
1050
+ const [limitPriceInput, setLimitPriceInput] = React9__namespace.useState(currentPrice.toFixed(2));
1051
+ const [limitPriceDirty, setLimitPriceDirty] = React9__namespace.useState(false);
1052
+ const [tokenAmountInput, setTokenAmountInput] = React9__namespace.useState("");
1053
+ const houseRef = React9__namespace.useRef(null);
1054
+ React9__namespace.useEffect(() => {
1055
1055
  if (orderType !== "limit") return;
1056
1056
  if (limitPriceDirty) return;
1057
1057
  setLimitPrice(currentPrice);
@@ -1093,7 +1093,7 @@ function HousePositionSliderMobile({
1093
1093
  const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
1094
1094
  const targetOwnership = totalTokens > 0 ? targetTokens / totalTokens * 100 : 0;
1095
1095
  const estFeeTokens = effectivePrice > 0 ? Math.abs(deltaValue) * 5e-3 / effectivePrice : 0;
1096
- const updateOrderFromTargetValue = React5__namespace.useCallback(
1096
+ const updateOrderFromTargetValue = React9__namespace.useCallback(
1097
1097
  (newTargetValue) => {
1098
1098
  const newDeltaValue = newTargetValue - holdingsValue;
1099
1099
  if (newDeltaValue > 0.01) {
@@ -1121,7 +1121,7 @@ function HousePositionSliderMobile({
1121
1121
  },
1122
1122
  [holdingsValue, availableCash, effectivePrice, tokensHeld]
1123
1123
  );
1124
- const updateOrderFromTokenAmount = React5__namespace.useCallback(
1124
+ const updateOrderFromTokenAmount = React9__namespace.useCallback(
1125
1125
  (tokenAmount) => {
1126
1126
  if (tokenAmount > 0) {
1127
1127
  const maxTokens = effectivePrice > 0 ? availableCash / effectivePrice : 0;
@@ -1148,14 +1148,14 @@ function HousePositionSliderMobile({
1148
1148
  },
1149
1149
  [effectivePrice, availableCash, tokensHeld]
1150
1150
  );
1151
- const handleMarkerClick = React5__namespace.useCallback(
1151
+ const handleMarkerClick = React9__namespace.useCallback(
1152
1152
  (pct) => {
1153
1153
  const newTargetValue = pct / 100 * totalCapacity;
1154
1154
  updateOrderFromTargetValue(newTargetValue);
1155
1155
  },
1156
1156
  [totalCapacity, updateOrderFromTargetValue]
1157
1157
  );
1158
- const onMouseDown = React5__namespace.useCallback(
1158
+ const onMouseDown = React9__namespace.useCallback(
1159
1159
  (e) => {
1160
1160
  e.preventDefault();
1161
1161
  const move = (ev) => {
@@ -1175,7 +1175,7 @@ function HousePositionSliderMobile({
1175
1175
  },
1176
1176
  [totalCapacity, updateOrderFromTargetValue]
1177
1177
  );
1178
- const onTouchStart = React5__namespace.useCallback(
1178
+ const onTouchStart = React9__namespace.useCallback(
1179
1179
  (e) => {
1180
1180
  e.preventDefault();
1181
1181
  e.stopPropagation();
@@ -1655,7 +1655,7 @@ var StatusDot = styled10__default.default.span`
1655
1655
  background: rgba(255, 255, 255, 0.3);
1656
1656
  `}
1657
1657
  `;
1658
- var LoafLiquidityBadge = React5__namespace.forwardRef(
1658
+ var LoafLiquidityBadge = React9__namespace.forwardRef(
1659
1659
  ({ className, isGlowing, status = "unknown", onClick, children, ...props }, ref) => {
1660
1660
  return /* @__PURE__ */ jsxRuntime.jsxs(
1661
1661
  LogoContainer,
@@ -1679,7 +1679,7 @@ var LoafLiquidityBadge = React5__namespace.forwardRef(
1679
1679
  );
1680
1680
  LoafLiquidityBadge.displayName = "LoafLiquidityBadge";
1681
1681
  var toSize = (v, fallback) => v == null ? fallback : typeof v === "number" ? `${v}px` : v;
1682
- var Skeleton = React5__namespace.forwardRef(
1682
+ var Skeleton = React9__namespace.forwardRef(
1683
1683
  ({ width, height, radius, className, style, ...props }, ref) => {
1684
1684
  return /* @__PURE__ */ jsxRuntime.jsx(
1685
1685
  "div",
@@ -1703,9 +1703,17 @@ var Skeleton = React5__namespace.forwardRef(
1703
1703
  }
1704
1704
  );
1705
1705
  Skeleton.displayName = "Skeleton";
1706
+ var DEFAULT_PRICE_LABEL = "Price (USD)";
1707
+ var PRICE_UNIT_MIN_WIDTH_PX = 320;
1708
+ function priceHeaderLabel(label, panelWidth) {
1709
+ if (label === DEFAULT_PRICE_LABEL && panelWidth != null && panelWidth > 0 && panelWidth < PRICE_UNIT_MIN_WIDTH_PX) {
1710
+ return "Price";
1711
+ }
1712
+ return label;
1713
+ }
1706
1714
  function useViewportCompact(breakpoint) {
1707
- const [isCompact, setIsCompact] = React5__namespace.useState(false);
1708
- React5__namespace.useEffect(() => {
1715
+ const [isCompact, setIsCompact] = React9__namespace.useState(false);
1716
+ React9__namespace.useEffect(() => {
1709
1717
  if (typeof window === "undefined") return;
1710
1718
  const check = () => setIsCompact(window.innerWidth <= breakpoint);
1711
1719
  check();
@@ -1720,9 +1728,14 @@ var formatTradeTime = (time) => {
1720
1728
  if (Number.isNaN(d.getTime())) return time;
1721
1729
  return d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false });
1722
1730
  };
1723
- var FLASH_DURATION_MS = 450;
1724
- var FLASH_UP_COLOR = "rgba(14, 203, 129, 0.35)";
1725
- var FLASH_DOWN_COLOR = "rgba(246, 70, 93, 0.35)";
1731
+ var FLASH_DURATION_MS = 900;
1732
+ var FLASH_UP_COLOR = "rgba(14, 203, 129, 0.22)";
1733
+ var FLASH_DOWN_COLOR = "rgba(246, 70, 93, 0.22)";
1734
+ var FLASH_KEYFRAMES = (color) => [
1735
+ { backgroundColor: "rgba(0,0,0,0)" },
1736
+ { backgroundColor: color, offset: 0.3 },
1737
+ { backgroundColor: "rgba(0,0,0,0)" }
1738
+ ];
1726
1739
  function getTradeKey(trade, fallbackIndex) {
1727
1740
  if (trade.tradeId != null) return `id-${trade.tradeId}`;
1728
1741
  if (trade.time != null) return `t-${trade.time}-${trade.type}-${trade.price}-${trade.amount}`;
@@ -1731,14 +1744,11 @@ function getTradeKey(trade, fallbackIndex) {
1731
1744
  function flashElement(node, side) {
1732
1745
  if (typeof node.animate !== "function") return;
1733
1746
  const color = side === "bid" ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1734
- node.animate(
1735
- [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1736
- { duration: FLASH_DURATION_MS, easing: "ease-out" }
1737
- );
1747
+ node.animate(FLASH_KEYFRAMES(color), { duration: FLASH_DURATION_MS, easing: "ease-in-out" });
1738
1748
  }
1739
1749
  function useAmountChangeFlash(ref, amount, side, flashOnMount) {
1740
- const prevAmountRef = React5__namespace.useRef(flashOnMount ? null : amount);
1741
- React5__namespace.useEffect(() => {
1750
+ const prevAmountRef = React9__namespace.useRef(flashOnMount ? null : amount);
1751
+ React9__namespace.useEffect(() => {
1742
1752
  const prev = prevAmountRef.current;
1743
1753
  const node = ref.current;
1744
1754
  if (node && prev !== amount) {
@@ -1759,18 +1769,15 @@ function TradeRow({
1759
1769
  compact,
1760
1770
  explorerUrl
1761
1771
  }) {
1762
- const rowRef = React5__namespace.useRef(null);
1772
+ const rowRef = React9__namespace.useRef(null);
1763
1773
  const { type } = trade;
1764
- React5__namespace.useEffect(() => {
1774
+ React9__namespace.useEffect(() => {
1765
1775
  if (seenTradeKeysRef.current.has(tradeKey)) return;
1766
1776
  seenTradeKeysRef.current.add(tradeKey);
1767
1777
  const node = rowRef.current;
1768
1778
  if (!node || typeof node.animate !== "function") return;
1769
1779
  const color = type === "buy" ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
1770
- node.animate(
1771
- [{ backgroundColor: color }, { backgroundColor: "transparent" }],
1772
- { duration: FLASH_DURATION_MS, easing: "ease-out" }
1773
- );
1780
+ node.animate(FLASH_KEYFRAMES(color), { duration: FLASH_DURATION_MS, easing: "ease-in-out" });
1774
1781
  }, [tradeKey, seenTradeKeysRef, type]);
1775
1782
  if (compact) {
1776
1783
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1837,6 +1844,27 @@ function TradeRow({
1837
1844
  }
1838
1845
  );
1839
1846
  }
1847
+ function BreadSliceGlyph() {
1848
+ return /* @__PURE__ */ jsxRuntime.jsx(
1849
+ "svg",
1850
+ {
1851
+ width: "10",
1852
+ height: "10",
1853
+ viewBox: "0 0 10 10",
1854
+ "aria-hidden": "true",
1855
+ style: { display: "block", filter: "drop-shadow(0 0 4px rgba(201,162,39,0.6))" },
1856
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1857
+ "path",
1858
+ {
1859
+ d: "M1 4.2 C1 1.9 2.7 1 5 1 C7.3 1 9 1.9 9 4.2 L9 8.2 C9 8.6 8.6 9 8.2 9 L1.8 9 C1.4 9 1 8.6 1 8.2 Z",
1860
+ fill: "none",
1861
+ stroke: "#C9A227",
1862
+ strokeWidth: "1.3"
1863
+ }
1864
+ )
1865
+ }
1866
+ );
1867
+ }
1840
1868
  function DepthRow({
1841
1869
  side,
1842
1870
  price,
@@ -1851,12 +1879,14 @@ function DepthRow({
1851
1879
  fillHeight
1852
1880
  }) {
1853
1881
  const isAsk = side === "ask";
1854
- const rowRef = React5__namespace.useRef(null);
1882
+ const rowRef = React9__namespace.useRef(null);
1855
1883
  useAmountChangeFlash(rowRef, amount, side, flashOnMount);
1856
1884
  return /* @__PURE__ */ jsxRuntime.jsxs(
1857
1885
  "div",
1858
1886
  {
1859
1887
  ref: rowRef,
1888
+ "data-depth-row": true,
1889
+ "data-price": `$${formatNumber(price, precision)}`,
1860
1890
  className: "relative grid grid-cols-3 items-center gap-3 px-3 text-[0.8rem]",
1861
1891
  style: fillHeight ? { flex: "1 1 0", minHeight: 0, maxHeight: `${DEPTH_ROW_HEIGHT_PX}px`, cursor: onPriceClick ? "pointer" : void 0 } : { height: `${DEPTH_ROW_HEIGHT_PX}px`, flexShrink: 0, cursor: onPriceClick ? "pointer" : void 0 },
1862
1892
  onClick: onPriceClick ? () => onPriceClick(price) : void 0,
@@ -1864,14 +1894,20 @@ function DepthRow({
1864
1894
  /* @__PURE__ */ jsxRuntime.jsx(
1865
1895
  "div",
1866
1896
  {
1897
+ "data-depth-bar": true,
1867
1898
  className: cn(isAsk ? "bg-rose-900/30" : "bg-emerald-900/30"),
1868
1899
  style: {
1869
1900
  position: "absolute",
1870
- top: 0,
1871
- bottom: 0,
1901
+ top: 1,
1902
+ bottom: 1,
1872
1903
  left: 0,
1873
1904
  width: `${clamp3(depthPct, 0, 100)}%`,
1874
- transition: "width 300ms ease-out"
1905
+ transition: "width 300ms ease-out",
1906
+ borderRadius: "0 4px 4px 0",
1907
+ // backgroundImage LONGHAND, not the `background` shorthand — jsdom's
1908
+ // cssstyle drops gradients from the shorthand (tests assert this).
1909
+ backgroundColor: "transparent",
1910
+ backgroundImage: isAsk ? "linear-gradient(90deg, rgba(246,70,93,0.11), rgba(246,70,93,0.15))" : "linear-gradient(90deg, rgba(14,203,129,0.09), rgba(14,203,129,0.13))"
1875
1911
  }
1876
1912
  }
1877
1913
  ),
@@ -1879,33 +1915,35 @@ function DepthRow({
1879
1915
  "span",
1880
1916
  {
1881
1917
  "aria-label": "Your order at this price",
1882
- className: "absolute left-0 top-1/2 -translate-y-1/2 z-[2] h-[6px] w-[6px] rounded-full bg-[#C9A227] shadow-[0_0_6px_rgba(201,162,39,0.7)]"
1918
+ className: "absolute left-0 top-1/2 -translate-y-1/2 z-[2]",
1919
+ children: /* @__PURE__ */ jsxRuntime.jsx(BreadSliceGlyph, {})
1883
1920
  }
1884
1921
  ) : null,
1885
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative z-[1] tabular-nums", isAsk ? "text-[#f6465d]" : "text-[#0ecb81]"), children: [
1922
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cell": "price", className: cn("relative z-[1] tabular-nums", isAsk ? "text-[#f6465d]" : "text-[#0ecb81]"), children: [
1886
1923
  "$",
1887
1924
  formatNumber(price, precision)
1888
1925
  ] }),
1889
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-[1] text-right tabular-nums text-white/90", children: formatNumber(amount, amountPrecision) }),
1890
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-[1] text-right tabular-nums text-white/50", children: formatNumber(cumDepth, amountPrecision) })
1926
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cell": "amt", className: "relative z-[1] text-right tabular-nums text-white/90", children: formatNumber(amount, amountPrecision) }),
1927
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cell": "tot", className: "relative z-[1] text-right tabular-nums text-white/50", children: formatNumber(cumDepth, amountPrecision) })
1891
1928
  ]
1892
1929
  }
1893
1930
  );
1894
1931
  }
1895
1932
  var clamp3 = (value, min, max) => Math.min(max, Math.max(min, value));
1933
+ var fitLevelCount = (availableHeightPx, max) => clamp3(Math.floor(availableHeightPx / DEPTH_ROW_HEIGHT_PX), 1, max);
1896
1934
  var LEVEL_ROWS_VISIBLE = 8;
1897
1935
  var DEPTH_ROW_HEIGHT_PX = 28;
1898
1936
  var COMPACT_ROWS_VISIBLE = 5;
1899
1937
  var COMPACT_ROW_HEIGHT_PX = 30;
1900
1938
  var COMPACT_BREAKPOINT_PX = 1024;
1901
- var Orderbook = React5__namespace.forwardRef(
1939
+ var Orderbook = React9__namespace.forwardRef(
1902
1940
  ({
1903
1941
  asks,
1904
1942
  bids,
1905
1943
  midPrice,
1906
1944
  midChangePercent,
1907
1945
  trades = [],
1908
- priceLabel = "Price (USD)",
1946
+ priceLabel = DEFAULT_PRICE_LABEL,
1909
1947
  amountLabel = "Amount",
1910
1948
  precision = 2,
1911
1949
  amountPrecision = 2,
@@ -1933,12 +1971,12 @@ var Orderbook = React5__namespace.forwardRef(
1933
1971
  status: liquidityStatus
1934
1972
  }
1935
1973
  );
1936
- const [tab, setTabState] = React5__namespace.useState(defaultTab);
1974
+ const [tab, setTabState] = React9__namespace.useState(defaultTab);
1937
1975
  const setTab = setTabState;
1938
1976
  const effectiveTab = showTradesTab ? tab : "orderbook";
1939
- const [tradeFilter, setTradeFilter] = React5__namespace.useState("all");
1977
+ const [tradeFilter, setTradeFilter] = React9__namespace.useState("all");
1940
1978
  const viewportCompact = useViewportCompact(COMPACT_BREAKPOINT_PX);
1941
- const { userAskPrices, userBidPrices } = React5__namespace.useMemo(() => {
1979
+ const { userAskPrices, userBidPrices } = React9__namespace.useMemo(() => {
1942
1980
  const ask = /* @__PURE__ */ new Set();
1943
1981
  const bid = /* @__PURE__ */ new Set();
1944
1982
  if (!userOrderPrices) return { userAskPrices: ask, userBidPrices: bid };
@@ -1948,15 +1986,15 @@ var Orderbook = React5__namespace.forwardRef(
1948
1986
  }
1949
1987
  return { userAskPrices: ask, userBidPrices: bid };
1950
1988
  }, [userOrderPrices]);
1951
- const seenTradeKeysRef = React5__namespace.useRef(/* @__PURE__ */ new Set());
1952
- const initializedRef = React5__namespace.useRef(false);
1989
+ const seenTradeKeysRef = React9__namespace.useRef(/* @__PURE__ */ new Set());
1990
+ const initializedRef = React9__namespace.useRef(false);
1953
1991
  if (!initializedRef.current && trades.length > 0) {
1954
1992
  for (let i = 0; i < trades.length; i++) {
1955
1993
  seenTradeKeysRef.current.add(getTradeKey(trades[i], i));
1956
1994
  }
1957
1995
  initializedRef.current = true;
1958
1996
  }
1959
- React5__namespace.useEffect(() => {
1997
+ React9__namespace.useEffect(() => {
1960
1998
  if (!initializedRef.current) return;
1961
1999
  const live = /* @__PURE__ */ new Set();
1962
2000
  for (let i = 0; i < trades.length; i++) {
@@ -1967,7 +2005,7 @@ var Orderbook = React5__namespace.forwardRef(
1967
2005
  if (!live.has(key)) seen.delete(key);
1968
2006
  }
1969
2007
  }, [trades]);
1970
- React5__namespace.useEffect(() => {
2008
+ React9__namespace.useEffect(() => {
1971
2009
  setTab(defaultTab);
1972
2010
  }, [defaultTab]);
1973
2011
  const handleTab = (next) => {
@@ -1975,10 +2013,49 @@ var Orderbook = React5__namespace.forwardRef(
1975
2013
  onTabChange?.(next);
1976
2014
  };
1977
2015
  const isCompact = variant === "compact" || variant === "auto" && viewportCompact;
2016
+ const rootRef = React9__namespace.useRef(null);
2017
+ const setRootRef = React9__namespace.useCallback(
2018
+ (node) => {
2019
+ rootRef.current = node;
2020
+ if (typeof ref === "function") ref(node);
2021
+ else if (ref) ref.current = node;
2022
+ },
2023
+ [ref]
2024
+ );
2025
+ const [panelWidth, setPanelWidth] = React9__namespace.useState(null);
2026
+ React9__namespace.useEffect(() => {
2027
+ if (typeof ResizeObserver === "undefined") return;
2028
+ const el = rootRef.current;
2029
+ if (!el) return;
2030
+ const ro = new ResizeObserver((entries) => {
2031
+ const w = entries[0]?.contentRect?.width;
2032
+ if (typeof w === "number") setPanelWidth((prev) => prev === w ? prev : w);
2033
+ });
2034
+ ro.observe(el);
2035
+ return () => ro.disconnect();
2036
+ }, []);
2037
+ const effectivePriceLabel = priceHeaderLabel(priceLabel, panelWidth);
1978
2038
  const effectiveLevels = maxLevels ?? LEVEL_ROWS_VISIBLE;
1979
2039
  const effectiveCompactLevels = maxLevels ?? COMPACT_ROWS_VISIBLE;
1980
2040
  const sectionHeight = isCompact ? effectiveCompactLevels * COMPACT_ROW_HEIGHT_PX : effectiveLevels * DEPTH_ROW_HEIGHT_PX;
1981
- const rowCount = isCompact ? effectiveCompactLevels : effectiveLevels;
2041
+ const asksSectionRef = React9__namespace.useRef(null);
2042
+ const [depthSectionH, setDepthSectionH] = React9__namespace.useState(null);
2043
+ React9__namespace.useEffect(() => {
2044
+ if (!fillHeight || isCompact || effectiveTab !== "orderbook") return;
2045
+ if (typeof ResizeObserver === "undefined") return;
2046
+ const el = asksSectionRef.current;
2047
+ if (!el) return;
2048
+ const ro = new ResizeObserver((entries) => {
2049
+ const h = entries[0]?.contentRect?.height;
2050
+ if (typeof h === "number") {
2051
+ setDepthSectionH((prev) => prev === h ? prev : h);
2052
+ }
2053
+ });
2054
+ ro.observe(el);
2055
+ return () => ro.disconnect();
2056
+ }, [fillHeight, isCompact, effectiveTab]);
2057
+ const fitRows = fillHeight && !isCompact && depthSectionH != null ? fitLevelCount(depthSectionH, effectiveLevels) : null;
2058
+ const rowCount = isCompact ? effectiveCompactLevels : fitRows ?? effectiveLevels;
1982
2059
  const askVisibleLevels = asks.slice(-rowCount);
1983
2060
  const bidVisibleLevels = bids.slice(0, rowCount);
1984
2061
  const askCumDepths = new Array(askVisibleLevels.length);
@@ -1999,9 +2076,9 @@ var Orderbook = React5__namespace.forwardRef(
1999
2076
  }
2000
2077
  const combinedMaxCumDepth = Math.max(1, ...askCumDepths, ...bidCumDepths);
2001
2078
  const askMaxCumDepth = combinedMaxCumDepth;
2002
- const prevAskPricesRef = React5__namespace.useRef(null);
2003
- const prevBidPricesRef = React5__namespace.useRef(null);
2004
- const newAskPrices = React5__namespace.useMemo(() => {
2079
+ const prevAskPricesRef = React9__namespace.useRef(null);
2080
+ const prevBidPricesRef = React9__namespace.useRef(null);
2081
+ const newAskPrices = React9__namespace.useMemo(() => {
2005
2082
  const current = new Set(askVisibleLevels.map((l) => l.price));
2006
2083
  const prev = prevAskPricesRef.current;
2007
2084
  if (!prev) return /* @__PURE__ */ new Set();
@@ -2011,7 +2088,7 @@ var Orderbook = React5__namespace.forwardRef(
2011
2088
  }
2012
2089
  return added;
2013
2090
  }, [askVisibleLevels]);
2014
- const newBidPrices = React5__namespace.useMemo(() => {
2091
+ const newBidPrices = React9__namespace.useMemo(() => {
2015
2092
  const current = new Set(bidVisibleLevels.map((l) => l.price));
2016
2093
  const prev = prevBidPricesRef.current;
2017
2094
  if (!prev) return /* @__PURE__ */ new Set();
@@ -2021,12 +2098,16 @@ var Orderbook = React5__namespace.forwardRef(
2021
2098
  }
2022
2099
  return added;
2023
2100
  }, [bidVisibleLevels]);
2024
- React5__namespace.useEffect(() => {
2101
+ React9__namespace.useEffect(() => {
2025
2102
  prevAskPricesRef.current = new Set(askVisibleLevels.map((l) => l.price));
2026
2103
  prevBidPricesRef.current = new Set(bidVisibleLevels.map((l) => l.price));
2027
2104
  }, [askVisibleLevels, bidVisibleLevels]);
2028
2105
  const bidMaxCumDepth = combinedMaxCumDepth;
2029
2106
  const midClass = midChangePercent == null ? "text-white" : midChangePercent >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]";
2107
+ const bestAskPrice = asks.length > 0 ? asks[asks.length - 1].price : null;
2108
+ const bestBidPrice = bids.length > 0 ? bids[0].price : null;
2109
+ const spread = bestAskPrice != null && bestBidPrice != null ? bestAskPrice - bestBidPrice : null;
2110
+ const spreadPct = spread != null && midPrice > 0 ? spread / midPrice * 100 : null;
2030
2111
  const tradeFiltered = trades.filter((t) => tradeFilter === "all" || t.type === tradeFilter);
2031
2112
  const layoutProps = {
2032
2113
  tab: effectiveTab,
@@ -2035,7 +2116,7 @@ var Orderbook = React5__namespace.forwardRef(
2035
2116
  tradeFilter,
2036
2117
  setTradeFilter,
2037
2118
  rightHeader: resolvedRightHeader,
2038
- priceLabel,
2119
+ priceLabel: effectivePriceLabel,
2039
2120
  amountLabel,
2040
2121
  tradeFiltered,
2041
2122
  precision,
@@ -2062,12 +2143,15 @@ var Orderbook = React5__namespace.forwardRef(
2062
2143
  compactLevelCount: effectiveCompactLevels,
2063
2144
  fillHeight,
2064
2145
  newAskPrices,
2065
- newBidPrices
2146
+ newBidPrices,
2147
+ spread,
2148
+ spreadPct,
2149
+ asksSectionRef
2066
2150
  };
2067
2151
  return /* @__PURE__ */ jsxRuntime.jsx(
2068
2152
  Card,
2069
2153
  {
2070
- ref,
2154
+ ref: setRootRef,
2071
2155
  className: cn(
2072
2156
  "w-full max-w-[520px] overflow-hidden rounded-[12px] border border-white/10 bg-[#111111] text-white shadow-md flex flex-col",
2073
2157
  isCompact && "max-w-none",
@@ -2081,6 +2165,170 @@ var Orderbook = React5__namespace.forwardRef(
2081
2165
  }
2082
2166
  );
2083
2167
  Orderbook.displayName = "Orderbook";
2168
+ var MID_ROW_GOLD_STYLE = {
2169
+ backgroundImage: "linear-gradient(90deg, rgba(230,200,126,0.07), rgba(230,200,126,0.015))",
2170
+ borderTop: "1px solid rgba(230,200,126,0.22)",
2171
+ borderBottom: "1px solid rgba(230,200,126,0.22)"
2172
+ };
2173
+ function SpreadReadout({
2174
+ spread,
2175
+ spreadPct,
2176
+ precision: _precision,
2177
+ compact
2178
+ }) {
2179
+ if (spread == null || spreadPct == null) return null;
2180
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2181
+ "div",
2182
+ {
2183
+ style: {
2184
+ display: "flex",
2185
+ alignItems: "baseline",
2186
+ gap: 5,
2187
+ whiteSpace: "nowrap",
2188
+ lineHeight: 1
2189
+ },
2190
+ children: [
2191
+ /* @__PURE__ */ jsxRuntime.jsx(
2192
+ "span",
2193
+ {
2194
+ style: {
2195
+ fontSize: compact ? "0.48rem" : "0.52rem",
2196
+ letterSpacing: "0.14em",
2197
+ textTransform: "uppercase",
2198
+ color: "rgba(255,255,255,0.45)",
2199
+ fontWeight: 600
2200
+ },
2201
+ children: "Spread"
2202
+ }
2203
+ ),
2204
+ /* @__PURE__ */ jsxRuntime.jsxs(
2205
+ "span",
2206
+ {
2207
+ className: "tabular-nums",
2208
+ style: { fontSize: compact ? "0.56rem" : "0.62rem", color: "rgba(255,255,255,0.45)" },
2209
+ children: [
2210
+ spreadPct.toFixed(2),
2211
+ "%"
2212
+ ]
2213
+ }
2214
+ )
2215
+ ]
2216
+ }
2217
+ );
2218
+ }
2219
+ function useGlidePill() {
2220
+ const sectionRef = React9__namespace.useRef(null);
2221
+ const pillRef = React9__namespace.useRef(null);
2222
+ const priceSpanRef = React9__namespace.useRef(null);
2223
+ const boldedCellRef = React9__namespace.useRef(null);
2224
+ const [pillPrice, setPillPrice] = React9__namespace.useState(null);
2225
+ const motion = React9__namespace.useRef({ x: 0, targetX: 0, y: 0, targetY: 0, amp: 0, on: false, raf: 0 });
2226
+ const reducedMotion = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2227
+ const unbold = () => {
2228
+ if (boldedCellRef.current) {
2229
+ boldedCellRef.current.style.fontWeight = "";
2230
+ boldedCellRef.current = null;
2231
+ }
2232
+ };
2233
+ const frame = React9__namespace.useCallback(() => {
2234
+ const m = motion.current;
2235
+ const section = sectionRef.current;
2236
+ const pill = pillRef.current;
2237
+ m.raf = 0;
2238
+ if (!section || !pill) return;
2239
+ const k = reducedMotion ? 1 : 0.12;
2240
+ m.x += (m.targetX - m.x) * k;
2241
+ m.y += (m.targetY - m.y) * k;
2242
+ pill.style.transform = `translate(${m.x.toFixed(1)}px, ${m.y.toFixed(1)}px)`;
2243
+ const ampTarget = m.on && !reducedMotion ? 1 : 0;
2244
+ m.amp += (ampTarget - m.amp) * 0.14;
2245
+ const crest = m.y + pill.offsetHeight / 2;
2246
+ const rows = section.querySelectorAll("[data-depth-row]");
2247
+ for (const row of rows) {
2248
+ const rect = row.getBoundingClientRect();
2249
+ const center = rect.top + rect.height / 2;
2250
+ const d = center - crest;
2251
+ const inf = Math.exp(-(d * d) / (2 * 42 * 42)) * m.amp;
2252
+ const bar = row.querySelector("[data-depth-bar]");
2253
+ const priceCell = row.querySelector('[data-cell="price"]');
2254
+ if (inf < 0.01) {
2255
+ if (row.dataset.waved) {
2256
+ delete row.dataset.waved;
2257
+ row.style.zIndex = "";
2258
+ row.style.background = "";
2259
+ row.style.boxShadow = "";
2260
+ if (bar) bar.style.filter = "";
2261
+ if (priceCell) priceCell.style.transform = "";
2262
+ }
2263
+ continue;
2264
+ }
2265
+ row.dataset.waved = "1";
2266
+ row.style.zIndex = String(3 + Math.round(inf * 10));
2267
+ row.style.background = `rgba(19,20,24,${(inf * 0.92).toFixed(2)})`;
2268
+ row.style.boxShadow = `0 ${(inf * 3).toFixed(1)}px ${(inf * 12).toFixed(1)}px rgba(0,0,0,${(inf * 0.45).toFixed(2)})`;
2269
+ if (bar) bar.style.filter = `brightness(${(1 + inf * 0.45).toFixed(2)})`;
2270
+ if (priceCell) {
2271
+ priceCell.style.transformOrigin = "left center";
2272
+ priceCell.style.transform = `scale(${(1 + inf * 0.09).toFixed(3)})`;
2273
+ }
2274
+ }
2275
+ if (m.on || Math.abs(m.targetX - m.x) + Math.abs(m.targetY - m.y) > 0.5 || m.amp > 5e-3) {
2276
+ m.raf = requestAnimationFrame(frame);
2277
+ }
2278
+ }, [reducedMotion]);
2279
+ const onMouseMove = React9__namespace.useCallback(
2280
+ (e) => {
2281
+ const target = e.target;
2282
+ const row = target?.closest?.("[data-depth-row]");
2283
+ const m = motion.current;
2284
+ if (!row || !row.dataset.price) {
2285
+ m.on = false;
2286
+ unbold();
2287
+ setPillPrice(null);
2288
+ return;
2289
+ }
2290
+ setPillPrice(row.dataset.price);
2291
+ const priceCell = row.querySelector('[data-cell="price"]');
2292
+ if (priceCell !== boldedCellRef.current) {
2293
+ unbold();
2294
+ if (priceCell) {
2295
+ priceCell.style.fontWeight = "600";
2296
+ boldedCellRef.current = priceCell;
2297
+ }
2298
+ }
2299
+ const pill = pillRef.current;
2300
+ if (pill && priceCell) {
2301
+ const rowRect = row.getBoundingClientRect();
2302
+ const cellRect = priceCell.getBoundingClientRect();
2303
+ const priceOffset = priceSpanRef.current?.offsetLeft || 48;
2304
+ const nextX = cellRect.left - priceOffset;
2305
+ const nextY = rowRect.top + (rowRect.height || 28) / 2 - pill.offsetHeight / 2;
2306
+ if (!m.on) {
2307
+ m.x = nextX;
2308
+ m.y = nextY;
2309
+ }
2310
+ m.targetX = nextX;
2311
+ m.targetY = nextY;
2312
+ }
2313
+ m.on = true;
2314
+ if (!m.raf && typeof requestAnimationFrame === "function") {
2315
+ m.raf = requestAnimationFrame(frame);
2316
+ }
2317
+ },
2318
+ [frame]
2319
+ );
2320
+ const onMouseLeave = React9__namespace.useCallback(() => {
2321
+ motion.current.on = false;
2322
+ unbold();
2323
+ setPillPrice(null);
2324
+ }, []);
2325
+ React9__namespace.useEffect(() => {
2326
+ return () => {
2327
+ if (motion.current.raf) cancelAnimationFrame(motion.current.raf);
2328
+ };
2329
+ }, []);
2330
+ return { sectionRef, pillRef, priceSpanRef, pillPrice, onMouseMove, onMouseLeave };
2331
+ }
2084
2332
  function SkeletonRow({ compact }) {
2085
2333
  if (compact) {
2086
2334
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2137,8 +2385,12 @@ function DesktopOrderbookLayout({
2137
2385
  compactLevelCount: _compactLevelCount,
2138
2386
  fillHeight,
2139
2387
  newAskPrices,
2140
- newBidPrices
2388
+ newBidPrices,
2389
+ spread,
2390
+ spreadPct,
2391
+ asksSectionRef
2141
2392
  }) {
2393
+ const glide = useGlidePill();
2142
2394
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2143
2395
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pt-4", children: [
2144
2396
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
@@ -2148,8 +2400,8 @@ function DesktopOrderbookLayout({
2148
2400
  type: "button",
2149
2401
  onClick: () => handleTab("orderbook"),
2150
2402
  className: cn(
2151
- "relative pb-2 text-sm font-semibold",
2152
- tab === "orderbook" ? "text-white" : "text-white/60"
2403
+ "relative pb-2 text-[0.8rem] font-medium transition-colors",
2404
+ tab === "orderbook" ? "text-white" : "text-white/60 hover:text-white/85"
2153
2405
  ),
2154
2406
  children: [
2155
2407
  "Orderbook",
@@ -2163,8 +2415,8 @@ function DesktopOrderbookLayout({
2163
2415
  type: "button",
2164
2416
  onClick: () => handleTab("trades"),
2165
2417
  className: cn(
2166
- "relative pb-2 text-sm font-medium",
2167
- tab === "trades" ? "text-white" : "text-white/60"
2418
+ "relative pb-2 text-[0.8rem] font-medium transition-colors",
2419
+ tab === "trades" ? "text-white" : "text-white/60 hover:text-white/85"
2168
2420
  ),
2169
2421
  children: [
2170
2422
  "Trades",
@@ -2212,100 +2464,170 @@ function DesktopOrderbookLayout({
2212
2464
  )
2213
2465
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: rightHeader })
2214
2466
  ] }),
2215
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col min-h-0 px-4 pt-2", children: [
2216
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-3 px-3 pb-1.5 pt-1 text-xs text-white/60", children: [
2217
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: priceLabel }),
2218
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: amountLabel }),
2219
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: tab === "orderbook" ? "Total" : "Time" })
2220
- ] }),
2221
- tab === "trades" ? /* @__PURE__ */ jsxRuntime.jsx(
2222
- "div",
2223
- {
2224
- className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
2225
- style: { scrollbarGutter: "stable" },
2226
- children: isLoading && tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: Array.from({ length: effectiveLevels }).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", { children: tradeFiltered.map((trade, i) => {
2227
- const tradeKey = getTradeKey(trade, i);
2228
- const explorerUrl = trade.txHash && tradeExplorerUrl ? tradeExplorerUrl(trade.txHash) : trade.txHash ? `https://sepolia.etherscan.io/tx/${trade.txHash}` : void 0;
2229
- return /* @__PURE__ */ jsxRuntime.jsx(
2230
- TradeRow,
2467
+ /* @__PURE__ */ jsxRuntime.jsxs(
2468
+ "div",
2469
+ {
2470
+ ref: glide.sectionRef,
2471
+ "data-glide-section": true,
2472
+ className: "relative flex flex-1 flex-col min-h-0 px-4 pt-2",
2473
+ onMouseMove: glide.onMouseMove,
2474
+ onMouseLeave: glide.onMouseLeave,
2475
+ children: [
2476
+ typeof document !== "undefined" ? ReactDOM.createPortal(
2477
+ /* @__PURE__ */ jsxRuntime.jsxs(
2478
+ "div",
2231
2479
  {
2232
- trade,
2233
- tradeKey,
2234
- precision,
2235
- amountPrecision,
2236
- seenTradeKeysRef,
2237
- explorerUrl
2238
- },
2239
- tradeKey
2240
- );
2241
- }) })
2242
- }
2243
- ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col min-h-0 overflow-hidden", fillHeight && "flex-1"), children: [
2244
- /* @__PURE__ */ jsxRuntime.jsx(
2245
- "div",
2246
- {
2247
- className: cn("flex flex-col justify-end overflow-hidden", !fillHeight && "flex-shrink-0"),
2248
- style: fillHeight ? { flex: 1, minHeight: 0 } : { height: `${sectionHeight}px` },
2249
- children: isLoading ? Array.from({ length: effectiveLevels }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `ask-skel-${i}`)) : askVisibleLevels.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center px-3 text-xs text-white/40", children: "No asks" }) : askVisibleLevels.map((l, i) => /* @__PURE__ */ jsxRuntime.jsx(
2250
- DepthRow,
2480
+ ref: glide.pillRef,
2481
+ "data-glide-pill": true,
2482
+ "data-visible": glide.pillPrice != null ? "true" : "false",
2483
+ style: {
2484
+ position: "fixed",
2485
+ left: 0,
2486
+ top: 0,
2487
+ zIndex: 60,
2488
+ pointerEvents: "none",
2489
+ display: "flex",
2490
+ alignItems: "center",
2491
+ gap: 8,
2492
+ whiteSpace: "nowrap",
2493
+ background: "#1b1d22",
2494
+ border: "1px solid rgba(255,255,255,0.14)",
2495
+ borderRadius: 999,
2496
+ padding: "4px 13px",
2497
+ boxShadow: "0 6px 20px rgba(0,0,0,0.55)",
2498
+ fontVariantNumeric: "tabular-nums",
2499
+ opacity: glide.pillPrice != null ? 1 : 0,
2500
+ transition: "opacity 160ms ease"
2501
+ },
2502
+ children: [
2503
+ /* @__PURE__ */ jsxRuntime.jsx(
2504
+ "span",
2505
+ {
2506
+ style: {
2507
+ fontSize: "0.6rem",
2508
+ fontWeight: 600,
2509
+ letterSpacing: "0.08em",
2510
+ textTransform: "uppercase",
2511
+ color: "#E6C87E",
2512
+ lineHeight: 1
2513
+ },
2514
+ children: "Limit"
2515
+ }
2516
+ ),
2517
+ /* @__PURE__ */ jsxRuntime.jsx(
2518
+ "span",
2519
+ {
2520
+ ref: glide.priceSpanRef,
2521
+ className: "tabular-nums",
2522
+ style: { fontSize: "0.8rem", fontWeight: 600, color: "#fff" },
2523
+ children: glide.pillPrice ?? ""
2524
+ }
2525
+ )
2526
+ ]
2527
+ }
2528
+ ),
2529
+ document.body
2530
+ ) : null,
2531
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-3 px-3 pb-1.5 pt-1 text-xs text-white/60", children: [
2532
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: priceLabel }),
2533
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: amountLabel }),
2534
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: tab === "orderbook" ? "Total" : "Time" })
2535
+ ] }),
2536
+ tab === "trades" ? /* @__PURE__ */ jsxRuntime.jsx(
2537
+ "div",
2538
+ {
2539
+ className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
2540
+ style: { scrollbarGutter: "stable" },
2541
+ children: isLoading && tradeFiltered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: Array.from({ length: effectiveLevels }).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", { children: tradeFiltered.map((trade, i) => {
2542
+ const tradeKey = getTradeKey(trade, i);
2543
+ const explorerUrl = trade.txHash && tradeExplorerUrl ? tradeExplorerUrl(trade.txHash) : trade.txHash ? `https://sepolia.etherscan.io/tx/${trade.txHash}` : void 0;
2544
+ return /* @__PURE__ */ jsxRuntime.jsx(
2545
+ TradeRow,
2546
+ {
2547
+ trade,
2548
+ tradeKey,
2549
+ precision,
2550
+ amountPrecision,
2551
+ seenTradeKeysRef,
2552
+ explorerUrl
2553
+ },
2554
+ tradeKey
2555
+ );
2556
+ }) })
2557
+ }
2558
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col min-h-0 overflow-hidden", fillHeight && "flex-1"), children: [
2559
+ /* @__PURE__ */ jsxRuntime.jsx(
2560
+ "div",
2251
2561
  {
2252
- side: "ask",
2253
- price: l.price,
2254
- amount: l.amount,
2255
- cumDepth: askCumDepths[i],
2256
- depthPct: askCumDepths[i] / askMaxCumDepth * 100,
2257
- precision,
2258
- amountPrecision,
2259
- hasUserOrder: userAskPrices.has(l.price),
2260
- onPriceClick,
2261
- flashOnMount: newAskPrices.has(l.price),
2262
- fillHeight
2263
- },
2264
- `ask-${l.price}`
2265
- ))
2266
- }
2267
- ),
2268
- /* @__PURE__ */ jsxRuntime.jsx(
2269
- "div",
2270
- {
2271
- className: "flex items-center gap-2 bg-[#0b1a24] px-3 py-2 flex-shrink-0 overflow-hidden orderbook-mid-row",
2272
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-lg font-semibold tabular-nums whitespace-nowrap orderbook-mid-price", midClass), children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 20 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2273
- "$",
2274
- formatNumber(midPrice, precision),
2275
- midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2276
- midChangePercent >= 0 ? "+" : "",
2277
- midChangePercent.toFixed(2),
2278
- "%"
2279
- ] })
2280
- ] }) })
2281
- }
2282
- ),
2283
- /* @__PURE__ */ jsxRuntime.jsx(
2284
- "div",
2285
- {
2286
- className: cn("flex flex-col overflow-hidden", !fillHeight && "flex-shrink-0"),
2287
- style: fillHeight ? { flex: 1, minHeight: 0 } : { height: `${sectionHeight}px` },
2288
- children: isLoading ? Array.from({ length: effectiveLevels }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `bid-skel-${i}`)) : bidVisibleLevels.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center px-3 text-xs text-white/40", children: "No bids" }) : bidVisibleLevels.map((l, i) => /* @__PURE__ */ jsxRuntime.jsx(
2289
- DepthRow,
2562
+ ref: asksSectionRef,
2563
+ className: cn("flex flex-col justify-end overflow-hidden", !fillHeight && "flex-shrink-0"),
2564
+ style: fillHeight ? { flex: 1, minHeight: 0 } : { height: `${sectionHeight}px` },
2565
+ children: isLoading ? Array.from({ length: effectiveLevels }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `ask-skel-${i}`)) : askVisibleLevels.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center px-3 text-xs text-white/40", children: "No asks" }) : askVisibleLevels.map((l, i) => /* @__PURE__ */ jsxRuntime.jsx(
2566
+ DepthRow,
2567
+ {
2568
+ side: "ask",
2569
+ price: l.price,
2570
+ amount: l.amount,
2571
+ cumDepth: askCumDepths[i],
2572
+ depthPct: askCumDepths[i] / askMaxCumDepth * 100,
2573
+ precision,
2574
+ amountPrecision,
2575
+ hasUserOrder: userAskPrices.has(l.price),
2576
+ onPriceClick,
2577
+ flashOnMount: newAskPrices.has(l.price),
2578
+ fillHeight
2579
+ },
2580
+ `ask-${l.price}`
2581
+ ))
2582
+ }
2583
+ ),
2584
+ /* @__PURE__ */ jsxRuntime.jsxs(
2585
+ "div",
2290
2586
  {
2291
- side: "bid",
2292
- price: l.price,
2293
- amount: l.amount,
2294
- cumDepth: bidCumDepths[i],
2295
- depthPct: bidCumDepths[i] / bidMaxCumDepth * 100,
2296
- precision,
2297
- amountPrecision,
2298
- hasUserOrder: userBidPrices.has(l.price),
2299
- onPriceClick,
2300
- flashOnMount: newBidPrices.has(l.price),
2301
- fillHeight
2302
- },
2303
- `bid-${l.price}`
2304
- ))
2305
- }
2306
- )
2307
- ] })
2308
- ] })
2587
+ className: "flex items-center justify-between gap-2 px-3 py-2 flex-shrink-0 overflow-hidden orderbook-mid-row",
2588
+ style: { ...MID_ROW_GOLD_STYLE, alignItems: "baseline" },
2589
+ children: [
2590
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-lg font-semibold tabular-nums whitespace-nowrap orderbook-mid-price", midClass), children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { width: 110, height: 20 }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2591
+ "$",
2592
+ formatNumber(midPrice, precision),
2593
+ midChangePercent == null ? null : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
2594
+ midChangePercent >= 0 ? "+" : "",
2595
+ midChangePercent.toFixed(2),
2596
+ "%"
2597
+ ] })
2598
+ ] }) }),
2599
+ !isLoading && /* @__PURE__ */ jsxRuntime.jsx(SpreadReadout, { spread, spreadPct, precision })
2600
+ ]
2601
+ }
2602
+ ),
2603
+ /* @__PURE__ */ jsxRuntime.jsx(
2604
+ "div",
2605
+ {
2606
+ className: cn("flex flex-col overflow-hidden", !fillHeight && "flex-shrink-0"),
2607
+ style: fillHeight ? { flex: 1, minHeight: 0 } : { height: `${sectionHeight}px` },
2608
+ children: isLoading ? Array.from({ length: effectiveLevels }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonRow, {}, `bid-skel-${i}`)) : bidVisibleLevels.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center px-3 text-xs text-white/40", children: "No bids" }) : bidVisibleLevels.map((l, i) => /* @__PURE__ */ jsxRuntime.jsx(
2609
+ DepthRow,
2610
+ {
2611
+ side: "bid",
2612
+ price: l.price,
2613
+ amount: l.amount,
2614
+ cumDepth: bidCumDepths[i],
2615
+ depthPct: bidCumDepths[i] / bidMaxCumDepth * 100,
2616
+ precision,
2617
+ amountPrecision,
2618
+ hasUserOrder: userBidPrices.has(l.price),
2619
+ onPriceClick,
2620
+ flashOnMount: newBidPrices.has(l.price),
2621
+ fillHeight
2622
+ },
2623
+ `bid-${l.price}`
2624
+ ))
2625
+ }
2626
+ )
2627
+ ] })
2628
+ ]
2629
+ }
2630
+ )
2309
2631
  ] });
2310
2632
  }
2311
2633
  function MobileOrderbookLayout({
@@ -2432,8 +2754,7 @@ function MobileOrderbookLayout({
2432
2754
  gridTemplateColumns: "1.2fr 0.8fr",
2433
2755
  padding: "0.3rem 0",
2434
2756
  fontSize: "0.8rem",
2435
- borderTop: "1px solid rgba(255,255,255,0.1)",
2436
- borderBottom: "1px solid rgba(255,255,255,0.1)"
2757
+ ...MID_ROW_GOLD_STYLE
2437
2758
  },
2438
2759
  children: [
2439
2760
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2515,7 +2836,7 @@ function MobileDepthRow({
2515
2836
  flashOnMount
2516
2837
  }) {
2517
2838
  const isAsk = side === "ask";
2518
- const rowRef = React5__namespace.useRef(null);
2839
+ const rowRef = React9__namespace.useRef(null);
2519
2840
  useAmountChangeFlash(rowRef, amount, side, flashOnMount);
2520
2841
  return /* @__PURE__ */ jsxRuntime.jsxs(
2521
2842
  "div",
@@ -2541,16 +2862,12 @@ function MobileDepthRow({
2541
2862
  left: "2px",
2542
2863
  top: "50%",
2543
2864
  transform: "translateY(-50%)",
2544
- width: "6px",
2545
- height: "6px",
2546
- borderRadius: "50%",
2547
- backgroundColor: "#C9A227",
2548
- boxShadow: "0 0 6px rgba(201,162,39,0.7)",
2549
2865
  zIndex: 2
2550
- }
2866
+ },
2867
+ children: /* @__PURE__ */ jsxRuntime.jsx(BreadSliceGlyph, {})
2551
2868
  }
2552
2869
  ) : null,
2553
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1, color: isAsk ? "#f6465d" : "#0ecb81", paddingLeft: hasUserOrder ? "10px" : void 0 }, children: [
2870
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1, color: isAsk ? "#f6465d" : "#0ecb81", paddingLeft: hasUserOrder ? "14px" : void 0 }, children: [
2554
2871
  "$",
2555
2872
  formatNumber(price, precision)
2556
2873
  ] }),
@@ -2560,12 +2877,12 @@ function MobileDepthRow({
2560
2877
  {
2561
2878
  style: {
2562
2879
  position: "absolute",
2563
- top: 0,
2880
+ top: 1,
2564
2881
  left: 0,
2565
- bottom: 0,
2882
+ bottom: 1,
2566
2883
  width: `${clamp3(depthPct, 0, 100)}%`,
2567
- backgroundColor: isAsk ? "#f6465d" : "#0ecb81",
2568
- opacity: 0.1,
2884
+ backgroundImage: isAsk ? "linear-gradient(90deg, rgba(246,70,93,0.11), rgba(246,70,93,0.15))" : "linear-gradient(90deg, rgba(14,203,129,0.09), rgba(14,203,129,0.13))",
2885
+ borderRadius: "0 4px 4px 0",
2569
2886
  zIndex: 0,
2570
2887
  transition: "width 300ms ease-out"
2571
2888
  }
@@ -2578,20 +2895,20 @@ function MobileDepthRow({
2578
2895
  var isHlsManifest = (url) => /\.m3u8(\?|$)/i.test(url);
2579
2896
  var HLS_MIME = "application/vnd.apple.mpegurl";
2580
2897
  var MANIFEST_FAILURES = /* @__PURE__ */ new Set(["manifestLoadError", "manifestLoadTimeOut", "manifestParsingError"]);
2581
- var HlsVideo = React5__namespace.forwardRef(
2898
+ var HlsVideo = React9__namespace.forwardRef(
2582
2899
  ({ src, capLevelToPlayerSize = true, onError, ...videoProps }, ref) => {
2583
- const videoRef = React5__namespace.useRef(null);
2584
- React5__namespace.useImperativeHandle(ref, () => videoRef.current, []);
2900
+ const videoRef = React9__namespace.useRef(null);
2901
+ React9__namespace.useImperativeHandle(ref, () => videoRef.current, []);
2585
2902
  const primary = typeof src === "string" ? src : src.src;
2586
2903
  const fallbackSrc = typeof src === "string" ? void 0 : src.fallbackSrc;
2587
- const [failedSrc, setFailedSrc] = React5__namespace.useState(null);
2904
+ const [failedSrc, setFailedSrc] = React9__namespace.useState(null);
2588
2905
  const usingFallback = fallbackSrc != null && failedSrc === primary;
2589
2906
  const activeSrc = usingFallback ? fallbackSrc : primary;
2590
- const failPrimary = React5__namespace.useCallback(() => {
2907
+ const failPrimary = React9__namespace.useCallback(() => {
2591
2908
  if (fallbackSrc == null) return;
2592
2909
  setFailedSrc(primary);
2593
2910
  }, [fallbackSrc, primary]);
2594
- React5__namespace.useEffect(() => {
2911
+ React9__namespace.useEffect(() => {
2595
2912
  const video = videoRef.current;
2596
2913
  if (!video || !activeSrc) return;
2597
2914
  if (!isHlsManifest(activeSrc) || video.canPlayType(HLS_MIME)) {
@@ -2624,7 +2941,7 @@ var HlsVideo = React5__namespace.forwardRef(
2624
2941
  hls?.destroy();
2625
2942
  };
2626
2943
  }, [activeSrc, capLevelToPlayerSize, failPrimary]);
2627
- const handleError = React5__namespace.useCallback(
2944
+ const handleError = React9__namespace.useCallback(
2628
2945
  (e) => {
2629
2946
  if (!usingFallback) failPrimary();
2630
2947
  onError?.(e);
@@ -2635,7 +2952,7 @@ var HlsVideo = React5__namespace.forwardRef(
2635
2952
  }
2636
2953
  );
2637
2954
  HlsVideo.displayName = "HlsVideo";
2638
- var PropertyTour = React5__namespace.forwardRef(
2955
+ var PropertyTour = React9__namespace.forwardRef(
2639
2956
  ({
2640
2957
  className,
2641
2958
  title,
@@ -2648,8 +2965,8 @@ var PropertyTour = React5__namespace.forwardRef(
2648
2965
  playsInline = true,
2649
2966
  ...props
2650
2967
  }, ref) => {
2651
- const videoRef = React5__namespace.useRef(null);
2652
- React5__namespace.useEffect(() => {
2968
+ const videoRef = React9__namespace.useRef(null);
2969
+ React9__namespace.useEffect(() => {
2653
2970
  const video = videoRef.current;
2654
2971
  if (!video) return;
2655
2972
  const handleFullscreenChange = () => {
@@ -2757,8 +3074,50 @@ function isSafeUrl(url) {
2757
3074
  return false;
2758
3075
  }
2759
3076
  }
3077
+ var BREAKING_WINDOW_HOURS = 6;
3078
+ var MAX_PINNED_BREAKING = 2;
3079
+ var BREAKING_IMPACT_FLOOR = 8;
3080
+ var breakingImpact = (it) => typeof it.impactScore === "number" && Number.isFinite(it.impactScore) ? it.impactScore : BREAKING_IMPACT_FLOOR;
3081
+ var dismissedBreakingKeys = /* @__PURE__ */ new Set();
3082
+ var __resetDismissedBreaking = () => dismissedBreakingKeys.clear();
3083
+ var breakingKey = (it) => String(it.id ?? it.title);
3084
+ var BREAKING_SWIPE_MIN_PX = 80;
2760
3085
  var ITEMS_PER_PAGE = 5;
2761
3086
  var ITEMS_PER_PAGE_MOBILE = 5;
3087
+ function formatAge(publishedAt, now) {
3088
+ const elapsed = Math.max(0, now - new Date(publishedAt).getTime());
3089
+ const secs = Math.floor(elapsed / 1e3);
3090
+ if (secs < 60) return `${secs}s ago`;
3091
+ const mins = Math.floor(secs / 60);
3092
+ if (mins < 60) return `${mins}m ago`;
3093
+ return `${Math.floor(mins / 60)}h ago`;
3094
+ }
3095
+ function rowAgeLabel(publishedAt, now) {
3096
+ if (!publishedAt) return null;
3097
+ const t = new Date(publishedAt).getTime();
3098
+ if (!Number.isFinite(t)) return null;
3099
+ const ageMs = Math.max(0, now - t);
3100
+ if (ageMs >= 24 * 36e5) return null;
3101
+ return { label: formatAge(publishedAt, now), fresh: ageMs < 36e5 };
3102
+ }
3103
+ function useTickingNow(active, youngestPublishedAt) {
3104
+ const [now, setNow] = React9__namespace.useState(() => Date.now());
3105
+ React9__namespace.useEffect(() => {
3106
+ if (!active || !youngestPublishedAt) return;
3107
+ let timer;
3108
+ const schedule = () => {
3109
+ const ageSecs = (Date.now() - new Date(youngestPublishedAt).getTime()) / 1e3;
3110
+ const delay = ageSecs < 60 ? 1e3 : ageSecs < 3600 ? 15e3 : 6e4;
3111
+ timer = setTimeout(() => {
3112
+ setNow(Date.now());
3113
+ schedule();
3114
+ }, delay);
3115
+ };
3116
+ schedule();
3117
+ return () => clearTimeout(timer);
3118
+ }, [active, youngestPublishedAt]);
3119
+ return now;
3120
+ }
2762
3121
  var ensureAnimationsInjected = () => {
2763
3122
  if (typeof document === "undefined") return;
2764
3123
  if (document.getElementById("property-news-updates-animations")) return;
@@ -2781,6 +3140,110 @@ var ensureAnimationsInjected = () => {
2781
3140
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
2782
3141
  to { opacity: 1; transform: translateY(0) scale(1); }
2783
3142
  }
3143
+ /* The list scrolls but never shows a scrollbar (user call 2026-08-22: the
3144
+ grey track crowded the rows). Same treatment as the rest of the app. */
3145
+ .news-list-scroll { scrollbar-width: none; -ms-overflow-style: none; }
3146
+ .news-list-scroll::-webkit-scrollbar { display: none; width: 0; height: 0; }
3147
+ .property-news-breaking-dismiss {
3148
+ opacity: 0;
3149
+ pointer-events: none;
3150
+ transform: translateY(3px);
3151
+ transition: opacity 0.16s ease, transform 0.2s cubic-bezier(0.22, 1, 0.36, 1), color 0.15s ease;
3152
+ }
3153
+ .property-news-breaking-item:hover .property-news-breaking-dismiss,
3154
+ .property-news-breaking-item:focus-within .property-news-breaking-dismiss {
3155
+ opacity: 1;
3156
+ pointer-events: auto;
3157
+ transform: translateY(0);
3158
+ }
3159
+ .property-news-breaking-dismiss:hover,
3160
+ .property-news-breaking-dismiss:focus-visible {
3161
+ color: #fff !important;
3162
+ text-decoration: underline;
3163
+ text-underline-offset: 2px;
3164
+ outline: none;
3165
+ }
3166
+ .property-news-breaking-item[data-dismissing="true"] {
3167
+ pointer-events: none;
3168
+ animation: propertyNewsBreakingDismiss 0.22s cubic-bezier(0.4, 0, 1, 1) forwards;
3169
+ }
3170
+ .property-news-breaking-item[data-new-breaking="true"] {
3171
+ position: relative;
3172
+ overflow: hidden;
3173
+ animation: propertyNewsBreakingArrive 1.18s cubic-bezier(0.16, 1, 0.3, 1) both;
3174
+ }
3175
+ .property-news-breaking-item[data-new-breaking="true"]::after {
3176
+ content: "";
3177
+ position: absolute;
3178
+ inset: 0;
3179
+ z-index: 0;
3180
+ pointer-events: none;
3181
+ background: linear-gradient(100deg, transparent 8%, rgba(var(--color-accent-rgb, 230, 200, 126), 0.42) 48%, transparent 82%);
3182
+ transform: translateX(-120%);
3183
+ animation: propertyNewsBreakingSheen 1.18s 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
3184
+ }
3185
+ .property-news-breaking-item[data-new-breaking="true"] > span {
3186
+ position: relative;
3187
+ z-index: 1;
3188
+ }
3189
+ .property-news-breaking-item[data-new-breaking="true"][data-dismissing="true"] {
3190
+ animation: propertyNewsBreakingDismiss 0.22s cubic-bezier(0.4, 0, 1, 1) forwards;
3191
+ }
3192
+ @keyframes propertyNewsBreakingArrive {
3193
+ 0% { opacity: 0; transform: translateY(-14px) scale(0.985); box-shadow: 0 0 0 rgba(var(--color-accent-rgb, 230, 200, 126), 0); filter: brightness(1); }
3194
+ 24% { opacity: 1; transform: translateY(0) scale(1); box-shadow: 0 0 26px rgba(var(--color-accent-rgb, 230, 200, 126), 0.38); filter: brightness(1.16); }
3195
+ 58% { box-shadow: 0 0 16px rgba(var(--color-accent-rgb, 230, 200, 126), 0.22); filter: brightness(1.06); }
3196
+ 100% { opacity: 1; transform: translateY(0) scale(1); box-shadow: 0 0 0 rgba(var(--color-accent-rgb, 230, 200, 126), 0); }
3197
+ }
3198
+ @keyframes propertyNewsBreakingSheen {
3199
+ from { transform: translateX(-120%); }
3200
+ to { transform: translateX(120%); }
3201
+ }
3202
+ @keyframes propertyNewsBreakingDismiss {
3203
+ from { opacity: 1; transform: translateX(0); max-height: 96px; }
3204
+ to { opacity: 0; transform: translateX(24px); max-height: 0; padding-top: 0; padding-bottom: 0; }
3205
+ }
3206
+ @media (prefers-reduced-motion: reduce) {
3207
+ .property-news-breaking-dismiss { transition: none; }
3208
+ .property-news-breaking-item[data-new-breaking="true"],
3209
+ .property-news-breaking-item[data-new-breaking="true"]::after { animation-duration: 1ms; animation-delay: 0ms; }
3210
+ .property-news-breaking-item[data-dismissing="true"] { animation-duration: 1ms; }
3211
+ }
3212
+ /* Asset badge: the wrapper hosts the INSTANT CSS tooltip (native title is
3213
+ too slow) and the hover affordance that says "the icon itself is the
3214
+ target" \u2014 the box scales up with a gold ring while the tooltip shows
3215
+ "Name (TICKER)" immediately. */
3216
+ .news-badge-wrap { position: relative; display: inline-flex; flex-shrink: 0; }
3217
+ .news-badge-wrap > .news-badge-box { transition: transform 0.15s ease, box-shadow 0.15s ease; }
3218
+ .news-badge-wrap:hover > .news-badge-box {
3219
+ transform: scale(1.08);
3220
+ box-shadow: 0 0 0 1px rgba(var(--color-accent-rgb, 230, 200, 126), 0.7);
3221
+ }
3222
+ /* Instant element tooltip (an ::after can't carry a coloured % change).
3223
+ PORTALED to document.body with position:fixed \u2014 as an absolute child it
3224
+ was clipped by the scrolling news list at the top/right edges. Anchored
3225
+ above the badge by default (translateY(-100%)), flipped below via
3226
+ data-tip-below when the badge sits too close to the viewport top. */
3227
+ .news-badge-tipbox {
3228
+ position: fixed;
3229
+ display: flex;
3230
+ transform: translate(-50%, -100%);
3231
+ flex-direction: column;
3232
+ align-items: center;
3233
+ gap: 2px;
3234
+ background: #1a1d24;
3235
+ color: #fff;
3236
+ font-size: 0.62rem;
3237
+ font-weight: 600;
3238
+ line-height: 1.2;
3239
+ padding: 0.32rem 0.55rem;
3240
+ border-radius: 5px;
3241
+ border: 1px solid rgba(255, 255, 255, 0.12);
3242
+ white-space: nowrap;
3243
+ z-index: 10060;
3244
+ pointer-events: none;
3245
+ }
3246
+ .news-badge-tipbox[data-tip-below="true"] { transform: translate(-50%, 0); }
2784
3247
  `;
2785
3248
  document.head.appendChild(style);
2786
3249
  };
@@ -2817,7 +3280,8 @@ var formatDateShort = (value) => {
2817
3280
  if (diffS < 3600) return `${Math.floor(diffS / 60)}m ago`;
2818
3281
  if (diffS < 86400) return `${Math.floor(diffS / 3600)}h ago`;
2819
3282
  const time = d.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit", hour12: true });
2820
- return `${time} \xB7 ${d.toLocaleDateString(void 0, { month: "short", day: "numeric" })}`;
3283
+ const date = d.toLocaleDateString(void 0, { month: "short", day: "numeric" });
3284
+ return `${date} \xB7 ${time}`;
2821
3285
  };
2822
3286
  var formatTimeAgo = (timestamp) => {
2823
3287
  const diff = (Date.now() - new Date(timestamp).getTime()) / 1e3;
@@ -2831,10 +3295,66 @@ function getSentimentInfo(score) {
2831
3295
  if (score < -0.15) return { arrow: "\u25BC", label: "Bearish", color: "#f6465d" };
2832
3296
  return { arrow: "", label: "Neutral", color: "#848e9c" };
2833
3297
  }
3298
+ function SentimentBar({ score, color }) {
3299
+ const clamped = Math.max(-1, Math.min(1, score));
3300
+ const widthPct = Math.abs(clamped) * 50;
3301
+ const direction = clamped > 0 ? "positive" : clamped < 0 ? "negative" : "neutral";
3302
+ const word = clamped > 0.15 ? "bullish" : clamped < -0.15 ? "bearish" : "neutral";
3303
+ const signed = `${clamped >= 0 ? "+" : "\u2212"}${Math.abs(clamped).toFixed(2)}`;
3304
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3305
+ "span",
3306
+ {
3307
+ "data-testid": "sentiment-bar",
3308
+ "data-score": String(score),
3309
+ role: "img",
3310
+ "aria-label": `Sentiment: ${word}, ${signed} of +1`,
3311
+ style: {
3312
+ position: "relative",
3313
+ display: "inline-block",
3314
+ width: "36px",
3315
+ height: "3px",
3316
+ borderRadius: "2px",
3317
+ background: "rgba(255,255,255,0.10)",
3318
+ flexShrink: 0
3319
+ },
3320
+ children: [
3321
+ /* @__PURE__ */ jsxRuntime.jsx(
3322
+ "span",
3323
+ {
3324
+ style: {
3325
+ position: "absolute",
3326
+ left: "50%",
3327
+ top: "-1px",
3328
+ width: "1px",
3329
+ height: "5px",
3330
+ background: "rgba(255,255,255,0.28)"
3331
+ }
3332
+ }
3333
+ ),
3334
+ /* @__PURE__ */ jsxRuntime.jsx(
3335
+ "span",
3336
+ {
3337
+ "data-testid": "sentiment-fill",
3338
+ "data-direction": direction,
3339
+ style: {
3340
+ position: "absolute",
3341
+ top: 0,
3342
+ height: "100%",
3343
+ borderRadius: "2px",
3344
+ background: color,
3345
+ width: `${widthPct}%`,
3346
+ left: `${clamped >= 0 ? 50 : 50 - widthPct}%`
3347
+ }
3348
+ }
3349
+ )
3350
+ ]
3351
+ }
3352
+ );
3353
+ }
2834
3354
  function NewsArticleModal({ item, onClose }) {
2835
3355
  const sentimentInfo = getSentimentInfo(item.sentimentScore);
2836
3356
  const catStyle = categoryStyles[item.type] ?? categoryStyles.market;
2837
- React5__namespace.useEffect(() => {
3357
+ React9__namespace.useEffect(() => {
2838
3358
  const handler = (e) => {
2839
3359
  if (e.key === "Escape") onClose();
2840
3360
  };
@@ -2895,7 +3415,7 @@ function NewsArticleModal({ item, onClose }) {
2895
3415
  children: /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) })
2896
3416
  }
2897
3417
  ) }),
2898
- sentimentInfo && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "0.6rem" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
3418
+ sentimentInfo && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginBottom: "0.6rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
2899
3419
  "span",
2900
3420
  {
2901
3421
  style: {
@@ -2910,10 +3430,11 @@ function NewsArticleModal({ item, onClose }) {
2910
3430
  background: `${sentimentInfo.color}1a`,
2911
3431
  border: `1px solid ${sentimentInfo.color}40`
2912
3432
  },
2913
- children: [
3433
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: "0.3rem" }, children: [
2914
3434
  sentimentInfo.arrow ? `${sentimentInfo.arrow} ` : "",
2915
- sentimentInfo.label
2916
- ]
3435
+ sentimentInfo.label,
3436
+ item.sentimentScore != null && /* @__PURE__ */ jsxRuntime.jsx(SentimentBar, { score: item.sentimentScore, color: sentimentInfo.color })
3437
+ ] })
2917
3438
  }
2918
3439
  ) }),
2919
3440
  /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { fontSize: "1rem", fontWeight: 600, color: "#fff", lineHeight: 1.5, margin: "0 0 1rem" }, children: item.title }),
@@ -2928,7 +3449,13 @@ function NewsArticleModal({ item, onClose }) {
2928
3449
  fontSize: "0.65rem",
2929
3450
  fontWeight: 500,
2930
3451
  background: "rgba(255,255,255,0.07)",
2931
- color: "#848e9c"
3452
+ color: "#848e9c",
3453
+ // Truncation guard moved here with the source itself — a long
3454
+ // publication name would otherwise stretch the meta row.
3455
+ maxWidth: "120px",
3456
+ overflow: "hidden",
3457
+ textOverflow: "ellipsis",
3458
+ whiteSpace: "nowrap"
2932
3459
  },
2933
3460
  children: item.source
2934
3461
  }
@@ -2990,7 +3517,7 @@ function NewsArticleModal({ item, onClose }) {
2990
3517
  }
2991
3518
  return modal;
2992
3519
  }
2993
- var PropertyNewsUpdates = React5__namespace.forwardRef(
3520
+ var PropertyNewsUpdates = React9__namespace.forwardRef(
2994
3521
  ({
2995
3522
  className,
2996
3523
  heading,
@@ -3004,49 +3531,120 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3004
3531
  viewAllLabel = "View All News",
3005
3532
  connectionStatus = "live",
3006
3533
  disablePagination = false,
3534
+ hideHeading = false,
3535
+ hideCategoryTabs = false,
3536
+ category,
3537
+ onCategoryChange,
3538
+ pinBreaking = false,
3539
+ onAssetOpen,
3540
+ showAssetBadges = true,
3007
3541
  ...props
3008
3542
  }, ref) => {
3009
3543
  const isPurchaseVariant = variant === "purchases";
3010
3544
  const isHomeVariant = variant === "home";
3011
3545
  const resolvedHeading = heading ?? (isPurchaseVariant ? "Live Purchases" : "Property News & Headlines");
3012
- const [homeTab, setHomeTab] = React5__namespace.useState("all");
3013
- const [homePage, setHomePage] = React5__namespace.useState(0);
3546
+ const headerTrailing = Boolean(isHomeVariant ? viewAllHref : !isPurchaseVariant);
3547
+ const [homeTabInternal, setHomeTabInternal] = React9__namespace.useState("all");
3548
+ const homeTab = category ?? homeTabInternal;
3549
+ const setHomeTab = React9__namespace.useCallback(
3550
+ (next) => {
3551
+ setHomeTabInternal(next);
3552
+ onCategoryChange?.(next);
3553
+ },
3554
+ [onCategoryChange]
3555
+ );
3556
+ const [homePage, setHomePage] = React9__namespace.useState(0);
3014
3557
  const purchaseItems = purchasesProp ?? [];
3015
- const [page, setPage] = React5__namespace.useState(0);
3016
- const [selectedItem, setSelectedItem] = React5__namespace.useState(null);
3017
- const [isMobile, setIsMobile] = React5__namespace.useState(
3558
+ const [page, setPage] = React9__namespace.useState(0);
3559
+ const [selectedItem, setSelectedItem] = React9__namespace.useState(null);
3560
+ const [isMobile, setIsMobile] = React9__namespace.useState(
3018
3561
  () => typeof window !== "undefined" && window.innerWidth <= 768
3019
3562
  );
3020
- React5__namespace.useEffect(() => {
3563
+ React9__namespace.useEffect(() => {
3021
3564
  const check = () => setIsMobile(window.innerWidth <= 768);
3022
3565
  window.addEventListener("resize", check);
3023
3566
  return () => window.removeEventListener("resize", check);
3024
3567
  }, []);
3025
3568
  const homePageSize = isMobile ? ITEMS_PER_PAGE_MOBILE : ITEMS_PER_PAGE;
3026
- React5__namespace.useEffect(() => {
3569
+ React9__namespace.useEffect(() => {
3027
3570
  ensureAnimationsInjected();
3028
3571
  }, []);
3029
- React5__namespace.useEffect(() => {
3572
+ React9__namespace.useEffect(() => {
3030
3573
  setHomePage(0);
3031
3574
  }, [homeTab]);
3032
- const hasItems = Array.isArray(items) && items.length > 0;
3033
- const totalPages = React5__namespace.useMemo(
3034
- () => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1,
3035
- [hasItems, items.length]
3575
+ const breakingCandidates = React9__namespace.useMemo(() => {
3576
+ if (!pinBreaking || !Array.isArray(items)) return [];
3577
+ return items.filter((it) => it.breaking && it.publishedAt && Number.isFinite(new Date(it.publishedAt).getTime())).sort((a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime());
3578
+ }, [pinBreaking, items]);
3579
+ const breakingNow = useTickingNow(
3580
+ breakingCandidates.length > 0,
3581
+ breakingCandidates[0]?.publishedAt ?? null
3582
+ );
3583
+ const breakingEligible = React9__namespace.useMemo(() => {
3584
+ const cutoff = breakingNow - BREAKING_WINDOW_HOURS * 36e5;
3585
+ return breakingCandidates.filter((it) => {
3586
+ if (new Date(it.publishedAt).getTime() < cutoff) return false;
3587
+ return homeTab === "all" || it.type === homeTab;
3588
+ });
3589
+ }, [breakingCandidates, breakingNow, homeTab]);
3590
+ const [dismissedVersion, setDismissedVersion] = React9__namespace.useState(0);
3591
+ const [dismissingBreakingKey, setDismissingBreakingKey] = React9__namespace.useState(null);
3592
+ const [breakingSwipe, setBreakingSwipe] = React9__namespace.useState(null);
3593
+ const breakingSwipeStartXRef = React9__namespace.useRef(0);
3594
+ const suppressBreakingClickRef = React9__namespace.useRef(false);
3595
+ const breakingSwipeActiveKeyRef = React9__namespace.useRef(null);
3596
+ const breakingSwipeMaxRef = React9__namespace.useRef(0);
3597
+ const [badgeTip, setBadgeTip] = React9__namespace.useState(null);
3598
+ const BADGE_TIP_GAP = 7;
3599
+ const BADGE_TIP_FLIP_PX = 56;
3600
+ const showBadgeTip = (el, asset) => {
3601
+ const rect = el.getBoundingClientRect();
3602
+ const below = rect.top < BADGE_TIP_FLIP_PX;
3603
+ setBadgeTip({
3604
+ asset,
3605
+ left: rect.left + rect.width / 2,
3606
+ top: below ? rect.bottom + BADGE_TIP_GAP : rect.top - BADGE_TIP_GAP,
3607
+ below
3608
+ });
3609
+ };
3610
+ const pinnedBreaking = React9__namespace.useMemo(() => {
3611
+ return breakingEligible.filter((it) => !dismissedBreakingKeys.has(breakingKey(it))).sort((a, b) => breakingImpact(b) - breakingImpact(a)).slice(0, MAX_PINNED_BREAKING);
3612
+ }, [breakingEligible, dismissedVersion]);
3613
+ const breakingRowKeys = React9__namespace.useMemo(
3614
+ () => new Set(breakingEligible.map(breakingKey)),
3615
+ [breakingEligible]
3036
3616
  );
3037
- React5__namespace.useEffect(() => {
3617
+ const listItems = React9__namespace.useMemo(() => {
3618
+ if (pinnedBreaking.length === 0) return items;
3619
+ const pinned = new Set(pinnedBreaking);
3620
+ return items.filter((it) => !pinned.has(it));
3621
+ }, [items, pinnedBreaking]);
3622
+ const hasItems = Array.isArray(listItems) && listItems.length > 0;
3623
+ const totalPages = React9__namespace.useMemo(
3624
+ () => hasItems ? Math.max(1, Math.ceil(listItems.length / ITEMS_PER_PAGE)) : 1,
3625
+ [hasItems, listItems.length]
3626
+ );
3627
+ React9__namespace.useEffect(() => {
3038
3628
  setPage((prev) => Math.min(prev, totalPages - 1));
3039
3629
  }, [totalPages]);
3040
- const paginatedItems = hasItems ? items.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
3041
- const homeFilteredItems = React5__namespace.useMemo(
3042
- () => hasItems ? items.filter((it) => homeTab === "all" || it.type === homeTab) : [],
3043
- [hasItems, items, homeTab]
3630
+ const paginatedItems = hasItems ? listItems.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
3631
+ const homeFilteredItems = React9__namespace.useMemo(
3632
+ () => hasItems ? listItems.filter((it) => homeTab === "all" || it.type === homeTab) : [],
3633
+ [hasItems, listItems, homeTab]
3044
3634
  );
3045
- const homeTotalPages = React5__namespace.useMemo(
3635
+ const homeTotalPages = React9__namespace.useMemo(
3046
3636
  () => Math.max(1, Math.ceil(homeFilteredItems.length / homePageSize)),
3047
3637
  [homeFilteredItems.length, homePageSize]
3048
3638
  );
3049
3639
  const homePaginatedItems = disablePagination ? homeFilteredItems : homeFilteredItems.slice(homePage * homePageSize, (homePage + 1) * homePageSize);
3640
+ const youngestRowPublishedAt = React9__namespace.useMemo(() => {
3641
+ let youngest = null;
3642
+ for (const it of homePaginatedItems) {
3643
+ if (it.publishedAt && (!youngest || it.publishedAt > youngest)) youngest = it.publishedAt;
3644
+ }
3645
+ return youngest;
3646
+ }, [homePaginatedItems]);
3647
+ const rowNow = useTickingNow(isHomeVariant && youngestRowPublishedAt != null, youngestRowPublishedAt);
3050
3648
  return /* @__PURE__ */ jsxRuntime.jsxs(
3051
3649
  "div",
3052
3650
  {
@@ -3057,8 +3655,8 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3057
3655
  ),
3058
3656
  ...props,
3059
3657
  children: [
3060
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", style: isHomeVariant ? { marginBottom: "0.5rem", minHeight: isMobile ? "32px" : "24px", gap: isMobile ? "0.5rem" : "1rem" } : void 0, children: [
3061
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
3658
+ (!hideHeading || headerTrailing) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", style: isHomeVariant ? { marginBottom: "0.5rem", minHeight: isMobile ? "32px" : "24px", gap: isMobile ? "0.5rem" : "1rem", justifyContent: hideHeading ? "flex-end" : void 0 } : hideHeading ? { justifyContent: "flex-end" } : void 0, children: [
3659
+ !hideHeading && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
3062
3660
  isHomeVariant && /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: isMobile ? 14 : 16, height: isMobile ? 14 : 16, viewBox: "0 0 24 24", fill: "currentColor", style: { color: "var(--color-text, #fff)", flexShrink: 0, display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-5 14H4v-4h11v4zm0-5H4V9h11v4zm5 5h-4V9h4v9z" }) }),
3063
3661
  isPurchaseVariant && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "inline-block", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#0ecb81", boxShadow: "0 0 8px rgba(14,203,129,0.8)", animation: "propertyNewsPulse 1.5s infinite" } }),
3064
3662
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -3077,7 +3675,7 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3077
3675
  "LIVE"
3078
3676
  ] }) : null
3079
3677
  ] }),
3080
- isHomeVariant && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: isMobile ? "1rem" : "1.5rem", marginTop: "0.25rem", marginBottom: "1rem", borderBottom: "1px solid rgba(255, 255, 255, 0.08)", paddingBottom: "0.5rem" }, children: ["all", "property", "market"].map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
3678
+ isHomeVariant && !hideCategoryTabs && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: isMobile ? "1rem" : "1.5rem", marginTop: "0.25rem", marginBottom: "1rem", borderBottom: "1px solid rgba(255, 255, 255, 0.08)", paddingBottom: "0.5rem" }, children: ["all", "property", "market"].map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
3081
3679
  "button",
3082
3680
  {
3083
3681
  type: "button",
@@ -3098,10 +3696,229 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3098
3696
  },
3099
3697
  tab
3100
3698
  )) }),
3699
+ pinnedBreaking.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
3700
+ "div",
3701
+ {
3702
+ "data-testid": "news-breaking",
3703
+ style: {
3704
+ display: "flex",
3705
+ flexDirection: "column",
3706
+ marginBottom: "0.5rem",
3707
+ // Clips the row while it's being swiped out to the right. The gold
3708
+ // band styling lives on each ITEM below, not here — the whole band
3709
+ // (rule, wash, hairlines) must travel with a swipe, not just the
3710
+ // text inside it (user bug report, 2026-08-20).
3711
+ overflow: "hidden"
3712
+ },
3713
+ children: pinnedBreaking.map((item, i) => {
3714
+ const sentiment = getSentimentInfo(item.sentimentScore);
3715
+ const k = breakingKey(item);
3716
+ const dx = breakingSwipe?.key === k ? breakingSwipe.dx : 0;
3717
+ const finishDismiss = () => {
3718
+ dismissedBreakingKeys.add(k);
3719
+ setDismissingBreakingKey(null);
3720
+ setDismissedVersion((v) => v + 1);
3721
+ };
3722
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3723
+ "button",
3724
+ {
3725
+ type: "button",
3726
+ className: "property-news-breaking-item",
3727
+ "data-new-breaking": item.isNew ? "true" : void 0,
3728
+ "data-dismissing": dismissingBreakingKey === k ? "true" : void 0,
3729
+ "data-testid": "news-breaking-item",
3730
+ onAnimationEnd: (e) => {
3731
+ if (e.animationName === "propertyNewsBreakingDismiss" && dismissingBreakingKey === k) {
3732
+ finishDismiss();
3733
+ }
3734
+ },
3735
+ onClick: () => {
3736
+ if (suppressBreakingClickRef.current) {
3737
+ suppressBreakingClickRef.current = false;
3738
+ return;
3739
+ }
3740
+ setSelectedItem(item);
3741
+ },
3742
+ onPointerDown: (e) => {
3743
+ breakingSwipeStartXRef.current = e.clientX;
3744
+ breakingSwipeActiveKeyRef.current = k;
3745
+ breakingSwipeMaxRef.current = 0;
3746
+ setBreakingSwipe({ key: k, dx: 0 });
3747
+ try {
3748
+ e.currentTarget.setPointerCapture?.(e.pointerId);
3749
+ } catch {
3750
+ }
3751
+ },
3752
+ onPointerMove: (e) => {
3753
+ if (breakingSwipeActiveKeyRef.current !== k) return;
3754
+ const delta = e.clientX - breakingSwipeStartXRef.current;
3755
+ breakingSwipeMaxRef.current = Math.max(breakingSwipeMaxRef.current, Math.abs(delta));
3756
+ setBreakingSwipe({ key: k, dx: Math.max(0, delta) });
3757
+ },
3758
+ onPointerUp: (e) => {
3759
+ if (breakingSwipeActiveKeyRef.current !== k) return;
3760
+ breakingSwipeActiveKeyRef.current = null;
3761
+ if (breakingSwipeMaxRef.current > 6) suppressBreakingClickRef.current = true;
3762
+ setBreakingSwipe(null);
3763
+ const drag = Math.max(0, e.clientX - breakingSwipeStartXRef.current);
3764
+ const width = e.currentTarget.offsetWidth || 0;
3765
+ if (drag >= Math.max(BREAKING_SWIPE_MIN_PX, width * 0.3)) {
3766
+ dismissedBreakingKeys.add(k);
3767
+ setDismissedVersion((v) => v + 1);
3768
+ }
3769
+ },
3770
+ onPointerCancel: () => {
3771
+ breakingSwipeActiveKeyRef.current = null;
3772
+ setBreakingSwipe(null);
3773
+ },
3774
+ style: {
3775
+ display: "block",
3776
+ width: "100%",
3777
+ padding: "0.4rem 0 0.5rem 0.6rem",
3778
+ textAlign: "left",
3779
+ background: "none",
3780
+ border: "none",
3781
+ cursor: "pointer",
3782
+ minWidth: 0,
3783
+ // Highlighted on purpose (user call, 2026-08-20): BREAKING is
3784
+ // the one thing on this page allowed to shout. The gold rule,
3785
+ // hairlines and wash live HERE on the item — the whole band
3786
+ // travels when the item is swiped away.
3787
+ borderLeft: "3px solid var(--color-accent, #E6C87E)",
3788
+ borderTop: "1px solid rgba(var(--color-accent-rgb, 230, 200, 126), 0.28)",
3789
+ borderBottom: "1px solid rgba(var(--color-accent-rgb, 230, 200, 126), 0.28)",
3790
+ backgroundImage: "linear-gradient(90deg, rgba(var(--color-accent-rgb, 230, 200, 126), 0.16) 0%, rgba(var(--color-accent-rgb, 230, 200, 126), 0.06) 45%, rgba(var(--color-accent-rgb, 230, 200, 126), 0.02) 100%)",
3791
+ // Horizontal drags are ours; vertical stays with the scroll.
3792
+ touchAction: "pan-y",
3793
+ transform: dx > 0 ? `translateX(${dx}px)` : void 0,
3794
+ opacity: dx > 0 ? Math.max(0.3, 1 - dx / 320) : 1,
3795
+ transition: dx > 0 ? "none" : "transform 0.15s ease, opacity 0.15s ease"
3796
+ },
3797
+ children: [
3798
+ /* @__PURE__ */ jsxRuntime.jsx(
3799
+ "span",
3800
+ {
3801
+ "data-testid": "news-breaking-title",
3802
+ style: {
3803
+ display: "-webkit-box",
3804
+ WebkitBoxOrient: "vertical",
3805
+ WebkitLineClamp: 2,
3806
+ fontSize: "0.8rem",
3807
+ fontWeight: 600,
3808
+ color: "#fff",
3809
+ lineHeight: 1.35,
3810
+ overflow: "hidden",
3811
+ overflowWrap: "anywhere"
3812
+ },
3813
+ children: item.title
3814
+ }
3815
+ ),
3816
+ /* @__PURE__ */ jsxRuntime.jsxs(
3817
+ "span",
3818
+ {
3819
+ style: {
3820
+ display: "flex",
3821
+ alignItems: "center",
3822
+ gap: "0.45rem",
3823
+ marginTop: "0.2rem"
3824
+ },
3825
+ children: [
3826
+ (() => {
3827
+ const age = rowAgeLabel(item.publishedAt, breakingNow);
3828
+ return age ? /* @__PURE__ */ jsxRuntime.jsx(
3829
+ "span",
3830
+ {
3831
+ "data-age-fresh": age.fresh ? "true" : void 0,
3832
+ style: {
3833
+ fontSize: "0.64rem",
3834
+ fontWeight: 600,
3835
+ fontVariantNumeric: "tabular-nums",
3836
+ color: age.fresh ? "var(--color-accent, #E6C87E)" : "rgba(255,255,255,0.65)"
3837
+ },
3838
+ children: age.label
3839
+ }
3840
+ ) : null;
3841
+ })(),
3842
+ /* @__PURE__ */ jsxRuntime.jsx(
3843
+ "span",
3844
+ {
3845
+ "data-testid": "breaking-tag",
3846
+ style: {
3847
+ fontSize: "0.55rem",
3848
+ fontWeight: 700,
3849
+ letterSpacing: "0.09em",
3850
+ color: "#0a0b0e",
3851
+ background: "var(--color-accent, #E6C87E)",
3852
+ padding: "0.16rem 0.34rem 0.13rem",
3853
+ borderRadius: "3px",
3854
+ lineHeight: 1
3855
+ },
3856
+ children: "BREAKING"
3857
+ }
3858
+ ),
3859
+ sentiment ? /* @__PURE__ */ jsxRuntime.jsxs(
3860
+ "span",
3861
+ {
3862
+ style: {
3863
+ display: "inline-flex",
3864
+ alignItems: "center",
3865
+ gap: "0.3rem",
3866
+ fontSize: "0.58rem",
3867
+ fontWeight: 600,
3868
+ color: sentiment.color
3869
+ },
3870
+ children: [
3871
+ sentiment.arrow ? `${sentiment.arrow} ` : "",
3872
+ sentiment.label,
3873
+ item.sentimentScore != null && /* @__PURE__ */ jsxRuntime.jsx(SentimentBar, { score: item.sentimentScore, color: sentiment.color })
3874
+ ]
3875
+ }
3876
+ ) : null,
3877
+ /* @__PURE__ */ jsxRuntime.jsx(
3878
+ "span",
3879
+ {
3880
+ className: "property-news-breaking-dismiss",
3881
+ "data-testid": "breaking-dismiss",
3882
+ role: "button",
3883
+ tabIndex: 0,
3884
+ "aria-label": `Dismiss breaking story: ${item.title}`,
3885
+ onPointerDown: (e) => e.stopPropagation(),
3886
+ onClick: (e) => {
3887
+ e.stopPropagation();
3888
+ setDismissingBreakingKey(k);
3889
+ },
3890
+ onKeyDown: (e) => {
3891
+ if (e.key !== "Enter" && e.key !== " ") return;
3892
+ e.preventDefault();
3893
+ e.stopPropagation();
3894
+ setDismissingBreakingKey(k);
3895
+ },
3896
+ style: {
3897
+ marginLeft: "auto",
3898
+ padding: "0.2rem 0.35rem 0.2rem 0.5rem",
3899
+ fontSize: "0.58rem",
3900
+ fontWeight: 600,
3901
+ color: "rgba(255,255,255,0.58)",
3902
+ cursor: "pointer",
3903
+ whiteSpace: "nowrap"
3904
+ },
3905
+ children: "Dismiss"
3906
+ }
3907
+ )
3908
+ ]
3909
+ }
3910
+ )
3911
+ ]
3912
+ },
3913
+ item.id ?? `breaking-${i}`
3914
+ );
3915
+ })
3916
+ }
3917
+ ),
3101
3918
  /* @__PURE__ */ jsxRuntime.jsx(
3102
3919
  "div",
3103
3920
  {
3104
- className: cn("flex flex-1 flex-col overflow-y-auto overflow-x-hidden", isHomeVariant ? "gap-0" : "mt-4 gap-3"),
3921
+ className: cn("news-list-scroll flex flex-1 flex-col overflow-y-auto overflow-x-hidden", isHomeVariant ? "gap-0" : "mt-4 gap-3"),
3105
3922
  style: !isPurchaseVariant && !isHomeVariant ? { minHeight: `${ITEMS_PER_PAGE * 86}px` } : void 0,
3106
3923
  children: isPurchaseVariant ? purchaseItems.length > 0 ? purchaseItems.slice(0, 7).map((purchase, index) => {
3107
3924
  const maxAmount = 6e4;
@@ -3132,10 +3949,12 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3132
3949
  const key = item.displayId ?? item.id ?? `${item.title}-${index}`;
3133
3950
  const isProperty = item.type === "property";
3134
3951
  const sentimentInfo = getSentimentInfo(item.sentimentScore);
3952
+ const isBreakingRow = pinBreaking && Boolean(item.breaking) && breakingRowKeys.has(breakingKey(item));
3135
3953
  return /* @__PURE__ */ jsxRuntime.jsxs(
3136
3954
  "button",
3137
3955
  {
3138
3956
  type: "button",
3957
+ "data-breaking-row": isBreakingRow ? "true" : void 0,
3139
3958
  onClick: () => setSelectedItem(item),
3140
3959
  style: {
3141
3960
  width: "100%",
@@ -3151,6 +3970,10 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3151
3970
  gap: isMobile ? "0.25rem" : "0.5rem",
3152
3971
  color: "inherit",
3153
3972
  transition: "background-color 0.15s"
3973
+ // No gold wash or left edge on a dismissed row: once swiped
3974
+ // out of the pin it is back in the ordinary feed, and the
3975
+ // BREAKING badge below is enough to find it again. Only the
3976
+ // PINNED strip keeps the gold treatment.
3154
3977
  },
3155
3978
  onMouseEnter: (e) => {
3156
3979
  e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.04)";
@@ -3164,15 +3987,91 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3164
3987
  },
3165
3988
  children: [
3166
3989
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [
3167
- /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: isMobile ? "0.88rem" : "0.95rem", fontWeight: 500, marginBottom: isMobile ? "0.25rem" : "0.35rem", color: "#f8f9fa", lineHeight: isMobile ? 1.35 : 1.4, transition: "color 0.15s" }, children: item.title }),
3990
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { fontSize: "0.8rem", fontWeight: 500, marginBottom: isMobile ? "0.2rem" : "0.3rem", color: "#f8f9fa", lineHeight: 1.35, transition: "color 0.15s" }, children: item.title }),
3168
3991
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: isMobile ? "0.35rem" : "0.5rem", alignItems: "center", flexWrap: "wrap" }, children: [
3169
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#848e9c", fontSize: isMobile ? "0.55rem" : "0.7rem" }, children: formatDateShort(item.date) }),
3170
- item.source && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: isMobile ? "0.08rem 0.35rem" : "0.1rem 0.4rem", borderRadius: "3px", fontSize: isMobile ? "0.52rem" : "0.62rem", fontWeight: 500, backgroundColor: "rgba(255,255,255,0.07)", color: "#848e9c", whiteSpace: "nowrap" }, children: item.source }),
3992
+ isBreakingRow && /* @__PURE__ */ jsxRuntime.jsx(
3993
+ "span",
3994
+ {
3995
+ "data-testid": "breaking-tag",
3996
+ style: {
3997
+ fontSize: "0.55rem",
3998
+ fontWeight: 700,
3999
+ letterSpacing: "0.09em",
4000
+ color: "#0a0b0e",
4001
+ background: "var(--color-accent, #E6C87E)",
4002
+ padding: "0.16rem 0.34rem 0.13rem",
4003
+ borderRadius: "3px",
4004
+ lineHeight: 1
4005
+ },
4006
+ children: "BREAKING"
4007
+ }
4008
+ ),
4009
+ (() => {
4010
+ const age = rowAgeLabel(item.publishedAt, rowNow);
4011
+ return age ? /* @__PURE__ */ jsxRuntime.jsx(
4012
+ "span",
4013
+ {
4014
+ "data-testid": "news-age",
4015
+ "data-age-fresh": age.fresh ? "true" : void 0,
4016
+ style: {
4017
+ // Sized against the 0.8rem row title (matches the
4018
+ // breaking strip's meta scale).
4019
+ fontSize: isMobile ? "0.58rem" : "0.64rem",
4020
+ fontWeight: 600,
4021
+ fontVariantNumeric: "tabular-nums",
4022
+ color: age.fresh ? "var(--color-accent, #E6C87E)" : "rgba(255,255,255,0.65)"
4023
+ },
4024
+ children: age.label
4025
+ }
4026
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#848e9c", fontSize: isMobile ? "0.55rem" : "0.7rem" }, children: formatDateShort(item.date) });
4027
+ })(),
4028
+ showAssetBadges && isProperty && (item.assets ?? (item.asset ? [item.asset] : [])).map((badgeAsset) => /* @__PURE__ */ jsxRuntime.jsx(
4029
+ "span",
4030
+ {
4031
+ className: "news-badge-wrap",
4032
+ onClick: onAssetOpen ? (e) => {
4033
+ e.stopPropagation();
4034
+ e.preventDefault();
4035
+ onAssetOpen(badgeAsset);
4036
+ } : void 0,
4037
+ onMouseEnter: (e) => showBadgeTip(e.currentTarget, badgeAsset),
4038
+ onMouseLeave: () => setBadgeTip(null),
4039
+ style: { cursor: onAssetOpen ? "pointer" : void 0 },
4040
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4041
+ "span",
4042
+ {
4043
+ className: "news-badge-box",
4044
+ "data-testid": "news-asset-badge",
4045
+ style: {
4046
+ display: "inline-flex",
4047
+ alignItems: "center",
4048
+ justifyContent: "center",
4049
+ width: "20px",
4050
+ height: "20px",
4051
+ borderRadius: "5px",
4052
+ overflow: "hidden",
4053
+ background: "rgba(255,255,255,0.08)",
4054
+ flexShrink: 0
4055
+ },
4056
+ children: badgeAsset.imageUrl ? /* @__PURE__ */ jsxRuntime.jsx(
4057
+ "img",
4058
+ {
4059
+ src: badgeAsset.imageUrl,
4060
+ alt: badgeAsset.name ?? badgeAsset.ticker,
4061
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
4062
+ }
4063
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.45rem", fontWeight: 700, letterSpacing: "0.02em", color: "rgba(255,255,255,0.75)" }, children: badgeAsset.ticker.slice(0, 4) })
4064
+ }
4065
+ )
4066
+ },
4067
+ badgeAsset.ticker
4068
+ )),
3171
4069
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: isMobile ? "0.1rem 0.35rem" : "0.15rem 0.4rem", borderRadius: "2px", fontSize: isMobile ? "0.52rem" : "0.65rem", fontWeight: 500, backgroundColor: isProperty ? "rgba(14,203,129,0.1)" : "rgba(240,185,11,0.1)", color: isProperty ? "#0ecb81" : "#E6C87E" }, children: isProperty ? "Property Update" : "Market News" }),
3172
- sentimentInfo && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: isMobile ? "0.52rem" : "0.65rem", fontWeight: 600, color: sentimentInfo.color }, children: [
4070
+ sentimentInfo && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: isMobile ? "0.52rem" : "0.65rem", fontWeight: 600, color: sentimentInfo.color }, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: "0.3rem" }, children: [
3173
4071
  sentimentInfo.arrow ? `${sentimentInfo.arrow} ` : "",
3174
- sentimentInfo.label
3175
- ] })
4072
+ sentimentInfo.label,
4073
+ item.sentimentScore != null && /* @__PURE__ */ jsxRuntime.jsx(SentimentBar, { score: item.sentimentScore, color: sentimentInfo.color })
4074
+ ] }) })
3176
4075
  ] })
3177
4076
  ] }),
3178
4077
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#848e9c", paddingTop: "2px", flexShrink: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z" }) }) })
@@ -3221,15 +4120,13 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3221
4120
  children: [
3222
4121
  /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.9375rem", fontWeight: 500, marginBottom: "0.4rem", color: "#fff", lineHeight: 1.4 }, children: item.title }),
3223
4122
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-end", gap: "0.5rem" }, children: [
3224
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", minWidth: 0, flexWrap: "wrap" }, children: [
3225
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.75rem", color: isHighlighted ? "#0ecb81" : "#b5b8c5", whiteSpace: "nowrap" }, children: dateLabel }),
3226
- item.source && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: "0.15rem 0.45rem", borderRadius: "3px", fontSize: "0.65rem", fontWeight: 500, backgroundColor: "rgba(255,255,255,0.07)", color: "#848e9c", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: "120px" }, children: item.source })
3227
- ] }),
4123
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", minWidth: 0, flexWrap: "wrap" }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.75rem", color: isHighlighted ? "#0ecb81" : "#b5b8c5", whiteSpace: "nowrap" }, children: dateLabel }) }),
3228
4124
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-end", gap: "0.3rem", flexShrink: 0 }, children: [
3229
- sentimentInfo && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: "0.65rem", fontWeight: 700, color: sentimentInfo.color, whiteSpace: "nowrap" }, children: [
4125
+ sentimentInfo && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.65rem", fontWeight: 700, color: sentimentInfo.color, whiteSpace: "nowrap" }, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: "0.3rem" }, children: [
3230
4126
  sentimentInfo.arrow ? `${sentimentInfo.arrow} ` : "",
3231
- sentimentInfo.label
3232
- ] }),
4127
+ sentimentInfo.label,
4128
+ item.sentimentScore != null && /* @__PURE__ */ jsxRuntime.jsx(SentimentBar, { score: item.sentimentScore, color: sentimentInfo.color })
4129
+ ] }) }),
3233
4130
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: "0.25rem 0.6rem", borderRadius: "4px", border: `1px solid ${catStyle.borderColor}`, backgroundColor: catStyle.backgroundColor, color: catStyle.color, fontSize: "0.68rem", fontWeight: 600, textTransform: "uppercase", whiteSpace: "nowrap" }, children: item.type === "property" ? catStyle.label : "Market News" })
3234
4131
  ] })
3235
4132
  ] })
@@ -3302,7 +4199,21 @@ var PropertyNewsUpdates = React5__namespace.forwardRef(
3302
4199
  }
3303
4200
  )
3304
4201
  ] }),
3305
- selectedItem && !isPurchaseVariant && /* @__PURE__ */ jsxRuntime.jsx(NewsArticleModal, { item: selectedItem, onClose: () => setSelectedItem(null) })
4202
+ selectedItem && !isPurchaseVariant && /* @__PURE__ */ jsxRuntime.jsx(NewsArticleModal, { item: selectedItem, onClose: () => setSelectedItem(null) }),
4203
+ badgeTip && ReactDOM__namespace.createPortal(
4204
+ /* @__PURE__ */ jsxRuntime.jsx(
4205
+ "span",
4206
+ {
4207
+ className: "news-badge-tipbox",
4208
+ "data-testid": "news-asset-tip",
4209
+ "data-tip-below": badgeTip.below ? "true" : void 0,
4210
+ "aria-hidden": true,
4211
+ style: { position: "fixed", left: `${badgeTip.left}px`, top: `${badgeTip.top}px` },
4212
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: badgeTip.asset.name ? `${badgeTip.asset.name} (${badgeTip.asset.ticker})` : badgeTip.asset.ticker })
4213
+ }
4214
+ ),
4215
+ document.body
4216
+ )
3306
4217
  ]
3307
4218
  }
3308
4219
  );
@@ -3355,7 +4266,7 @@ var defaultFormat = (value) => new Intl.NumberFormat("en-US", {
3355
4266
  notation: value >= 1e5 ? "compact" : "standard",
3356
4267
  maximumFractionDigits: value >= 1e3 ? 0 : 2
3357
4268
  }).format(value);
3358
- var TradingSlider = React5__namespace.forwardRef(
4269
+ var TradingSlider = React9__namespace.forwardRef(
3359
4270
  ({
3360
4271
  label = "Trade size",
3361
4272
  helperText = "Drag to pick the desired notional.",
@@ -3373,7 +4284,7 @@ var TradingSlider = React5__namespace.forwardRef(
3373
4284
  ...rest
3374
4285
  }, ref) => {
3375
4286
  const isControlled = value !== void 0;
3376
- const [internalValue, setInternalValue] = React5__namespace.useState(
4287
+ const [internalValue, setInternalValue] = React9__namespace.useState(
3377
4288
  defaultValue ?? (typeof min === "number" ? min : 0)
3378
4289
  );
3379
4290
  const currentValue = isControlled ? Number(value) : internalValue;
@@ -3476,7 +4387,7 @@ var MobileToggleButton = styled10__default.default.button`
3476
4387
  padding: 0.6rem 0.5rem;
3477
4388
  }
3478
4389
  `;
3479
- var MobileTradeNav = React5__namespace.forwardRef(
4390
+ var MobileTradeNav = React9__namespace.forwardRef(
3480
4391
  ({ className, items, activeId, onChange, ...props }, ref) => {
3481
4392
  return /* @__PURE__ */ jsxRuntime.jsx(MobileToggleContainer, { ref, className: cn(className), ...props, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
3482
4393
  MobileToggleButton,
@@ -4002,7 +4913,7 @@ var formatPercent = (value, fractionDigits = 2) => {
4002
4913
  if (value == null || Number.isNaN(value)) return "\u2014";
4003
4914
  return `${value.toFixed(fractionDigits)}%`;
4004
4915
  };
4005
- var YourOrders = React5__namespace.forwardRef(
4916
+ var YourOrders = React9__namespace.forwardRef(
4006
4917
  ({
4007
4918
  className,
4008
4919
  title,
@@ -4015,10 +4926,10 @@ var YourOrders = React5__namespace.forwardRef(
4015
4926
  pageSize: pageSizeOverride,
4016
4927
  ...props
4017
4928
  }, ref) => {
4018
- const [internalActiveTab, setInternalActiveTab] = React5__namespace.useState(tabs?.[0]?.id ?? "portfolio");
4019
- const [page, setPage] = React5__namespace.useState(0);
4929
+ const [internalActiveTab, setInternalActiveTab] = React9__namespace.useState(tabs?.[0]?.id ?? "portfolio");
4930
+ const [page, setPage] = React9__namespace.useState(0);
4020
4931
  const effectiveActiveTabId = activeTabId ?? internalActiveTab;
4021
- React5__namespace.useEffect(() => {
4932
+ React9__namespace.useEffect(() => {
4022
4933
  setPage(0);
4023
4934
  }, [effectiveActiveTabId]);
4024
4935
  const handleTabChange = (tabId) => {
@@ -4400,7 +5311,7 @@ function createCandlestickSeries(chart, options) {
4400
5311
  }
4401
5312
  throw new Error("Candlestick series API is not available in the current lightweight-charts version.");
4402
5313
  }
4403
- var PriceChart = React5__namespace.forwardRef(
5314
+ var PriceChart = React9__namespace.forwardRef(
4404
5315
  ({
4405
5316
  className,
4406
5317
  title = "Price Chart",
@@ -4414,18 +5325,18 @@ var PriceChart = React5__namespace.forwardRef(
4414
5325
  height = 301.52,
4415
5326
  ...props
4416
5327
  }, ref) => {
4417
- const containerRef = React5__namespace.useRef(null);
4418
- const chartRef = React5__namespace.useRef(null);
4419
- const seriesRef = React5__namespace.useRef(null);
4420
- const priceLineRef = React5__namespace.useRef(null);
4421
- const [hoveredRange, setHoveredRange] = React5__namespace.useState(null);
4422
- const [dropdownOpen, setDropdownOpen] = React5__namespace.useState(false);
4423
- const dropdownRef = React5__namespace.useRef(null);
4424
- const isAutoScrollRef = React5__namespace.useRef(true);
5328
+ const containerRef = React9__namespace.useRef(null);
5329
+ const chartRef = React9__namespace.useRef(null);
5330
+ const seriesRef = React9__namespace.useRef(null);
5331
+ const priceLineRef = React9__namespace.useRef(null);
5332
+ const [hoveredRange, setHoveredRange] = React9__namespace.useState(null);
5333
+ const [dropdownOpen, setDropdownOpen] = React9__namespace.useState(false);
5334
+ const dropdownRef = React9__namespace.useRef(null);
5335
+ const isAutoScrollRef = React9__namespace.useRef(true);
4425
5336
  const visibleRanges = ranges.slice(0, VISIBLE_RANGE_COUNT);
4426
5337
  const dropdownRanges = ranges.slice(VISIBLE_RANGE_COUNT);
4427
5338
  const selectedInDropdown = dropdownRanges.includes(selectedRange);
4428
- React5__namespace.useEffect(() => {
5339
+ React9__namespace.useEffect(() => {
4429
5340
  const handleClickOutside = (e) => {
4430
5341
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
4431
5342
  setDropdownOpen(false);
@@ -4434,25 +5345,25 @@ var PriceChart = React5__namespace.forwardRef(
4434
5345
  document.addEventListener("mousedown", handleClickOutside);
4435
5346
  return () => document.removeEventListener("mousedown", handleClickOutside);
4436
5347
  }, []);
4437
- const resolvedPrice = React5__namespace.useMemo(() => {
5348
+ const resolvedPrice = React9__namespace.useMemo(() => {
4438
5349
  if (price != null) return price;
4439
5350
  const last = data.at(-1);
4440
5351
  return last?.close;
4441
5352
  }, [data, price]);
4442
- const inferredChangePercent = React5__namespace.useMemo(() => {
5353
+ const inferredChangePercent = React9__namespace.useMemo(() => {
4443
5354
  if (changePercent != null) return changePercent;
4444
5355
  const first = data[0]?.open;
4445
5356
  const last = data.at(-1)?.close;
4446
5357
  if (first == null || last == null || first === 0) return void 0;
4447
5358
  return (last - first) / first * 100;
4448
5359
  }, [changePercent, data]);
4449
- const dollarChange = React5__namespace.useMemo(() => {
5360
+ const dollarChange = React9__namespace.useMemo(() => {
4450
5361
  const first = data[0]?.open;
4451
5362
  const last = data.at(-1)?.close;
4452
5363
  if (first == null || last == null) return void 0;
4453
5364
  return last - first;
4454
5365
  }, [data]);
4455
- React5__namespace.useEffect(() => {
5366
+ React9__namespace.useEffect(() => {
4456
5367
  const el = containerRef.current;
4457
5368
  if (!el) return;
4458
5369
  const chart = LightweightCharts__namespace.createChart(el, {
@@ -4497,7 +5408,7 @@ var PriceChart = React5__namespace.forwardRef(
4497
5408
  chart.remove();
4498
5409
  };
4499
5410
  }, []);
4500
- React5__namespace.useEffect(() => {
5411
+ React9__namespace.useEffect(() => {
4501
5412
  const chart = chartRef.current;
4502
5413
  if (!chart) return;
4503
5414
  const effectiveRange = selectedRange ?? ranges?.[0] ?? "1D";
@@ -4505,7 +5416,7 @@ var PriceChart = React5__namespace.forwardRef(
4505
5416
  timeScale: getTimeScaleOptions(effectiveRange)
4506
5417
  });
4507
5418
  }, [selectedRange, ranges]);
4508
- React5__namespace.useEffect(() => {
5419
+ React9__namespace.useEffect(() => {
4509
5420
  const chart = chartRef.current;
4510
5421
  const series = seriesRef.current;
4511
5422
  if (!chart || !series) return;
@@ -4720,7 +5631,7 @@ var formatPrice3 = (value, currencySymbol, compact) => {
4720
5631
  maximumFractionDigits: 2
4721
5632
  })}`;
4722
5633
  };
4723
- var PropertyHeroHeader = React5__namespace.forwardRef(
5634
+ var PropertyHeroHeader = React9__namespace.forwardRef(
4724
5635
  ({
4725
5636
  className,
4726
5637
  imageUrl,
@@ -4754,12 +5665,12 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
4754
5665
  const isPositive = changePercent == null ? void 0 : changePercent >= 0;
4755
5666
  const accentColor = "#e6c87e";
4756
5667
  const tradeHoverColor = "#f5dd9a";
4757
- const [isTradeInteracting, setIsTradeInteracting] = React5__namespace.useState(false);
4758
- const [isOfferInteracting, setIsOfferInteracting] = React5__namespace.useState(false);
4759
- const [isMobile, setIsMobile] = React5__namespace.useState(
5668
+ const [isTradeInteracting, setIsTradeInteracting] = React9__namespace.useState(false);
5669
+ const [isOfferInteracting, setIsOfferInteracting] = React9__namespace.useState(false);
5670
+ const [isMobile, setIsMobile] = React9__namespace.useState(
4760
5671
  () => typeof window !== "undefined" && window.innerWidth <= 768
4761
5672
  );
4762
- React5__namespace.useEffect(() => {
5673
+ React9__namespace.useEffect(() => {
4763
5674
  const onResize = () => setIsMobile(window.innerWidth <= 768);
4764
5675
  window.addEventListener("resize", onResize);
4765
5676
  return () => window.removeEventListener("resize", onResize);
@@ -5150,10 +6061,10 @@ function fmtCompactUsd(n) {
5150
6061
  }
5151
6062
  function useIsNarrow(maxWidthPx = 768) {
5152
6063
  const query = `(max-width:${maxWidthPx}px)`;
5153
- const [narrow, setNarrow] = React5.useState(
6064
+ const [narrow, setNarrow] = React9.useState(
5154
6065
  typeof window !== "undefined" ? window.matchMedia(query).matches : false
5155
6066
  );
5156
- React5.useEffect(() => {
6067
+ React9.useEffect(() => {
5157
6068
  if (typeof window === "undefined") return;
5158
6069
  const mq = window.matchMedia(query);
5159
6070
  const onChange = () => setNarrow(mq.matches);
@@ -5197,20 +6108,20 @@ var Header = ({
5197
6108
  headerCta = "deposit",
5198
6109
  showRefer = false
5199
6110
  }) => {
5200
- const [headerBgOpacity, setHeaderBgOpacity] = React5.useState(transparentOnTop ? 0 : 1);
5201
- const [isUserMenuOpen, setIsUserMenuOpen] = React5.useState(false);
5202
- const [isMobileMenuOpen, setIsMobileMenuOpen] = React5.useState(false);
6111
+ const [headerBgOpacity, setHeaderBgOpacity] = React9.useState(transparentOnTop ? 0 : 1);
6112
+ const [isUserMenuOpen, setIsUserMenuOpen] = React9.useState(false);
6113
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = React9.useState(false);
5203
6114
  const isNarrow = useIsNarrow();
5204
- const [isMoreMenuOpen, setIsMoreMenuOpen] = React5.useState(false);
5205
- const [showLoginPopup, setShowLoginPopup] = React5.useState(false);
5206
- const [loginPopupInitialView, setLoginPopupInitialView] = React5.useState(void 0);
5207
- const [isPortfolioBarVisible, setIsPortfolioBarVisible] = React5.useState(() => {
6115
+ const [isMoreMenuOpen, setIsMoreMenuOpen] = React9.useState(false);
6116
+ const [showLoginPopup, setShowLoginPopup] = React9.useState(false);
6117
+ const [loginPopupInitialView, setLoginPopupInitialView] = React9.useState(void 0);
6118
+ const [isPortfolioBarVisible, setIsPortfolioBarVisible] = React9.useState(() => {
5208
6119
  if (typeof localStorage === "undefined") return false;
5209
6120
  return localStorage.getItem("portfolioBarVisible") !== "false";
5210
6121
  });
5211
- const portfolioPillRef = React5.useRef(null);
5212
- const [portfolioArrowLeft, setPortfolioArrowLeft] = React5.useState(null);
5213
- const togglePortfolioBar = React5.useCallback(() => {
6122
+ const portfolioPillRef = React9.useRef(null);
6123
+ const [portfolioArrowLeft, setPortfolioArrowLeft] = React9.useState(null);
6124
+ const togglePortfolioBar = React9.useCallback(() => {
5214
6125
  setIsPortfolioBarVisible((prev) => {
5215
6126
  const next = !prev;
5216
6127
  try {
@@ -5221,13 +6132,13 @@ var Header = ({
5221
6132
  });
5222
6133
  }, []);
5223
6134
  const SIMULATE_FUNDS = false;
5224
- const [simFundsPending, setSimFundsPending] = React5.useState(true);
5225
- React5.useEffect(() => {
6135
+ const [simFundsPending, setSimFundsPending] = React9.useState(true);
6136
+ React9.useEffect(() => {
5226
6137
  return;
5227
6138
  }, [simFundsPending]);
5228
6139
  const showFundsPending = (fundsPending || SIMULATE_FUNDS) && isAuthenticated && isPortfolioBarVisible;
5229
- const [fundsCountdown, setFundsCountdown] = React5.useState(10);
5230
- React5.useEffect(() => {
6140
+ const [fundsCountdown, setFundsCountdown] = React9.useState(10);
6141
+ React9.useEffect(() => {
5231
6142
  if (!showFundsPending) return;
5232
6143
  setFundsCountdown(10);
5233
6144
  const id = setInterval(() => {
@@ -5241,7 +6152,7 @@ var Header = ({
5241
6152
  }, 1e3);
5242
6153
  return () => clearInterval(id);
5243
6154
  }, [showFundsPending]);
5244
- React5.useEffect(() => {
6155
+ React9.useEffect(() => {
5245
6156
  const handler = () => {
5246
6157
  if (LoginPopupComponent) {
5247
6158
  setLoginPopupInitialView("funding");
@@ -5251,7 +6162,7 @@ var Header = ({
5251
6162
  window.addEventListener("loaf:open-funding", handler);
5252
6163
  return () => window.removeEventListener("loaf:open-funding", handler);
5253
6164
  }, [LoginPopupComponent]);
5254
- const updatePortfolioArrow = React5.useCallback(() => {
6165
+ const updatePortfolioArrow = React9.useCallback(() => {
5255
6166
  const eye = document.getElementById("portfolio-eye-toggle");
5256
6167
  const pill = portfolioPillRef.current;
5257
6168
  if (!eye || !pill) return;
@@ -5260,13 +6171,13 @@ var Header = ({
5260
6171
  const offset = eyeRect.left + eyeRect.width / 2 - pillRect.left - 7;
5261
6172
  setPortfolioArrowLeft(offset);
5262
6173
  }, []);
5263
- React5.useEffect(() => {
6174
+ React9.useEffect(() => {
5264
6175
  if (!isPortfolioBarVisible || !portfolioSummary) return;
5265
6176
  updatePortfolioArrow();
5266
6177
  window.addEventListener("resize", updatePortfolioArrow);
5267
6178
  return () => window.removeEventListener("resize", updatePortfolioArrow);
5268
6179
  }, [isPortfolioBarVisible, portfolioSummary, updatePortfolioArrow]);
5269
- React5.useEffect(() => {
6180
+ React9.useEffect(() => {
5270
6181
  if (typeof window === "undefined") return;
5271
6182
  const ua = navigator.userAgent;
5272
6183
  const isTelegram = /Telegram/i.test(ua);
@@ -5275,7 +6186,7 @@ var Header = ({
5275
6186
  document.documentElement.style.setProperty("--telegram-safe-top", "59px");
5276
6187
  }
5277
6188
  }, []);
5278
- React5.useEffect(() => {
6189
+ React9.useEffect(() => {
5279
6190
  if (!transparentOnTop) {
5280
6191
  setHeaderBgOpacity(1);
5281
6192
  return;
@@ -5288,7 +6199,7 @@ var Header = ({
5288
6199
  window.addEventListener("scroll", onScroll, { passive: true });
5289
6200
  return () => window.removeEventListener("scroll", onScroll);
5290
6201
  }, [transparentOnTop]);
5291
- React5.useEffect(() => {
6202
+ React9.useEffect(() => {
5292
6203
  const handleClickOutside = (event) => {
5293
6204
  const target = event.target;
5294
6205
  if (!target) return;
@@ -5308,7 +6219,7 @@ var Header = ({
5308
6219
  document.removeEventListener("mousedown", handleClickOutside);
5309
6220
  };
5310
6221
  }, [isUserMenuOpen, isMobileMenuOpen, isMoreMenuOpen]);
5311
- React5.useEffect(() => {
6222
+ React9.useEffect(() => {
5312
6223
  if (typeof window === "undefined") return;
5313
6224
  const handleExternalLoginPopup = (event) => {
5314
6225
  const customEvent = event;
@@ -5439,7 +6350,7 @@ var Header = ({
5439
6350
  setShowLoginPopup(true);
5440
6351
  }
5441
6352
  };
5442
- const handleLoginPopupClose = React5__namespace.default.useCallback(() => {
6353
+ const handleLoginPopupClose = React9__namespace.default.useCallback(() => {
5443
6354
  setShowLoginPopup(false);
5444
6355
  setLoginPopupInitialView(void 0);
5445
6356
  }, []);
@@ -5717,7 +6628,7 @@ var Header = ({
5717
6628
  }
5718
6629
  )
5719
6630
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
5720
- /* @__PURE__ */ jsxRuntime.jsx(Button2, { className: "signup", onClick: handleSignIn, children: "Join Competition" }),
6631
+ /* @__PURE__ */ jsxRuntime.jsx(Button2, { className: "signup", onClick: handleSignIn, children: "Access Beta" }),
5721
6632
  /* @__PURE__ */ jsxRuntime.jsx(
5722
6633
  MobileOnlyButton,
5723
6634
  {
@@ -6603,10 +7514,10 @@ var PBOperator = styled10__default.default.span`
6603
7514
  font-size: 0.55rem;
6604
7515
  }
6605
7516
  `;
6606
- var PropertySubheader = React5__namespace.forwardRef(
7517
+ var PropertySubheader = React9__namespace.forwardRef(
6607
7518
  ({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
6608
- const tabsContainerRef = React5__namespace.useRef(null);
6609
- React5__namespace.useEffect(() => {
7519
+ const tabsContainerRef = React9__namespace.useRef(null);
7520
+ React9__namespace.useEffect(() => {
6610
7521
  const container = tabsContainerRef.current;
6611
7522
  if (!container) return;
6612
7523
  const isMobile = window.innerWidth <= 768;
@@ -6778,34 +7689,34 @@ var LoginPopup = ({
6778
7689
  onCheckAccess,
6779
7690
  gate
6780
7691
  }) => {
6781
- const [view, setView] = React5.useState(() => initialView ?? "main");
6782
- const [email, setEmail] = React5.useState("");
6783
- const [handle, setHandle] = React5.useState("");
6784
- const [otp, setOtp] = React5.useState(Array(OTP_INPUT_LENGTH).fill(""));
6785
- const [error, setError] = React5.useState("");
6786
- const [copied, setCopied] = React5.useState(false);
6787
- const [referralCode, setReferralCode] = React5.useState(
7692
+ const [view, setView] = React9.useState(() => initialView ?? "main");
7693
+ const [email, setEmail] = React9.useState("");
7694
+ const [handle, setHandle] = React9.useState("");
7695
+ const [otp, setOtp] = React9.useState(Array(OTP_INPUT_LENGTH).fill(""));
7696
+ const [error, setError] = React9.useState("");
7697
+ const [copied, setCopied] = React9.useState(false);
7698
+ const [referralCode, setReferralCode] = React9.useState(
6788
7699
  () => gate && initialCode ? normalizeAccessCode(initialCode) : ""
6789
7700
  );
6790
- const [referralLoading, setReferralLoading] = React5.useState(false);
6791
- const [referralError, setReferralError] = React5.useState("");
6792
- const [codeStatus, setCodeStatus] = React5.useState("idle");
6793
- const [signInRevealed, setSignInRevealed] = React5.useState(false);
6794
- const [otpStatus, setOtpStatus] = React5.useState("idle");
6795
- const [signInMode, setSignInMode] = React5.useState(false);
6796
- const [loading, setLoading] = React5.useState(false);
6797
- const [isSignUp, setIsSignUp] = React5.useState(false);
6798
- const [fundingAmount] = React5.useState("");
6799
- const [kycLoading, setKycLoading] = React5.useState(false);
6800
- const [showKycWidget, setShowKycWidget] = React5.useState(false);
6801
- const [showKycFooter, setShowKycFooter] = React5.useState(false);
6802
- const [cryptoFundingLoading, setCryptoFundingLoading] = React5.useState(false);
6803
- const [fiatFundingLoading, setFiatFundingLoading] = React5.useState(false);
6804
- const [fundingError, setFundingError] = React5.useState("");
6805
- const [transakWidgetUrl, setTransakWidgetUrl] = React5.useState(null);
6806
- const suppressAutoCloseRef = React5__namespace.default.useRef(false);
6807
- const validatedCodeRef = React5__namespace.default.useRef(null);
6808
- const finishGate = React5__namespace.default.useCallback(async () => {
7701
+ const [referralLoading, setReferralLoading] = React9.useState(false);
7702
+ const [referralError, setReferralError] = React9.useState("");
7703
+ const [codeStatus, setCodeStatus] = React9.useState("idle");
7704
+ const [signInRevealed, setSignInRevealed] = React9.useState(false);
7705
+ const [otpStatus, setOtpStatus] = React9.useState("idle");
7706
+ const [signInMode, setSignInMode] = React9.useState(false);
7707
+ const [loading, setLoading] = React9.useState(false);
7708
+ const [isSignUp, setIsSignUp] = React9.useState(false);
7709
+ const [fundingAmount] = React9.useState("");
7710
+ const [kycLoading, setKycLoading] = React9.useState(false);
7711
+ const [showKycWidget, setShowKycWidget] = React9.useState(false);
7712
+ const [showKycFooter, setShowKycFooter] = React9.useState(false);
7713
+ const [cryptoFundingLoading, setCryptoFundingLoading] = React9.useState(false);
7714
+ const [fiatFundingLoading, setFiatFundingLoading] = React9.useState(false);
7715
+ const [fundingError, setFundingError] = React9.useState("");
7716
+ const [transakWidgetUrl, setTransakWidgetUrl] = React9.useState(null);
7717
+ const suppressAutoCloseRef = React9__namespace.default.useRef(false);
7718
+ const validatedCodeRef = React9__namespace.default.useRef(null);
7719
+ const finishGate = React9__namespace.default.useCallback(async () => {
6809
7720
  if (!gate) return true;
6810
7721
  const code = validatedCodeRef.current;
6811
7722
  if (code) {
@@ -6831,7 +7742,7 @@ var LoginPopup = ({
6831
7742
  );
6832
7743
  return false;
6833
7744
  }, [gate, onSubmitReferralCode, onCheckAccess]);
6834
- const runCodeValidation = React5__namespace.default.useCallback(async (fullCode) => {
7745
+ const runCodeValidation = React9__namespace.default.useCallback(async (fullCode) => {
6835
7746
  setCodeStatus("checking");
6836
7747
  setError("");
6837
7748
  try {
@@ -6854,20 +7765,20 @@ var LoginPopup = ({
6854
7765
  setCodeStatus("invalid");
6855
7766
  }
6856
7767
  }, [onValidateCode, isAuthenticated, finishGate, onClose]);
6857
- const autoCodeTriedRef = React5__namespace.default.useRef(false);
6858
- React5.useEffect(() => {
7768
+ const autoCodeTriedRef = React9__namespace.default.useRef(false);
7769
+ React9.useEffect(() => {
6859
7770
  if (autoCodeTriedRef.current || !gate || !initialCode) return;
6860
7771
  const full = normalizeAccessCode(initialCode);
6861
7772
  if (full.length !== CODE_PREFIX.length + CODE_SUFFIX_LEN) return;
6862
7773
  autoCodeTriedRef.current = true;
6863
7774
  void runCodeValidation(full);
6864
7775
  }, [gate, initialCode, runCodeValidation]);
6865
- React5.useEffect(() => {
7776
+ React9.useEffect(() => {
6866
7777
  if (typeof initialView === "string") {
6867
7778
  setView(initialView);
6868
7779
  }
6869
7780
  }, [initialView]);
6870
- React5.useEffect(() => {
7781
+ React9.useEffect(() => {
6871
7782
  if (!showKycWidget) {
6872
7783
  setShowKycFooter(false);
6873
7784
  return;
@@ -6875,7 +7786,7 @@ var LoginPopup = ({
6875
7786
  const timer = setTimeout(() => setShowKycFooter(true), 5e3);
6876
7787
  return () => clearTimeout(timer);
6877
7788
  }, [showKycWidget]);
6878
- React5.useEffect(() => {
7789
+ React9.useEffect(() => {
6879
7790
  if (!transakWidgetUrl) return;
6880
7791
  const handleTransakMessage = (event) => {
6881
7792
  if (!isTrustedTransakOrigin(event.origin, transakWidgetUrl)) {
@@ -6900,7 +7811,7 @@ var LoginPopup = ({
6900
7811
  window.addEventListener("message", handleTransakMessage);
6901
7812
  return () => window.removeEventListener("message", handleTransakMessage);
6902
7813
  }, [transakWidgetUrl, onClose]);
6903
- React5.useEffect(() => {
7814
+ React9.useEffect(() => {
6904
7815
  if (!autoCloseOnAuth) {
6905
7816
  return;
6906
7817
  }
@@ -6914,7 +7825,7 @@ var LoginPopup = ({
6914
7825
  onClose();
6915
7826
  }
6916
7827
  }, [autoCloseOnAuth, currentUser, isAuthenticated, onClose, view]);
6917
- React5.useEffect(() => {
7828
+ React9.useEffect(() => {
6918
7829
  const handleEsc = (e) => {
6919
7830
  if (e.key === "Escape" && !gate) onClose();
6920
7831
  };
@@ -7137,7 +8048,7 @@ var LoginPopup = ({
7137
8048
  setLoading(false);
7138
8049
  }
7139
8050
  };
7140
- const runGateOtpVerify = React5__namespace.default.useCallback(async (code) => {
8051
+ const runGateOtpVerify = React9__namespace.default.useCallback(async (code) => {
7141
8052
  if (!onVerifyEmailCode) return;
7142
8053
  setOtpStatus("checking");
7143
8054
  setError("");
@@ -7153,7 +8064,7 @@ var LoginPopup = ({
7153
8064
  setOtpStatus("invalid");
7154
8065
  }
7155
8066
  }, [onVerifyEmailCode, email, finishGate, onClose]);
7156
- React5.useEffect(() => {
8067
+ React9.useEffect(() => {
7157
8068
  if (!gate || view !== "otp") return;
7158
8069
  if (otp.join("").length < OTP_INPUT_LENGTH) {
7159
8070
  if (otpStatus === "invalid") setOtpStatus("idle");
@@ -7262,7 +8173,7 @@ var LoginPopup = ({
7262
8173
  /* @__PURE__ */ jsxRuntime.jsxs(Title, { children: [
7263
8174
  /* @__PURE__ */ jsxRuntime.jsxs(LogoContainer3, { children: [
7264
8175
  /* @__PURE__ */ jsxRuntime.jsx(LogoImage, { src: logoSrc, alt: logoAlt }),
7265
- /* @__PURE__ */ jsxRuntime.jsx(LogoBeta, { children: "Private Beta" })
8176
+ /* @__PURE__ */ jsxRuntime.jsx(LogoBeta, { children: "Beta" })
7266
8177
  ] }),
7267
8178
  /* @__PURE__ */ jsxRuntime.jsx(TitleText, { children: "Welcome to Loaf" })
7268
8179
  ] }),
@@ -7357,7 +8268,7 @@ var LoginPopup = ({
7357
8268
  /* @__PURE__ */ jsxRuntime.jsxs(GateBrand, { children: [
7358
8269
  /* @__PURE__ */ jsxRuntime.jsx(GateLogoLink, { href: "https://loafmarkets.com", "aria-label": "Go to loafmarkets.com", children: /* @__PURE__ */ jsxRuntime.jsx(GateLogo, { src: logoSrc, alt: logoAlt }) }),
7359
8270
  /* @__PURE__ */ jsxRuntime.jsx(GateBrandDivider, {}),
7360
- /* @__PURE__ */ jsxRuntime.jsx(GateBetaTag, { children: "Private Beta" })
8271
+ /* @__PURE__ */ jsxRuntime.jsx(GateBetaTag, { children: "Beta" })
7361
8272
  ] }),
7362
8273
  /* @__PURE__ */ jsxRuntime.jsxs(GateOtpText, { children: [
7363
8274
  "We sent a code to",
@@ -7696,6 +8607,16 @@ var LoginPopup = ({
7696
8607
  ),
7697
8608
  /* @__PURE__ */ jsxRuntime.jsx(GateSubmit, { type: "submit", "aria-label": "Continue", disabled: loading || !email, children: loading ? /* @__PURE__ */ jsxRuntime.jsx(GateSpinner, {}) : /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 12h14M13 6l6 6-6 6" }) }) })
7698
8609
  ] }),
8610
+ !signInMode && /* @__PURE__ */ jsxRuntime.jsx(GateHandleRow, { children: /* @__PURE__ */ jsxRuntime.jsx(
8611
+ GateEmailInput,
8612
+ {
8613
+ type: "text",
8614
+ autoComplete: "username",
8615
+ placeholder: "Claim your username (Optional)",
8616
+ value: handle,
8617
+ onChange: (event) => setHandle(event.target.value)
8618
+ }
8619
+ ) }),
7699
8620
  error && /* @__PURE__ */ jsxRuntime.jsx(StatusMessage, { $error: true, children: error })
7700
8621
  ] }),
7701
8622
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -7714,7 +8635,7 @@ var LoginPopup = ({
7714
8635
  /* @__PURE__ */ jsxRuntime.jsxs(GateBrand, { children: [
7715
8636
  /* @__PURE__ */ jsxRuntime.jsx(GateLogoLink, { href: "https://loafmarkets.com", "aria-label": "Go to loafmarkets.com", children: /* @__PURE__ */ jsxRuntime.jsx(GateLogo, { src: logoSrc, alt: logoAlt }) }),
7716
8637
  /* @__PURE__ */ jsxRuntime.jsx(GateBrandDivider, {}),
7717
- /* @__PURE__ */ jsxRuntime.jsx(GateBetaTag, { children: "Private Beta" })
8638
+ /* @__PURE__ */ jsxRuntime.jsx(GateBetaTag, { children: "Beta" })
7718
8639
  ] }),
7719
8640
  signInMode ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7720
8641
  signInStep,
@@ -7766,7 +8687,7 @@ var LoginPopup = ({
7766
8687
  /* @__PURE__ */ jsxRuntime.jsxs(Title, { children: [
7767
8688
  /* @__PURE__ */ jsxRuntime.jsxs(LogoContainer3, { children: [
7768
8689
  /* @__PURE__ */ jsxRuntime.jsx(LogoImage, { src: logoSrc, alt: logoAlt }),
7769
- /* @__PURE__ */ jsxRuntime.jsx(LogoBeta, { children: "Private Beta" })
8690
+ /* @__PURE__ */ jsxRuntime.jsx(LogoBeta, { children: "Beta" })
7770
8691
  ] }),
7771
8692
  /* @__PURE__ */ jsxRuntime.jsx(TitleText, { children: "Enter your access code" })
7772
8693
  ] }),
@@ -8430,6 +9351,9 @@ var GateSubmit = styled10__default.default.button`
8430
9351
  cursor: default;
8431
9352
  }
8432
9353
  `;
9354
+ var GateHandleRow = styled10__default.default(CodeInputWrapper)`
9355
+ margin-top: 0.6rem;
9356
+ `;
8433
9357
  var GateEmailInput = styled10__default.default.input`
8434
9358
  flex: 1;
8435
9359
  min-width: 0;
@@ -8715,8 +9639,8 @@ var TransakIframe = styled10__default.default.iframe`
8715
9639
  border-radius: var(--border-radius, 12px);
8716
9640
  `;
8717
9641
  var MiniLiveFeed = () => {
8718
- const [purchases, setPurchases] = React5.useState([]);
8719
- React5.useEffect(() => {
9642
+ const [purchases, setPurchases] = React9.useState([]);
9643
+ React9.useEffect(() => {
8720
9644
  const handles = [
8721
9645
  "Landlord",
8722
9646
  "PropertyKing",
@@ -8972,8 +9896,8 @@ var FactText = styled10__default.default.p`
8972
9896
  }
8973
9897
  `;
8974
9898
  var PreparingFacts = () => {
8975
- const [index, setIndex] = React5.useState(() => Math.floor(Math.random() * PREPARING_FACTS.length));
8976
- React5.useEffect(() => {
9899
+ const [index, setIndex] = React9.useState(() => Math.floor(Math.random() * PREPARING_FACTS.length));
9900
+ React9.useEffect(() => {
8977
9901
  const id = setInterval(() => {
8978
9902
  setIndex((i) => (i + 1) % PREPARING_FACTS.length);
8979
9903
  }, 4e3);
@@ -9236,11 +10160,11 @@ function OnboardingGuide({
9236
10160
  onClaimHandle,
9237
10161
  logoSrc = "/Loaf-logo-Banner.png"
9238
10162
  }) {
9239
- const [step, setStep] = React5.useState(onClaimHandle ? "handle" : "funds");
9240
- const [handle, setHandle] = React5.useState("");
9241
- const [claiming, setClaiming] = React5.useState(false);
9242
- const [handleError, setHandleError] = React5.useState("");
9243
- React5.useEffect(() => {
10163
+ const [step, setStep] = React9.useState(onClaimHandle ? "handle" : "funds");
10164
+ const [handle, setHandle] = React9.useState("");
10165
+ const [claiming, setClaiming] = React9.useState(false);
10166
+ const [handleError, setHandleError] = React9.useState("");
10167
+ React9.useEffect(() => {
9244
10168
  if (open) {
9245
10169
  setStep(onClaimHandle ? "handle" : "funds");
9246
10170
  setHandle("");
@@ -9248,7 +10172,7 @@ function OnboardingGuide({
9248
10172
  setHandleError("");
9249
10173
  }
9250
10174
  }, [open, onClaimHandle]);
9251
- React5.useEffect(() => {
10175
+ React9.useEffect(() => {
9252
10176
  if (!open) return;
9253
10177
  const onKey = (e) => {
9254
10178
  if (e.key === "Escape") onClose();
@@ -9348,7 +10272,7 @@ function OnboardingGuide({
9348
10272
  ] })
9349
10273
  ] }) });
9350
10274
  }
9351
- var PropertyCompareBar = React5__namespace.forwardRef(
10275
+ var PropertyCompareBar = React9__namespace.forwardRef(
9352
10276
  ({
9353
10277
  className,
9354
10278
  addresses,
@@ -9359,7 +10283,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
9359
10283
  price,
9360
10284
  ...props
9361
10285
  }, ref) => {
9362
- const normalizedAddresses = React5__namespace.useMemo(() => {
10286
+ const normalizedAddresses = React9__namespace.useMemo(() => {
9363
10287
  return addresses.map(
9364
10288
  (option) => typeof option === "string" ? { id: option, label: option } : option
9365
10289
  );
@@ -9367,11 +10291,11 @@ var PropertyCompareBar = React5__namespace.forwardRef(
9367
10291
  const hasAddresses = normalizedAddresses.length > 0;
9368
10292
  const firstAddressId = normalizedAddresses[0]?.id;
9369
10293
  const isControlled = selectedAddressId !== void 0;
9370
- const [internalSelectedId, setInternalSelectedId] = React5__namespace.useState(
10294
+ const [internalSelectedId, setInternalSelectedId] = React9__namespace.useState(
9371
10295
  () => isControlled ? void 0 : firstAddressId
9372
10296
  );
9373
10297
  const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
9374
- React5__namespace.useEffect(() => {
10298
+ React9__namespace.useEffect(() => {
9375
10299
  if (!isControlled) {
9376
10300
  setInternalSelectedId((current) => {
9377
10301
  if (current != null && normalizedAddresses.some((option) => option.id === current)) {
@@ -9382,9 +10306,9 @@ var PropertyCompareBar = React5__namespace.forwardRef(
9382
10306
  }
9383
10307
  }, [firstAddressId, isControlled, normalizedAddresses]);
9384
10308
  const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
9385
- const [isDropdownOpen, setIsDropdownOpen] = React5__namespace.useState(false);
9386
- const dropdownRef = React5__namespace.useRef(null);
9387
- React5__namespace.useEffect(() => {
10309
+ const [isDropdownOpen, setIsDropdownOpen] = React9__namespace.useState(false);
10310
+ const dropdownRef = React9__namespace.useRef(null);
10311
+ React9__namespace.useEffect(() => {
9388
10312
  if (!isDropdownOpen) return;
9389
10313
  const handleClick = (event) => {
9390
10314
  if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
@@ -9777,8 +10701,8 @@ var PriceChange = styled10__default.default.span`
9777
10701
  color: ${(props) => props.$isPositive == null ? "var(--color-text-secondary, rgba(255, 255, 255, 0.6))" : props.$isPositive ? "var(--color-positive, #0ecb81)" : "var(--color-negative, #f6465d)"};
9778
10702
  `;
9779
10703
  function useMaxWidth(maxWidth) {
9780
- const [match, setMatch] = React5.useState(() => typeof window !== "undefined" && window.matchMedia(`(max-width: ${maxWidth}px)`).matches);
9781
- React5.useEffect(() => {
10704
+ const [match, setMatch] = React9.useState(() => typeof window !== "undefined" && window.matchMedia(`(max-width: ${maxWidth}px)`).matches);
10705
+ React9.useEffect(() => {
9782
10706
  if (typeof window === "undefined") return;
9783
10707
  const mq = window.matchMedia(`(max-width: ${maxWidth}px)`);
9784
10708
  const onChange = () => setMatch(mq.matches);
@@ -9803,14 +10727,14 @@ function GalleryMapSection({
9803
10727
  hideSuburb = false,
9804
10728
  featuresSlot
9805
10729
  }) {
9806
- const [carouselIndex, setCarouselIndex] = React5.useState(0);
9807
- const [showVideo, setShowVideo] = React5.useState(false);
9808
- const [autoPlaying, setAutoPlaying] = React5.useState(autoPlay);
9809
- const [showFullMap, setShowFullMap] = React5.useState(false);
9810
- const [showFullVideo, setShowFullVideo] = React5.useState(false);
10730
+ const [carouselIndex, setCarouselIndex] = React9.useState(0);
10731
+ const [showVideo, setShowVideo] = React9.useState(false);
10732
+ const [autoPlaying, setAutoPlaying] = React9.useState(autoPlay);
10733
+ const [showFullMap, setShowFullMap] = React9.useState(false);
10734
+ const [showFullVideo, setShowFullVideo] = React9.useState(false);
9811
10735
  const isMobile = useMaxWidth(768);
9812
10736
  const resolvedMapUrl = mapUrl ?? (tokenName ? `/map/${tokenName}?embed=true&zoom=14&hideOthers=true` : "about:blank");
9813
- React5.useEffect(() => {
10737
+ React9.useEffect(() => {
9814
10738
  if (!autoPlaying || images.length <= 1) return;
9815
10739
  const interval = setInterval(() => {
9816
10740
  setCarouselIndex((p) => (p + 1) % images.length);
@@ -9997,10 +10921,10 @@ function GalleryMapSection({
9997
10921
  ] });
9998
10922
  }
9999
10923
  function StackedGallery({ images, onPhotoClick }) {
10000
- const [expanded, setExpanded] = React5.useState(false);
10001
- const [cardH, setCardH] = React5.useState(200);
10002
- const wrapRef = React5.useRef(null);
10003
- React5.useEffect(() => {
10924
+ const [expanded, setExpanded] = React9.useState(false);
10925
+ const [cardH, setCardH] = React9.useState(200);
10926
+ const wrapRef = React9.useRef(null);
10927
+ React9.useEffect(() => {
10004
10928
  const el = wrapRef.current;
10005
10929
  if (!el) return;
10006
10930
  const measure = () => {
@@ -10012,7 +10936,7 @@ function StackedGallery({ images, onPhotoClick }) {
10012
10936
  ro.observe(el);
10013
10937
  return () => ro.disconnect();
10014
10938
  }, []);
10015
- React5.useEffect(() => {
10939
+ React9.useEffect(() => {
10016
10940
  const el = wrapRef.current;
10017
10941
  if (!el) return;
10018
10942
  const update = () => {
@@ -10104,21 +11028,21 @@ function StackedGallery({ images, onPhotoClick }) {
10104
11028
  ] });
10105
11029
  }
10106
11030
  function FullMapPopup({ onClose, mapUrl }) {
10107
- React5.useEffect(() => {
11031
+ React9.useEffect(() => {
10108
11032
  const handleEsc = (e) => {
10109
11033
  if (e.key === "Escape") onClose();
10110
11034
  };
10111
11035
  window.addEventListener("keydown", handleEsc);
10112
11036
  return () => window.removeEventListener("keydown", handleEsc);
10113
11037
  }, [onClose]);
10114
- React5.useEffect(() => {
11038
+ React9.useEffect(() => {
10115
11039
  const handleMessage = (e) => {
10116
11040
  if (e.data === "loaf:close-embed") onClose();
10117
11041
  };
10118
11042
  window.addEventListener("message", handleMessage);
10119
11043
  return () => window.removeEventListener("message", handleMessage);
10120
11044
  }, [onClose]);
10121
- const iframeRef = React5.useCallback((node) => {
11045
+ const iframeRef = React9.useCallback((node) => {
10122
11046
  if (!node) return;
10123
11047
  const handleLoad = () => {
10124
11048
  try {
@@ -10595,10 +11519,10 @@ function PropertyOverview({
10595
11519
  beta = false,
10596
11520
  marketHours
10597
11521
  }) {
10598
- const [isDescExpanded, setDescExpanded] = React5.useState(false);
10599
- const [showDividendHistory, setShowDividendHistory] = React5.useState(false);
10600
- const [copiedAddress, setCopiedAddress] = React5.useState(false);
10601
- const [statsTab, setStatsTab] = React5.useState("token");
11522
+ const [isDescExpanded, setDescExpanded] = React9.useState(false);
11523
+ const [showDividendHistory, setShowDividendHistory] = React9.useState(false);
11524
+ const [copiedAddress, setCopiedAddress] = React9.useState(false);
11525
+ const [statsTab, setStatsTab] = React9.useState("token");
10602
11526
  const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
10603
11527
  const landSize = landProp ?? overviewData?.landSizeSqm ?? null;
10604
11528
  const buildingSize = buildingProp ?? overviewData?.buildingSizeSqm ?? null;
@@ -10907,8 +11831,8 @@ function DividendHistoryPopup({
10907
11831
  onClose
10908
11832
  }) {
10909
11833
  const { records, priceHistory } = generateDividendHistory(valuation ?? 0, totalTokens ?? 0, tokenPrice ?? 0, realPriceHistory);
10910
- const [highlightedIdx, setHighlightedIdx] = React5.useState(null);
10911
- React5.useEffect(() => {
11834
+ const [highlightedIdx, setHighlightedIdx] = React9.useState(null);
11835
+ React9.useEffect(() => {
10912
11836
  const handleEsc = (e) => {
10913
11837
  if (e.key === "Escape") onClose();
10914
11838
  };
@@ -11755,8 +12679,8 @@ var OfferPricePulse = styled10__default.default.span`
11755
12679
  `;
11756
12680
  var eventTypes = ["Leased", "Renovated", "Extended", "Rebuilt", "Rezoned", "DA Approval"];
11757
12681
  function PropertyHistory() {
11758
- const [historyFilter, setHistoryFilter] = React5.useState("all");
11759
- const pastSales = React5.useMemo(() => generateMockPastSales(), []);
12682
+ const [historyFilter, setHistoryFilter] = React9.useState("all");
12683
+ const pastSales = React9.useMemo(() => generateMockPastSales(), []);
11760
12684
  const loafListing = pastSales.find((sale) => sale.type === "Listed");
11761
12685
  const loafEvents = pastSales.filter(
11762
12686
  (sale) => sale.ownershipPeriod === "current" && sale.type !== "Listed" && (sale.id === "leased-current" || sale.id === "da-approval")
@@ -11893,7 +12817,7 @@ function PropertyHistory() {
11893
12817
  ] });
11894
12818
  }
11895
12819
  function EventDetails({ event }) {
11896
- const [expanded, setExpanded] = React5.useState(false);
12820
+ const [expanded, setExpanded] = React9.useState(false);
11897
12821
  const toggleExpand = () => {
11898
12822
  setExpanded((prev) => !prev);
11899
12823
  };
@@ -12390,9 +13314,9 @@ var COMING_SOON_TITLES = [
12390
13314
  "Risk Disclosure Statement"
12391
13315
  ];
12392
13316
  function PropertyDocuments({ documentsData, highlightDocument, onClearHighlight }) {
12393
- const highlightRef = React5.useRef(null);
12394
- const [previewUrl, setPreviewUrl] = React5.useState(null);
12395
- const [previewTitle, setPreviewTitle] = React5.useState(null);
13317
+ const highlightRef = React9.useRef(null);
13318
+ const [previewUrl, setPreviewUrl] = React9.useState(null);
13319
+ const [previewTitle, setPreviewTitle] = React9.useState(null);
12396
13320
  const backendDocuments = Array.isArray(documentsData?.documents) ? documentsData.documents : [];
12397
13321
  const liveDocs = backendDocuments.filter(
12398
13322
  (d) => Boolean(d.documentUrl) && isSafeUrl(d.documentUrl) && LIVE_TITLE_PATTERNS.some((rx) => rx.test(d.title))
@@ -12407,7 +13331,7 @@ function PropertyDocuments({ documentsData, highlightDocument, onClearHighlight
12407
13331
  setPreviewUrl(doc.documentUrl);
12408
13332
  setPreviewTitle(doc.title);
12409
13333
  };
12410
- React5.useEffect(() => {
13334
+ React9.useEffect(() => {
12411
13335
  if (highlightDocument && highlightRef.current) {
12412
13336
  highlightRef.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
12413
13337
  }
@@ -12416,7 +13340,7 @@ function PropertyDocuments({ documentsData, highlightDocument, onClearHighlight
12416
13340
  if (hit) selectPreview(hit);
12417
13341
  }
12418
13342
  }, [highlightDocument]);
12419
- React5.useEffect(() => {
13343
+ React9.useEffect(() => {
12420
13344
  if (!highlightDocument || !onClearHighlight) return;
12421
13345
  const handler = (e) => {
12422
13346
  if (highlightRef.current && !highlightRef.current.contains(e.target)) {
@@ -12812,6 +13736,32 @@ var SignInButton = styled10__default.default.button`
12812
13736
  background: rgba(240, 185, 11, 0.1);
12813
13737
  }
12814
13738
  `;
13739
+ var SORT_COLUMNS = [
13740
+ { field: "price", label: "Price" },
13741
+ { field: "change", label: "24h Change" },
13742
+ { field: "volume", label: "24h Volume", hideOnPhone: true },
13743
+ { field: "value", label: "Asset Value", hideOnPhone: true }
13744
+ ];
13745
+ function sortValue(item, field) {
13746
+ switch (field) {
13747
+ case "volume":
13748
+ return item.volume24h ?? null;
13749
+ case "price":
13750
+ return item.price ?? null;
13751
+ case "change":
13752
+ return item.changePercent ?? null;
13753
+ case "value":
13754
+ return item.propertyValue ?? null;
13755
+ }
13756
+ }
13757
+ function fmtWholeUsd(value) {
13758
+ if (value == null) return null;
13759
+ return `$${value.toLocaleString(void 0, { maximumFractionDigits: 0 })}`;
13760
+ }
13761
+ function fmtPrice(value) {
13762
+ if (value == null) return null;
13763
+ return `$${value.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
13764
+ }
12815
13765
  function displayName(item) {
12816
13766
  if (item.name) return item.name;
12817
13767
  return item.tokenName.charAt(0).toUpperCase() + item.tokenName.slice(1);
@@ -12825,24 +13775,79 @@ function AssetSelectorBar({
12825
13775
  selectorItems,
12826
13776
  onSelect,
12827
13777
  trailing,
13778
+ afterName,
12828
13779
  imageUrl,
12829
13780
  badgeLabel,
12830
- tickerPrimary
13781
+ tickerPrimary,
13782
+ compactName
12831
13783
  }) {
12832
- const [isDropdownOpen, setIsDropdownOpen] = React5.useState(false);
13784
+ const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
13785
+ const [nameTip, setNameTip] = React9.useState(null);
13786
+ const anchorRef = React9.useRef(null);
13787
+ const [dropdownPos, setDropdownPos] = React9.useState(null);
13788
+ React9.useLayoutEffect(() => {
13789
+ if (!isDropdownOpen) return;
13790
+ const measure = () => {
13791
+ const rect = anchorRef.current?.getBoundingClientRect();
13792
+ if (rect) setDropdownPos({ top: rect.bottom + 6, left: rect.left });
13793
+ };
13794
+ measure();
13795
+ window.addEventListener("resize", measure);
13796
+ window.addEventListener("scroll", measure, true);
13797
+ return () => {
13798
+ window.removeEventListener("resize", measure);
13799
+ window.removeEventListener("scroll", measure, true);
13800
+ };
13801
+ }, [isDropdownOpen]);
13802
+ const [sortField, setSortField] = React9.useState("volume");
13803
+ const [sortDir, setSortDir] = React9.useState("desc");
12833
13804
  const hasItems = selectorItems && selectorItems.length > 0;
13805
+ const hasMarketData = !!selectorItems?.some(
13806
+ (i) => i.price != null || i.changePercent != null || i.volume24h != null || i.propertyValue != null
13807
+ );
13808
+ const sortedItems = React9.useMemo(() => {
13809
+ if (!selectorItems) return [];
13810
+ if (!hasMarketData) return [...selectorItems];
13811
+ const dir = sortDir === "desc" ? -1 : 1;
13812
+ const missing = sortDir === "desc" ? -Infinity : Infinity;
13813
+ return [...selectorItems].sort((a, b) => {
13814
+ const av = sortValue(a, sortField) ?? missing;
13815
+ const bv = sortValue(b, sortField) ?? missing;
13816
+ return (av - bv) * dir || 0;
13817
+ });
13818
+ }, [selectorItems, hasMarketData, sortField, sortDir]);
13819
+ const handleSortClick = (field) => {
13820
+ if (field === sortField) {
13821
+ setSortDir((d) => d === "desc" ? "asc" : "desc");
13822
+ } else {
13823
+ setSortField(field);
13824
+ setSortDir("desc");
13825
+ }
13826
+ };
12834
13827
  const currentTicker = currentTokenName ? selectorItems?.find((i) => i.tokenName.toLowerCase() === currentTokenName.toLowerCase())?.ticker : void 0;
12835
13828
  const metrics = metricsProp ?? [
12836
13829
  ...tokenPrice != null ? [{ label: "Unit Price", value: `$${tokenPrice.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`, accent: true }] : [],
12837
13830
  ...offeringValuation != null ? [{ label: "Offering Valuation", value: `$${offeringValuation.toLocaleString()}` }] : []
12838
13831
  ];
12839
- return /* @__PURE__ */ jsxRuntime.jsx(AssetSelectorWrapper, { children: /* @__PURE__ */ jsxRuntime.jsxs(IPOAssetSelector, { children: [
13832
+ return /* @__PURE__ */ jsxRuntime.jsx(AssetSelectorWrapper, { children: /* @__PURE__ */ jsxRuntime.jsxs(IPOAssetSelector, { ref: anchorRef, children: [
12840
13833
  imageUrl && /* @__PURE__ */ jsxRuntime.jsx(AssetThumbnail, { src: imageUrl, alt: propertyName }),
12841
- /* @__PURE__ */ jsxRuntime.jsx(AssetSelectorDropdown, { $flush: tickerPrimary, onClick: () => hasItems && setIsDropdownOpen((prev) => !prev), children: /* @__PURE__ */ jsxRuntime.jsxs(AssetName, { children: [
13834
+ /* @__PURE__ */ jsxRuntime.jsx(AssetSelectorDropdown, { $flush: tickerPrimary, $noShrink: !!compactName && !!currentTicker && !tickerPrimary, onClick: () => hasItems && setIsDropdownOpen((prev) => !prev), children: /* @__PURE__ */ jsxRuntime.jsxs(AssetName, { children: [
12842
13835
  tickerPrimary && currentTicker ? /* @__PURE__ */ jsxRuntime.jsxs(AssetIdentity, { children: [
12843
13836
  /* @__PURE__ */ jsxRuntime.jsx(AssetTicker, { children: currentTicker.toUpperCase() }),
12844
13837
  /* @__PURE__ */ jsxRuntime.jsx(AssetSubName, { children: propertyName })
12845
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13838
+ ] }) : compactName && currentTicker ? /* @__PURE__ */ jsxRuntime.jsx(
13839
+ CompactName,
13840
+ {
13841
+ className: "asset-bar-compact-name",
13842
+ "aria-label": propertyName,
13843
+ onMouseEnter: (e) => {
13844
+ const r = e.currentTarget.getBoundingClientRect();
13845
+ setNameTip({ left: r.left + r.width / 2, top: r.bottom + 10 });
13846
+ },
13847
+ onMouseLeave: () => setNameTip(null),
13848
+ children: currentTicker.toUpperCase()
13849
+ }
13850
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12846
13851
  propertyName,
12847
13852
  currentTicker ? ` (${currentTicker.toUpperCase()})` : ""
12848
13853
  ] }),
@@ -12860,6 +13865,7 @@ function AssetSelectorBar({
12860
13865
  }
12861
13866
  )
12862
13867
  ] }) }),
13868
+ afterName != null && /* @__PURE__ */ jsxRuntime.jsx(AfterNameSlot, { className: "asset-bar-after-name", children: afterName }),
12863
13869
  metrics.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(SelectorMetrics, { children: metrics.map((m, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "contents" }, children: [
12864
13870
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx(Separator, { children: "|" }),
12865
13871
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
@@ -12875,40 +13881,128 @@ function AssetSelectorBar({
12875
13881
  ] })
12876
13882
  ] }, m.label)) }),
12877
13883
  trailing != null && /* @__PURE__ */ jsxRuntime.jsx(TrailingWrapper, { className: "asset-bar-trailing", children: /* @__PURE__ */ jsxRuntime.jsx(TrailingInner, { children: trailing }) }),
12878
- isDropdownOpen && hasItems && /* @__PURE__ */ jsxRuntime.jsx(IPODropdown, { children: selectorItems.map((item) => {
12879
- const isCurrent = item.tokenName === currentTokenName;
12880
- const status = item.status?.toUpperCase();
12881
- const statusLabel = status === "PENDING" ? "Preparing" : status === "CLOSED" ? "Closed" : status === "CANCELLED" ? "Cancelled" : null;
12882
- return /* @__PURE__ */ jsxRuntime.jsx(
12883
- IPOOption,
13884
+ nameTip != null && typeof document !== "undefined" && ReactDOM.createPortal(
13885
+ /* @__PURE__ */ jsxRuntime.jsx(
13886
+ NameTip,
12884
13887
  {
12885
- onClick: () => {
12886
- if (!isCurrent && onSelect) {
12887
- onSelect(item.tokenName);
12888
- }
12889
- setIsDropdownOpen(false);
12890
- },
12891
- $selected: isCurrent,
12892
- style: { cursor: isCurrent ? "default" : "pointer" },
12893
- children: /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionInner, { children: [
12894
- item.imageUrl && /* @__PURE__ */ jsxRuntime.jsx(IPOOptionThumb, { src: item.imageUrl, alt: displayName(item) }),
12895
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12896
- /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionName, { children: [
12897
- displayName(item),
12898
- item.ticker ? ` (${item.ticker})` : "",
12899
- item.badge && /* @__PURE__ */ jsxRuntime.jsx(CompetitionBadge, { children: item.badge })
12900
- ] }),
12901
- /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionLocation, { children: [
12902
- item.streetAddress,
12903
- item.suburb ? `, ${item.suburb}` : "",
12904
- statusLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: statusLabel })
12905
- ] })
12906
- ] })
12907
- ] })
12908
- },
12909
- item.tokenName
12910
- );
12911
- }) })
13888
+ role: "tooltip",
13889
+ "data-testid": "asset-name-tip",
13890
+ style: { position: "fixed", left: nameTip.left, top: nameTip.top, transform: "translateX(-50%)", zIndex: 10050 },
13891
+ children: propertyName
13892
+ }
13893
+ ),
13894
+ document.body
13895
+ ),
13896
+ isDropdownOpen && hasItems && dropdownPos != null && typeof document !== "undefined" && ReactDOM.createPortal(
13897
+ /* @__PURE__ */ jsxRuntime.jsxs(
13898
+ IPODropdown,
13899
+ {
13900
+ $wide: hasMarketData,
13901
+ style: { position: "fixed", top: dropdownPos.top, left: dropdownPos.left, zIndex: 10050 },
13902
+ children: [
13903
+ hasMarketData && /* @__PURE__ */ jsxRuntime.jsxs(HeaderRow, { children: [
13904
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderLabel, { children: "Asset" }),
13905
+ SORT_COLUMNS.map(({ field, label, hideOnPhone }) => /* @__PURE__ */ jsxRuntime.jsxs(
13906
+ SortButton,
13907
+ {
13908
+ type: "button",
13909
+ $active: sortField === field,
13910
+ $hideOnPhone: hideOnPhone,
13911
+ onClick: (e) => {
13912
+ e.stopPropagation();
13913
+ handleSortClick(field);
13914
+ },
13915
+ children: [
13916
+ label,
13917
+ sortField === field ? sortDir === "desc" ? " \u25BE" : " \u25B4" : ""
13918
+ ]
13919
+ },
13920
+ field
13921
+ ))
13922
+ ] }),
13923
+ sortedItems.map((item) => {
13924
+ const isCurrent = item.tokenName === currentTokenName;
13925
+ const status = item.status?.toUpperCase();
13926
+ const statusLabel = status === "PENDING" ? "Preparing" : status === "CLOSED" ? "Closed" : status === "CANCELLED" ? "Cancelled" : null;
13927
+ const price = fmtPrice(item.price);
13928
+ const change = item.changePercent;
13929
+ const vol = fmtWholeUsd(item.volume24h);
13930
+ const val = fmtWholeUsd(item.propertyValue);
13931
+ return /* @__PURE__ */ jsxRuntime.jsx(
13932
+ IPOOption,
13933
+ {
13934
+ "data-selector-row": item.tokenName,
13935
+ onClick: () => {
13936
+ if (!isCurrent && onSelect) {
13937
+ onSelect(item.tokenName);
13938
+ }
13939
+ setIsDropdownOpen(false);
13940
+ },
13941
+ $selected: isCurrent,
13942
+ style: {
13943
+ cursor: isCurrent ? "default" : "pointer",
13944
+ // Arena gold for competition assets — the same restrained cue as
13945
+ // the home Overview row (gold left crust + pooled spotlight, no
13946
+ // badge). backgroundImage LONGHAND: jsdom drops gradients from
13947
+ // the shorthand and UI6-AS-508 asserts it.
13948
+ ...item.isCompetition ? {
13949
+ // Straight crust bar — an inset box-shadow hugged the
13950
+ // row's rounded corners and read as a curved rim.
13951
+ // Left corners squared so the bar runs dead straight
13952
+ // like the home Overview arena row; right side keeps
13953
+ // the row rounding.
13954
+ borderLeft: "3px solid #E0B377",
13955
+ borderRadius: "0 7px 7px 0",
13956
+ backgroundImage: "radial-gradient(140% 90% at 0% 50%, rgba(224, 179, 119, 0.18) 0%, rgba(224, 179, 119, 0.06) 40%, transparent 68%)"
13957
+ } : {}
13958
+ },
13959
+ children: hasMarketData ? /* @__PURE__ */ jsxRuntime.jsxs(MarketRowInner, { children: [
13960
+ /* @__PURE__ */ jsxRuntime.jsxs(IdentityCell, { children: [
13961
+ item.imageUrl && /* @__PURE__ */ jsxRuntime.jsx(IPOOptionThumb, { src: item.imageUrl, alt: displayName(item) }),
13962
+ /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionIdentity, { children: [
13963
+ /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionName, { children: [
13964
+ /* @__PURE__ */ jsxRuntime.jsx(MarketTicker, { children: (item.ticker || displayName(item)).toUpperCase() }),
13965
+ item.typeBadge && /* @__PURE__ */ jsxRuntime.jsx(TypePill, { style: { color: item.typeBadge.color, background: item.typeBadge.background }, children: item.typeBadge.label }),
13966
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(CompetitionBadge, { children: item.badge })
13967
+ ] }),
13968
+ /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionLocation, { children: [
13969
+ item.streetAddress,
13970
+ statusLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: statusLabel })
13971
+ ] })
13972
+ ] })
13973
+ ] }),
13974
+ /* @__PURE__ */ jsxRuntime.jsx(PriceCell, { children: price ?? "\u2014" }),
13975
+ change != null ? /* @__PURE__ */ jsxRuntime.jsxs(ChangeCell, { $positive: change >= 0, children: [
13976
+ change >= 0 ? "+" : "",
13977
+ change.toFixed(2),
13978
+ "%"
13979
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(MutedCell, { children: "\u2014" }),
13980
+ /* @__PURE__ */ jsxRuntime.jsx(MutedCell, { $hideOnPhone: true, children: vol ?? "\u2014" }),
13981
+ /* @__PURE__ */ jsxRuntime.jsx(MutedCell, { $hideOnPhone: true, children: val ?? "\u2014" })
13982
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionInner, { children: [
13983
+ item.imageUrl && /* @__PURE__ */ jsxRuntime.jsx(IPOOptionThumb, { src: item.imageUrl, alt: displayName(item) }),
13984
+ /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionIdentity, { children: [
13985
+ /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionName, { children: [
13986
+ displayName(item),
13987
+ item.ticker ? ` (${item.ticker})` : "",
13988
+ item.badge && /* @__PURE__ */ jsxRuntime.jsx(CompetitionBadge, { children: item.badge })
13989
+ ] }),
13990
+ /* @__PURE__ */ jsxRuntime.jsxs(IPOOptionLocation, { children: [
13991
+ item.streetAddress,
13992
+ item.suburb ? `, ${item.suburb}` : "",
13993
+ statusLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: statusLabel })
13994
+ ] })
13995
+ ] })
13996
+ ] })
13997
+ },
13998
+ item.tokenName
13999
+ );
14000
+ })
14001
+ ]
14002
+ }
14003
+ ),
14004
+ document.body
14005
+ )
12912
14006
  ] }) });
12913
14007
  }
12914
14008
  var AssetSelectorWrapper = styled10__default.default.div`
@@ -12970,7 +14064,9 @@ var AssetSelectorDropdown = styled10__default.default.div`
12970
14064
  padding: ${(p) => p.$flush ? "0.25rem 0" : "0.5rem"};
12971
14065
  border-radius: 8px;
12972
14066
  transition: ${(p) => p.$flush ? "none" : "all 0.2s ease"};
12973
- flex: 0 1 auto;
14067
+ /* $noShrink (compactName): a four-letter ticker is already the floor — it must
14068
+ never clip to "Y" when the bar is starved; the trailing scrolls instead. */
14069
+ flex: ${(p) => p.$noShrink ? "0 0 auto" : "0 1 auto"};
12974
14070
  min-width: 0;
12975
14071
  overflow: hidden;
12976
14072
  &:hover { background-color: ${(p) => p.$flush ? "transparent" : "rgba(255,255,255,0.05)"}; }
@@ -13027,6 +14123,35 @@ var AssetName = styled10__default.default.div`
13027
14123
  svg { margin-left: 0.4rem; width: 16px; height: 16px; }
13028
14124
  }
13029
14125
  `;
14126
+ var CompactName = styled10__default.default.span`
14127
+ white-space: nowrap;
14128
+ letter-spacing: 0.01em;
14129
+ `;
14130
+ var NameTip = styled10__default.default.div`
14131
+ background: #1a1d24;
14132
+ border: 1px solid rgba(255, 255, 255, 0.1);
14133
+ border-radius: 8px;
14134
+ padding: 0.45rem 0.7rem;
14135
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
14136
+ pointer-events: none;
14137
+ white-space: nowrap;
14138
+ color: #fff;
14139
+ font-size: 0.78rem;
14140
+ font-weight: 600;
14141
+ letter-spacing: -0.01em;
14142
+ &::before {
14143
+ content: '';
14144
+ position: absolute;
14145
+ top: -5px;
14146
+ left: 50%;
14147
+ transform: translateX(-50%) rotate(45deg);
14148
+ width: 8px;
14149
+ height: 8px;
14150
+ background: #1a1d24;
14151
+ border-left: 1px solid rgba(255, 255, 255, 0.1);
14152
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
14153
+ }
14154
+ `;
13030
14155
  var SelectorMetrics = styled10__default.default.div`
13031
14156
  display: flex;
13032
14157
  align-items: center;
@@ -13047,6 +14172,12 @@ var SelectorMetrics = styled10__default.default.div`
13047
14172
  padding: 0.4rem 0.5rem;
13048
14173
  }
13049
14174
  `;
14175
+ var AfterNameSlot = styled10__default.default.div`
14176
+ display: flex;
14177
+ align-items: center;
14178
+ flex-shrink: 0;
14179
+ min-width: 0;
14180
+ `;
13050
14181
  var TrailingWrapper = styled10__default.default.div`
13051
14182
  display: flex;
13052
14183
  align-items: center;
@@ -13118,14 +14249,16 @@ var IPODropdown = styled10__default.default.div`
13118
14249
  position: absolute;
13119
14250
  top: calc(100% + 6px);
13120
14251
  left: 0;
13121
- width: 320px;
14252
+ width: ${(p) => p.$wide ? "min(660px, calc(100vw - 24px))" : "320px"};
13122
14253
  background: #0d0d0f;
13123
14254
  border-radius: 10px;
13124
14255
  box-shadow: 0 12px 32px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.06);
13125
14256
  z-index: 1000;
13126
- max-height: 320px;
14257
+ max-height: 360px;
13127
14258
  overflow-y: auto;
13128
- padding: 4px;
14259
+ /* Market mode: NO top padding — the sticky header must sit flush against the
14260
+ container's top edge so scrolling rows can never peek above/behind it. */
14261
+ padding: ${(p) => p.$wide ? "0 0 4px" : "4px"};
13129
14262
 
13130
14263
  scrollbar-width: thin;
13131
14264
  scrollbar-color: rgba(255,255,255,0.12) transparent;
@@ -13133,8 +14266,8 @@ var IPODropdown = styled10__default.default.div`
13133
14266
  &::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 2px; }
13134
14267
 
13135
14268
  @media (max-width: 480px) {
13136
- width: 280px;
13137
- max-height: 260px;
14269
+ width: ${(p) => p.$wide ? "min(360px, calc(100vw - 16px))" : "280px"};
14270
+ max-height: 300px;
13138
14271
  border-radius: 8px;
13139
14272
  }
13140
14273
  animation: slideDown 0.2s cubic-bezier(0.16,1,0.3,1);
@@ -13143,6 +14276,99 @@ var IPODropdown = styled10__default.default.div`
13143
14276
  to { opacity: 1; transform: translateY(0); }
13144
14277
  }
13145
14278
  `;
14279
+ var MARKET_GRID = "minmax(0, 1fr) 76px 92px 108px 118px";
14280
+ var MARKET_GRID_PHONE = "minmax(0, 1fr) 76px 92px";
14281
+ var HeaderRow = styled10__default.default.div`
14282
+ position: sticky;
14283
+ top: 0;
14284
+ z-index: 2;
14285
+ display: grid;
14286
+ grid-template-columns: ${MARKET_GRID};
14287
+ gap: 10px;
14288
+ align-items: center;
14289
+ padding: 0.5rem 0.85rem 0.45rem;
14290
+ background: #0d0d0f;
14291
+ border-bottom: 1px solid rgba(255,255,255,0.06);
14292
+
14293
+ @media (max-width: 480px) { grid-template-columns: ${MARKET_GRID_PHONE}; }
14294
+ `;
14295
+ var HeaderLabel = styled10__default.default.span`
14296
+ font-size: 0.6rem;
14297
+ font-weight: 600;
14298
+ letter-spacing: 0.08em;
14299
+ text-transform: uppercase;
14300
+ color: rgba(255,255,255,0.45);
14301
+ white-space: nowrap;
14302
+ `;
14303
+ var SortButton = styled10__default.default.button`
14304
+ background: none;
14305
+ border: none;
14306
+ padding: 0;
14307
+ cursor: pointer;
14308
+ font-family: inherit;
14309
+ font-size: 0.6rem;
14310
+ font-weight: 600;
14311
+ letter-spacing: 0.08em;
14312
+ text-transform: uppercase;
14313
+ white-space: nowrap;
14314
+ /* Left-aligned like every other column (user call, 2026-08-20). */
14315
+ text-align: left;
14316
+ justify-self: start;
14317
+ color: ${(p) => p.$active ? "var(--color-accent, #E6C87E)" : "rgba(255,255,255,0.45)"};
14318
+ transition: color 0.15s ease;
14319
+ &:hover { color: ${(p) => p.$active ? "var(--color-accent, #E6C87E)" : "rgba(255,255,255,0.75)"}; }
14320
+
14321
+ @media (max-width: 480px) {
14322
+ display: ${(p) => p.$hideOnPhone ? "none" : "inline"};
14323
+ }
14324
+ `;
14325
+ var IPOOptionIdentity = styled10__default.default.div`
14326
+ flex: 1 1 0;
14327
+ min-width: 0;
14328
+ overflow: hidden;
14329
+ `;
14330
+ var MarketRowInner = styled10__default.default.div`
14331
+ display: grid;
14332
+ grid-template-columns: ${MARKET_GRID};
14333
+ gap: 10px;
14334
+ align-items: center;
14335
+
14336
+ @media (max-width: 480px) { grid-template-columns: ${MARKET_GRID_PHONE}; }
14337
+ `;
14338
+ var IdentityCell = styled10__default.default.div`
14339
+ display: flex;
14340
+ align-items: center;
14341
+ gap: 0.65rem;
14342
+ min-width: 0;
14343
+ `;
14344
+ var PriceCell = styled10__default.default.span`
14345
+ font-size: 0.8rem;
14346
+ font-weight: 600;
14347
+ color: #fff;
14348
+ font-variant-numeric: tabular-nums;
14349
+ white-space: nowrap;
14350
+ text-align: left;
14351
+ `;
14352
+ var ChangeCell = styled10__default.default.span`
14353
+ font-size: 0.72rem;
14354
+ font-weight: 600;
14355
+ color: ${(p) => p.$positive ? "#0ecb81" : "#f6465d"};
14356
+ font-variant-numeric: tabular-nums;
14357
+ white-space: nowrap;
14358
+ text-align: left;
14359
+ `;
14360
+ var MutedCell = styled10__default.default.span`
14361
+ font-size: 0.72rem;
14362
+ /* Same ink as the price column (user call, 2026-08-20). */
14363
+ color: #fff;
14364
+ font-variant-numeric: tabular-nums;
14365
+ white-space: nowrap;
14366
+ text-align: left;
14367
+
14368
+ @media (max-width: 480px) {
14369
+ display: ${(p) => p.$hideOnPhone ? "none" : "inline"};
14370
+ }
14371
+ `;
13146
14372
  var IPOOption = styled10__default.default.div`
13147
14373
  padding: 0.6rem 0.75rem;
13148
14374
  transition: background 0.15s ease;
@@ -13168,6 +14394,25 @@ var IPOOptionName = styled10__default.default.div`
13168
14394
  font-size: 0.82rem;
13169
14395
  color: ${"#ebebeb"};
13170
14396
  line-height: 1.3;
14397
+ /* One line like the location — wrapped names made market rows uneven. */
14398
+ white-space: nowrap;
14399
+ overflow: hidden;
14400
+ text-overflow: ellipsis;
14401
+ `;
14402
+ var MarketTicker = styled10__default.default.span`
14403
+ font-weight: 700;
14404
+ letter-spacing: 0.01em;
14405
+ `;
14406
+ var TypePill = styled10__default.default.span`
14407
+ margin-left: 0.45rem;
14408
+ font-size: 0.55rem;
14409
+ font-weight: 700;
14410
+ letter-spacing: 0.08em;
14411
+ text-transform: uppercase;
14412
+ padding: 1px 5px;
14413
+ border-radius: 3px;
14414
+ vertical-align: middle;
14415
+ white-space: nowrap;
13171
14416
  `;
13172
14417
  var CompetitionBadge = styled10__default.default.span`
13173
14418
  margin-left: 0.4rem;
@@ -13186,6 +14431,11 @@ var IPOOptionLocation = styled10__default.default.div`
13186
14431
  font-size: 0.72rem;
13187
14432
  color: rgba(255,255,255,0.38);
13188
14433
  margin-top: 1px;
14434
+ /* One line, ellipsized — a long address must never wrap the row taller
14435
+ (matches the deployed dropdown's compact rows). */
14436
+ white-space: nowrap;
14437
+ overflow: hidden;
14438
+ text-overflow: ellipsis;
13189
14439
  span {
13190
14440
  margin-left: 0.4rem;
13191
14441
  color: var(--color-accent, #E6C87E);
@@ -13219,10 +14469,10 @@ var SlideOld = styled10__default.default.span`
13219
14469
  animation: ${slideOut} 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards;
13220
14470
  `;
13221
14471
  function SlideDigit({ value }) {
13222
- const prevRef = React5.useRef(value);
13223
- const [prev, setPrev] = React5.useState(null);
13224
- const [animKey, setAnimKey] = React5.useState(0);
13225
- React5.useEffect(() => {
14472
+ const prevRef = React9.useRef(value);
14473
+ const [prev, setPrev] = React9.useState(null);
14474
+ const [animKey, setAnimKey] = React9.useState(0);
14475
+ React9.useEffect(() => {
13226
14476
  if (value !== prevRef.current) {
13227
14477
  setPrev(prevRef.current);
13228
14478
  prevRef.current = value;
@@ -13262,15 +14512,15 @@ function OfferingProgressCard({
13262
14512
  style,
13263
14513
  className
13264
14514
  }) {
13265
- const [currentTime, setCurrentTime] = React5.useState(/* @__PURE__ */ new Date());
13266
- const [countdown, setCountdown] = React5.useState(null);
14515
+ const [currentTime, setCurrentTime] = React9.useState(/* @__PURE__ */ new Date());
14516
+ const [countdown, setCountdown] = React9.useState(null);
13267
14517
  const computedRaised = raisedAmount ?? totalSold * tokenPrice;
13268
14518
  const computedTarget = targetAmount ?? supplyToSell * tokenPrice;
13269
- React5.useEffect(() => {
14519
+ React9.useEffect(() => {
13270
14520
  const timer = setInterval(() => setCurrentTime(/* @__PURE__ */ new Date()), 1e3);
13271
14521
  return () => clearInterval(timer);
13272
14522
  }, []);
13273
- const [tradingCountdown, setTradingCountdown] = React5.useState(null);
14523
+ const [tradingCountdown, setTradingCountdown] = React9.useState(null);
13274
14524
  const calcCountdownFrom = (target) => {
13275
14525
  const now = Math.floor(Date.now() / 1e3);
13276
14526
  const diff = target - now;
@@ -13282,7 +14532,7 @@ function OfferingProgressCard({
13282
14532
  seconds: diff % 60
13283
14533
  };
13284
14534
  };
13285
- React5.useEffect(() => {
14535
+ React9.useEffect(() => {
13286
14536
  if (!opensAt) {
13287
14537
  setCountdown(null);
13288
14538
  return;
@@ -13291,7 +14541,7 @@ function OfferingProgressCard({
13291
14541
  const interval = setInterval(() => setCountdown(calcCountdownFrom(opensAt)), 1e3);
13292
14542
  return () => clearInterval(interval);
13293
14543
  }, [opensAt]);
13294
- React5.useEffect(() => {
14544
+ React9.useEffect(() => {
13295
14545
  if (!tradingStartsAt) {
13296
14546
  setTradingCountdown(null);
13297
14547
  return;
@@ -13785,8 +15035,8 @@ var HomeSpinner = styled10__default.default.span`
13785
15035
  }
13786
15036
  `;
13787
15037
  function useCountdown(opensAt) {
13788
- const [now, setNow] = React5.useState(() => Math.floor(Date.now() / 1e3));
13789
- React5.useEffect(() => {
15038
+ const [now, setNow] = React9.useState(() => Math.floor(Date.now() / 1e3));
15039
+ React9.useEffect(() => {
13790
15040
  if (opensAt == null) return;
13791
15041
  const id = setInterval(() => setNow(Math.floor(Date.now() / 1e3)), 1e3);
13792
15042
  return () => clearInterval(id);
@@ -13836,10 +15086,10 @@ function OrderPanel({
13836
15086
  toast
13837
15087
  }) {
13838
15088
  const countdown = useCountdown(opensAt);
13839
- const [payInputValue, setPayInputValue] = React5.useState("");
13840
- const [receiveInputValue, setReceiveInputValue] = React5.useState("");
13841
- const [isPayInputFocused, setIsPayInputFocused] = React5.useState(false);
13842
- const [isReceiveInputFocused, setIsReceiveInputFocused] = React5.useState(false);
15089
+ const [payInputValue, setPayInputValue] = React9.useState("");
15090
+ const [receiveInputValue, setReceiveInputValue] = React9.useState("");
15091
+ const [isPayInputFocused, setIsPayInputFocused] = React9.useState(false);
15092
+ const [isReceiveInputFocused, setIsReceiveInputFocused] = React9.useState(false);
13843
15093
  const handlePayBlur = () => {
13844
15094
  setIsPayInputFocused(false);
13845
15095
  const parsed = parseInt(payInputValue.replace(/,/g, "").replace(/[^0-9]/g, ""), 10) || 0;
@@ -14865,7 +16115,7 @@ function OrderConfirmationModal({
14865
16115
  isPlacing = false,
14866
16116
  placingLabel = "Placing order\u2026"
14867
16117
  }) {
14868
- const [dontShowAgain, setDontShowAgain] = React5.useState(false);
16118
+ const [dontShowAgain, setDontShowAgain] = React9.useState(false);
14869
16119
  if (!open) return null;
14870
16120
  const handleOverlayClose = () => {
14871
16121
  if (isPlacing) return;
@@ -15317,14 +16567,14 @@ function PortfolioActivityPanel({
15317
16567
  style
15318
16568
  }) {
15319
16569
  const resolvedDefaultTab = defaultTab ?? (showPositionsTab ? "positions" : showSubscriptionsTab ? "subscriptions" : "orders");
15320
- const [activeTab, setActiveTab] = React5.useState(resolvedDefaultTab);
15321
- const [currentPage, setCurrentPage] = React5.useState(0);
15322
- const [pendingCancelOrderId, setPendingCancelOrderId] = React5.useState(null);
15323
- const [cancelAllConfirmOpen, setCancelAllConfirmOpen] = React5.useState(false);
15324
- const [cancellingAll, setCancellingAll] = React5.useState(false);
15325
- const [closeAllOpen, setCloseAllOpen] = React5.useState(false);
15326
- const [closeAllType, setCloseAllType] = React5.useState("market");
15327
- const [closingAll, setClosingAll] = React5.useState(false);
16570
+ const [activeTab, setActiveTab] = React9.useState(resolvedDefaultTab);
16571
+ const [currentPage, setCurrentPage] = React9.useState(0);
16572
+ const [pendingCancelOrderId, setPendingCancelOrderId] = React9.useState(null);
16573
+ const [cancelAllConfirmOpen, setCancelAllConfirmOpen] = React9.useState(false);
16574
+ const [cancellingAll, setCancellingAll] = React9.useState(false);
16575
+ const [closeAllOpen, setCloseAllOpen] = React9.useState(false);
16576
+ const [closeAllType, setCloseAllType] = React9.useState("market");
16577
+ const [closingAll, setClosingAll] = React9.useState(false);
15328
16578
  const settlingPositionIds = positions.filter((p) => p.settling).map((p) => p.propertyId);
15329
16579
  const settlingKey = settlingPositionIds.join(",");
15330
16580
  const settlingTradeStartByProperty = /* @__PURE__ */ new Map();
@@ -15337,9 +16587,9 @@ function PortfolioActivityPanel({
15337
16587
  if (earliest === void 0 || startedAt < earliest) settlingTradeStartByProperty.set(trade.propertyId, startedAt);
15338
16588
  }
15339
16589
  const tradeDeadlineKey = settlingTradeDeadlines.join(",");
15340
- const settlingSinceRef = React5.useRef(/* @__PURE__ */ new Map());
15341
- const [now, setNow] = React5.useState(() => Date.now());
15342
- React5.useEffect(() => {
16590
+ const settlingSinceRef = React9.useRef(/* @__PURE__ */ new Map());
16591
+ const [now, setNow] = React9.useState(() => Date.now());
16592
+ React9.useEffect(() => {
15343
16593
  const since = settlingSinceRef.current;
15344
16594
  const seenAt = Date.now();
15345
16595
  for (const id of settlingPositionIds) if (!since.has(id)) since.set(id, seenAt);
@@ -15347,7 +16597,7 @@ function PortfolioActivityPanel({
15347
16597
  setNow(seenAt);
15348
16598
  }, [settlingKey]);
15349
16599
  const positionSettlingStart = (propertyId) => settlingTradeStartByProperty.get(propertyId) ?? settlingSinceRef.current.get(propertyId) ?? now;
15350
- React5.useEffect(() => {
16600
+ React9.useEffect(() => {
15351
16601
  const pending = [
15352
16602
  ...settlingPositionIds.map((id) => positionSettlingStart(id) + STUCK_SETTLING_MS),
15353
16603
  ...settlingTradeDeadlines
@@ -15360,8 +16610,8 @@ function PortfolioActivityPanel({
15360
16610
  const isPositionStuck = (pos) => !!pos.settling && now - positionSettlingStart(pos.propertyId) >= STUCK_SETTLING_MS;
15361
16611
  const isTradeStuck = (trade) => now - toMillis(trade.executedAt) >= STUCK_SETTLING_MS;
15362
16612
  const hasPositionActions = !!(onClosePosition || onSharePosition || onCloseAllPositions);
15363
- const [posSortKey, setPosSortKey] = React5.useState("asset");
15364
- const [posSortAsc, setPosSortAsc] = React5.useState(true);
16613
+ const [posSortKey, setPosSortKey] = React9.useState("asset");
16614
+ const [posSortAsc, setPosSortAsc] = React9.useState(true);
15365
16615
  const handlePosSort = (key) => {
15366
16616
  if (posSortKey === key) {
15367
16617
  setPosSortAsc((v) => !v);
@@ -15370,9 +16620,9 @@ function PortfolioActivityPanel({
15370
16620
  setPosSortAsc(key === "asset");
15371
16621
  }
15372
16622
  };
15373
- const [expandedPositions, setExpandedPositions] = React5.useState(/* @__PURE__ */ new Set());
15374
- const [allExpanded, setAllExpanded] = React5.useState(false);
15375
- const [sortDropdownOpen, setSortDropdownOpen] = React5.useState(false);
16623
+ const [expandedPositions, setExpandedPositions] = React9.useState(/* @__PURE__ */ new Set());
16624
+ const [allExpanded, setAllExpanded] = React9.useState(false);
16625
+ const [sortDropdownOpen, setSortDropdownOpen] = React9.useState(false);
15376
16626
  const togglePosition = (tokenName) => {
15377
16627
  setExpandedPositions((prev) => {
15378
16628
  const next = new Set(prev);
@@ -15381,7 +16631,7 @@ function PortfolioActivityPanel({
15381
16631
  return next;
15382
16632
  });
15383
16633
  };
15384
- const [expandedOpenOrders, setExpandedOpenOrders] = React5.useState(/* @__PURE__ */ new Set());
16634
+ const [expandedOpenOrders, setExpandedOpenOrders] = React9.useState(/* @__PURE__ */ new Set());
15385
16635
  const toggleOpenOrder = (id) => {
15386
16636
  setExpandedOpenOrders((prev) => {
15387
16637
  const next = new Set(prev);
@@ -15390,7 +16640,7 @@ function PortfolioActivityPanel({
15390
16640
  return next;
15391
16641
  });
15392
16642
  };
15393
- const [expandedRows, setExpandedRows] = React5.useState(/* @__PURE__ */ new Set());
16643
+ const [expandedRows, setExpandedRows] = React9.useState(/* @__PURE__ */ new Set());
15394
16644
  const toggleRow = (key) => {
15395
16645
  setExpandedRows((prev) => {
15396
16646
  const next = new Set(prev);
@@ -15418,7 +16668,7 @@ function PortfolioActivityPanel({
15418
16668
  }
15419
16669
  };
15420
16670
  const sortKeys = ["asset", "units", "value", "avgPrice", "currentPrice", "pnl"];
15421
- const sortedPositions = React5.useMemo(() => {
16671
+ const sortedPositions = React9.useMemo(() => {
15422
16672
  const arr = [...positions];
15423
16673
  const dir = posSortAsc ? 1 : -1;
15424
16674
  arr.sort((a, b) => {
@@ -15453,7 +16703,7 @@ function PortfolioActivityPanel({
15453
16703
  setAllExpanded(true);
15454
16704
  }
15455
16705
  };
15456
- const mergedOrderHistory = React5.useMemo(() => {
16706
+ const mergedOrderHistory = React9.useMemo(() => {
15457
16707
  if (showSubscriptionsTab || offeringOrders.length === 0) {
15458
16708
  return [...orderHistory].sort((a, b) => b.createdAt - a.createdAt);
15459
16709
  }
@@ -15478,32 +16728,32 @@ function PortfolioActivityPanel({
15478
16728
  }));
15479
16729
  return [...orderHistory, ...mapped].sort((a, b) => b.createdAt - a.createdAt);
15480
16730
  }, [showSubscriptionsTab, offeringOrders, orderHistory]);
15481
- const sortedOpenOrders = React5.useMemo(
16731
+ const sortedOpenOrders = React9.useMemo(
15482
16732
  () => [...openOrders].sort((a, b) => b.createdAt - a.createdAt),
15483
16733
  [openOrders]
15484
16734
  );
15485
- const sortedOfferingOrders = React5.useMemo(
16735
+ const sortedOfferingOrders = React9.useMemo(
15486
16736
  () => [...offeringOrders].sort((a, b) => b.createdAt - a.createdAt),
15487
16737
  [offeringOrders]
15488
16738
  );
15489
- const sortedTradeHistory = React5.useMemo(
16739
+ const sortedTradeHistory = React9.useMemo(
15490
16740
  () => [...tradeHistory].sort((a, b) => b.executedAt - a.executedAt),
15491
16741
  [tradeHistory]
15492
16742
  );
15493
- const sortedTransfers = React5.useMemo(
16743
+ const sortedTransfers = React9.useMemo(
15494
16744
  () => [...transfers].sort((a, b) => b.createdAt - a.createdAt),
15495
16745
  [transfers]
15496
16746
  );
15497
16747
  const positionsCount = positions.length;
15498
- const openOrdersCount = React5.useMemo(
16748
+ const openOrdersCount = React9.useMemo(
15499
16749
  () => openOrders.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
15500
16750
  [openOrders]
15501
16751
  );
15502
- const pendingHistoryCount = React5.useMemo(
16752
+ const pendingHistoryCount = React9.useMemo(
15503
16753
  () => mergedOrderHistory.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
15504
16754
  [mergedOrderHistory]
15505
16755
  );
15506
- const pendingOfferingsCount = React5.useMemo(
16756
+ const pendingOfferingsCount = React9.useMemo(
15507
16757
  () => offeringOrders.filter((o) => {
15508
16758
  const s = o.status.toUpperCase();
15509
16759
  return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
@@ -16350,7 +17600,7 @@ var ContentScroll = styled10__default.default.div`
16350
17600
  `;
16351
17601
  var TabContainer = styled10__default.default.div`
16352
17602
  display: flex;
16353
- gap: 0;
17603
+ gap: 1rem;
16354
17604
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
16355
17605
  margin-bottom: 0.75rem;
16356
17606
  overflow-x: auto;
@@ -16362,12 +17612,12 @@ var TabContainer = styled10__default.default.div`
16362
17612
  var Tab = styled10__default.default.button`
16363
17613
  background: transparent;
16364
17614
  border: none;
16365
- padding: 0.6rem 1rem;
16366
- font-size: 0.75rem;
17615
+ padding: 0 0 0.5rem;
17616
+ font-size: 0.8rem;
16367
17617
  font-weight: 500;
16368
17618
  white-space: nowrap;
16369
17619
  flex-shrink: 0;
16370
- color: ${({ $active }) => $active ? "#E6C87E" : "rgba(255, 255, 255, 0.4)"};
17620
+ color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.6)"};
16371
17621
  cursor: pointer;
16372
17622
  transition: color 0.15s;
16373
17623
  position: relative;
@@ -16380,12 +17630,11 @@ var Tab = styled10__default.default.button`
16380
17630
  right: 0;
16381
17631
  height: 2px;
16382
17632
  background: ${({ $active }) => $active ? "#E6C87E" : "transparent"};
16383
- border-radius: 1px;
16384
17633
  transition: background 0.15s;
16385
17634
  }
16386
17635
 
16387
17636
  &:hover {
16388
- color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
17637
+ color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.85)"};
16389
17638
  }
16390
17639
  `;
16391
17640
  var TabCount = styled10__default.default.span`
@@ -17104,17 +18353,17 @@ function PropertyBuy({
17104
18353
  videoUrl,
17105
18354
  toast
17106
18355
  }) {
17107
- const [sliderValue, setSliderValue] = React5.useState(0);
17108
- const [availableBalance, setAvailableBalance] = React5.useState(walletUsdcBalance ?? 0);
17109
- const [manualOrderAmount, setManualOrderAmount] = React5.useState(null);
17110
- const [ownedTokens, setOwnedTokens] = React5.useState(0);
17111
- const [displayedOwnedTokens, setDisplayedOwnedTokens] = React5.useState(0);
17112
- const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React5.useState(false);
17113
- const [lastOrderQuantity, setLastOrderQuantity] = React5.useState(0);
17114
- const [orderPendingAllocation, setOrderPendingAllocation] = React5.useState(false);
17115
- const [orderPlacedSuccess, setOrderPlacedSuccess] = React5.useState(false);
17116
- const [lastOrderDetails, setLastOrderDetails] = React5.useState(null);
17117
- const [showOrderConfirmModal, setShowOrderConfirmModal] = React5.useState(false);
18356
+ const [sliderValue, setSliderValue] = React9.useState(0);
18357
+ const [availableBalance, setAvailableBalance] = React9.useState(walletUsdcBalance ?? 0);
18358
+ const [manualOrderAmount, setManualOrderAmount] = React9.useState(null);
18359
+ const [ownedTokens, setOwnedTokens] = React9.useState(0);
18360
+ const [displayedOwnedTokens, setDisplayedOwnedTokens] = React9.useState(0);
18361
+ const [ownedTokensJustUpdated, setOwnedTokensJustUpdated] = React9.useState(false);
18362
+ const [lastOrderQuantity, setLastOrderQuantity] = React9.useState(0);
18363
+ const [orderPendingAllocation, setOrderPendingAllocation] = React9.useState(false);
18364
+ const [orderPlacedSuccess, setOrderPlacedSuccess] = React9.useState(false);
18365
+ const [lastOrderDetails, setLastOrderDetails] = React9.useState(null);
18366
+ const [showOrderConfirmModal, setShowOrderConfirmModal] = React9.useState(false);
17118
18367
  const tokenPrice = saleData?.tokenPrice ?? 250;
17119
18368
  const feeRate = (saleData?.feePercent ?? 0.5) / 100;
17120
18369
  const totalSold = saleData?.totalSold ?? 0;
@@ -17134,12 +18383,12 @@ function PropertyBuy({
17134
18383
  const orderTotal = tokenQuantity * tokenPrice + feeInUsd;
17135
18384
  const estExposure = (tokenQuantity / supplyToSell * 100).toFixed(4);
17136
18385
  const hasInsufficientFunds = orderTotal > availableBalance;
17137
- React5.useEffect(() => {
18386
+ React9.useEffect(() => {
17138
18387
  if (walletUsdcBalance != null) {
17139
18388
  setAvailableBalance(walletUsdcBalance);
17140
18389
  }
17141
18390
  }, [walletUsdcBalance]);
17142
- React5.useEffect(() => {
18391
+ React9.useEffect(() => {
17143
18392
  if (walletPropertyTokenBalance != null) {
17144
18393
  setOwnedTokens(walletPropertyTokenBalance);
17145
18394
  setDisplayedOwnedTokens(walletPropertyTokenBalance);
@@ -17155,17 +18404,17 @@ function PropertyBuy({
17155
18404
  }
17156
18405
  setShowOrderConfirmModal(true);
17157
18406
  };
17158
- React5.useEffect(() => {
18407
+ React9.useEffect(() => {
17159
18408
  if (purchaseStatus === "success" && orderPendingAllocation) {
17160
18409
  setOrderPendingAllocation(false);
17161
18410
  setOrderPlacedSuccess(true);
17162
18411
  }
17163
18412
  }, [purchaseStatus, orderPendingAllocation]);
17164
- const handlePlaceAnotherOrder = React5.useCallback(() => {
18413
+ const handlePlaceAnotherOrder = React9.useCallback(() => {
17165
18414
  setOrderPlacedSuccess(false);
17166
18415
  setOrderPendingAllocation(false);
17167
18416
  }, []);
17168
- const sortedOrders = React5.useMemo(
18417
+ const sortedOrders = React9.useMemo(
17169
18418
  () => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
17170
18419
  [recentOrders]
17171
18420
  );
@@ -17735,7 +18984,7 @@ function PaymentPopup({
17735
18984
  userTokenHoldings,
17736
18985
  propertyName
17737
18986
  }) {
17738
- const [selectedPaymentMethod, setSelectedPaymentMethod] = React5.useState(
18987
+ const [selectedPaymentMethod, setSelectedPaymentMethod] = React9.useState(
17739
18988
  "tokens"
17740
18989
  );
17741
18990
  if (!isOpen) return null;
@@ -17914,20 +19163,20 @@ function PaymentPopup({
17914
19163
  var payment_popup_default = PaymentPopup;
17915
19164
  var SUMMER_MONTHS = /* @__PURE__ */ new Set([11, 0, 1]);
17916
19165
  var OwnerBooking = ({ propertyName, token }) => {
17917
- const today = React5.useMemo(() => {
19166
+ const today = React9.useMemo(() => {
17918
19167
  const base = /* @__PURE__ */ new Date();
17919
19168
  base.setHours(0, 0, 0, 0);
17920
19169
  return base;
17921
19170
  }, []);
17922
- const [currentYear, setCurrentYear] = React5.useState(today.getFullYear());
17923
- const [currentMonth, setCurrentMonth] = React5.useState(today.getMonth());
17924
- const [dateRanges, setDateRanges] = React5.useState([]);
17925
- const [selectedDates, setSelectedDates] = React5.useState([]);
17926
- const [hoverDate, setHoverDate] = React5.useState(null);
17927
- const [isDateSelectorOpen, setIsDateSelectorOpen] = React5.useState(false);
17928
- const [selectorYear, setSelectorYear] = React5.useState(today.getFullYear());
17929
- const [isPaymentPopupOpen, setIsPaymentPopupOpen] = React5.useState(false);
17930
- const dateSelectorRef = React5.useRef(null);
19171
+ const [currentYear, setCurrentYear] = React9.useState(today.getFullYear());
19172
+ const [currentMonth, setCurrentMonth] = React9.useState(today.getMonth());
19173
+ const [dateRanges, setDateRanges] = React9.useState([]);
19174
+ const [selectedDates, setSelectedDates] = React9.useState([]);
19175
+ const [hoverDate, setHoverDate] = React9.useState(null);
19176
+ const [isDateSelectorOpen, setIsDateSelectorOpen] = React9.useState(false);
19177
+ const [selectorYear, setSelectorYear] = React9.useState(today.getFullYear());
19178
+ const [isPaymentPopupOpen, setIsPaymentPopupOpen] = React9.useState(false);
19179
+ const dateSelectorRef = React9.useRef(null);
17931
19180
  const tokenPrice = token.price ?? 700;
17932
19181
  const userTokenHoldings = 2.2;
17933
19182
  const MIN_NIGHTS = 3;
@@ -17937,25 +19186,25 @@ var OwnerBooking = ({ propertyName, token }) => {
17937
19186
  { bg: "rgba(230, 126, 34, 0.25)", border: "rgba(230, 126, 34, 0.6)" },
17938
19187
  { bg: "rgba(46, 204, 113, 0.25)", border: "rgba(46, 204, 113, 0.6)" }
17939
19188
  ];
17940
- const calculateTokensPerDayOwner = React5.useCallback(() => {
19189
+ const calculateTokensPerDayOwner = React9.useCallback(() => {
17941
19190
  if (tokenPrice <= 0) return 0;
17942
19191
  const target = 650;
17943
19192
  const raw = target / tokenPrice;
17944
19193
  return Math.ceil(raw * 1e4) / 1e4;
17945
19194
  }, [tokenPrice]);
17946
- const calculateTokensPerDayMarket = React5.useCallback(() => {
19195
+ const calculateTokensPerDayMarket = React9.useCallback(() => {
17947
19196
  if (tokenPrice <= 0) return 0;
17948
19197
  const target = 900;
17949
19198
  const raw = target / tokenPrice;
17950
19199
  return Math.ceil(raw * 1e4) / 1e4;
17951
19200
  }, [tokenPrice]);
17952
19201
  const qualifiesForOwnerRate = userTokenHoldings >= 0.1;
17953
- const getTokensPerDay = React5.useCallback(
19202
+ const getTokensPerDay = React9.useCallback(
17954
19203
  () => calculateTokensPerDayOwner() ,
17955
19204
  [qualifiesForOwnerRate, calculateTokensPerDayOwner, calculateTokensPerDayMarket]
17956
19205
  );
17957
19206
  const getRateLabel = () => "Owner's Rate" ;
17958
- const selectionStats = React5.useMemo(() => {
19207
+ const selectionStats = React9.useMemo(() => {
17959
19208
  if (selectedDates.length !== 2) return null;
17960
19209
  const [a, b] = selectedDates;
17961
19210
  const start = a < b ? a : b;
@@ -17966,10 +19215,10 @@ var OwnerBooking = ({ propertyName, token }) => {
17966
19215
  const usd = tokens * tokenPrice;
17967
19216
  return { nights, tokensPerDay, tokens, usd, start, end };
17968
19217
  }, [selectedDates, getTokensPerDay, tokenPrice]);
17969
- const totalNights = React5.useMemo(() => dateRanges.reduce((sum, r) => sum + r.nights, 0), [dateRanges]);
17970
- const totalTokens = React5.useMemo(() => dateRanges.reduce((sum, r) => sum + r.tokens, 0), [dateRanges]);
19218
+ const totalNights = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.nights, 0), [dateRanges]);
19219
+ const totalTokens = React9.useMemo(() => dateRanges.reduce((sum, r) => sum + r.tokens, 0), [dateRanges]);
17971
19220
  const totalUSD = totalTokens * tokenPrice;
17972
- const generateCalendarDays = React5.useCallback(
19221
+ const generateCalendarDays = React9.useCallback(
17973
19222
  (year, month) => {
17974
19223
  const first = new Date(year, month, 1);
17975
19224
  const last = new Date(year, month + 1, 0);
@@ -17998,11 +19247,11 @@ var OwnerBooking = ({ propertyName, token }) => {
17998
19247
  },
17999
19248
  [today]
18000
19249
  );
18001
- const calendarDays = React5.useMemo(
19250
+ const calendarDays = React9.useMemo(
18002
19251
  () => generateCalendarDays(currentYear, currentMonth),
18003
19252
  [currentYear, currentMonth, generateCalendarDays]
18004
19253
  );
18005
- const isDateReserved = React5.useCallback(
19254
+ const isDateReserved = React9.useCallback(
18006
19255
  (date) => dateRanges.some((r) => date >= r.arrival && date <= r.departure),
18007
19256
  [dateRanges]
18008
19257
  );
@@ -18096,14 +19345,14 @@ var OwnerBooking = ({ propertyName, token }) => {
18096
19345
  "December"
18097
19346
  ];
18098
19347
  const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
18099
- const setMonthYear = React5.useCallback(
19348
+ const setMonthYear = React9.useCallback(
18100
19349
  (month, year) => {
18101
19350
  setCurrentMonth(month);
18102
19351
  setCurrentYear(year);
18103
19352
  },
18104
19353
  [setCurrentMonth, setCurrentYear]
18105
19354
  );
18106
- const shiftMonth = React5.useCallback(
19355
+ const shiftMonth = React9.useCallback(
18107
19356
  (direction) => {
18108
19357
  const delta = direction === "prev" ? -1 : 1;
18109
19358
  let newMonth = currentMonth + delta;
@@ -18120,7 +19369,7 @@ var OwnerBooking = ({ propertyName, token }) => {
18120
19369
  },
18121
19370
  [currentMonth, currentYear, setMonthYear]
18122
19371
  );
18123
- const jumpToNextAvailable = React5.useCallback(() => {
19372
+ const jumpToNextAvailable = React9.useCallback(() => {
18124
19373
  for (let offset = 1; offset <= 12; offset++) {
18125
19374
  const candidateMonth = (currentMonth + offset) % 12;
18126
19375
  if (!SUMMER_MONTHS.has(candidateMonth)) continue;
@@ -18137,7 +19386,7 @@ var OwnerBooking = ({ propertyName, token }) => {
18137
19386
  setMonthYear(month, selectorYear);
18138
19387
  setIsDateSelectorOpen(false);
18139
19388
  };
18140
- React5.useEffect(() => {
19389
+ React9.useEffect(() => {
18141
19390
  const handleClickOutside = (event) => {
18142
19391
  if (dateSelectorRef.current && !dateSelectorRef.current.contains(event.target)) {
18143
19392
  setIsDateSelectorOpen(false);
@@ -18570,8 +19819,8 @@ function PropertyValuation({
18570
19819
  offeringValuationValue,
18571
19820
  totalUnits
18572
19821
  }) {
18573
- const [hoveredSaleYear, setHoveredSaleYear] = React5.useState(null);
18574
- const gaugePosition = React5.useMemo(() => {
19822
+ const [hoveredSaleYear, setHoveredSaleYear] = React9.useState(null);
19823
+ const gaugePosition = React9.useMemo(() => {
18575
19824
  const under = valSummary?.undervaluedThreshold;
18576
19825
  const over = valSummary?.overvaluedThreshold;
18577
19826
  const price = tokenPriceValue;
@@ -18581,7 +19830,7 @@ function PropertyValuation({
18581
19830
  }
18582
19831
  return 50;
18583
19832
  }, [valSummary?.undervaluedThreshold, valSummary?.overvaluedThreshold, tokenPriceValue]);
18584
- const chartOptions = React5.useMemo(() => ({
19833
+ const chartOptions = React9.useMemo(() => ({
18585
19834
  responsive: true,
18586
19835
  maintainAspectRatio: false,
18587
19836
  onHover: (_event, elements) => {
@@ -18624,7 +19873,7 @@ function PropertyValuation({
18624
19873
  }
18625
19874
  }
18626
19875
  }), []);
18627
- const chartData = React5.useMemo(() => ({
19876
+ const chartData = React9.useMemo(() => ({
18628
19877
  labels: musgraveComparisonData.labels,
18629
19878
  datasets: musgraveComparisonData.datasets.map((dataset, index) => ({
18630
19879
  label: dataset.name,
@@ -18665,8 +19914,8 @@ function PropertyValuation({
18665
19914
  fill: false
18666
19915
  }))
18667
19916
  }), [hoveredSaleYear]);
18668
- const handleMarkerEnter = React5.useCallback((year) => setHoveredSaleYear(year), []);
18669
- const handleMarkerLeave = React5.useCallback(() => setHoveredSaleYear(null), []);
19917
+ const handleMarkerEnter = React9.useCallback((year) => setHoveredSaleYear(year), []);
19918
+ const handleMarkerLeave = React9.useCallback(() => setHoveredSaleYear(null), []);
18670
19919
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
18671
19920
  /* @__PURE__ */ jsxRuntime.jsx(ValuationHeading, { children: "Valuation Model" }),
18672
19921
  /* @__PURE__ */ jsxRuntime.jsxs(LoafPricingSection, { children: [
@@ -19591,20 +20840,20 @@ function PropertyPhotoGallery({
19591
20840
  );
19592
20841
  }
19593
20842
  function GalleryContent({ galleryImages, startIndex, startWithVideo, title, subtitle, onClose, videoUrl }) {
19594
- const [currentIndex, setCurrentIndex] = React5.useState(() => clampIndex(startIndex, galleryImages.length));
19595
- const [activeHotspotId, setActiveHotspotId] = React5.useState(null);
19596
- const [showVideo, setShowVideo] = React5.useState(startWithVideo ?? false);
19597
- const sliderRef = React5.useRef(null);
19598
- const [isDragging, setIsDragging] = React5.useState(false);
19599
- const wasDraggingRef = React5.useRef(false);
19600
- const touchStartX = React5.useRef(null);
19601
- const touchStartY = React5.useRef(null);
19602
- const isSwiping = React5.useRef(false);
19603
- const progress = React5.useMemo(() => {
20843
+ const [currentIndex, setCurrentIndex] = React9.useState(() => clampIndex(startIndex, galleryImages.length));
20844
+ const [activeHotspotId, setActiveHotspotId] = React9.useState(null);
20845
+ const [showVideo, setShowVideo] = React9.useState(startWithVideo ?? false);
20846
+ const sliderRef = React9.useRef(null);
20847
+ const [isDragging, setIsDragging] = React9.useState(false);
20848
+ const wasDraggingRef = React9.useRef(false);
20849
+ const touchStartX = React9.useRef(null);
20850
+ const touchStartY = React9.useRef(null);
20851
+ const isSwiping = React9.useRef(false);
20852
+ const progress = React9.useMemo(() => {
19604
20853
  if (galleryImages.length <= 1) return 0;
19605
20854
  return currentIndex / (galleryImages.length - 1) * 100;
19606
20855
  }, [currentIndex, galleryImages.length]);
19607
- React5.useEffect(() => {
20856
+ React9.useEffect(() => {
19608
20857
  document.body.style.overflow = "hidden";
19609
20858
  document.body.style.touchAction = "none";
19610
20859
  return () => {
@@ -19612,7 +20861,7 @@ function GalleryContent({ galleryImages, startIndex, startWithVideo, title, subt
19612
20861
  document.body.style.touchAction = "";
19613
20862
  };
19614
20863
  }, []);
19615
- React5.useEffect(() => {
20864
+ React9.useEffect(() => {
19616
20865
  const handleKey = (event) => {
19617
20866
  if (event.key === "Escape") onClose();
19618
20867
  if (event.key === "ArrowLeft") setCurrentIndex((i) => i === 0 ? galleryImages.length - 1 : i - 1);
@@ -20016,23 +21265,23 @@ function truncateHash(hash) {
20016
21265
  }
20017
21266
  var SWIPE_DISMISS_PX = 100;
20018
21267
  function ToastItem({ toast, onDismiss }) {
20019
- const [exiting, setExiting] = React5.useState(false);
20020
- const [dragX, setDragX] = React5.useState(0);
20021
- const [dragging, setDragging] = React5.useState(false);
20022
- const [touched, setTouched] = React5.useState(false);
20023
- const timerRef = React5.useRef(null);
20024
- const dragStartRef = React5.useRef(null);
20025
- const dragXRef = React5.useRef(0);
20026
- const dismiss = React5.useCallback(() => {
21268
+ const [exiting, setExiting] = React9.useState(false);
21269
+ const [dragX, setDragX] = React9.useState(0);
21270
+ const [dragging, setDragging] = React9.useState(false);
21271
+ const [touched, setTouched] = React9.useState(false);
21272
+ const timerRef = React9.useRef(null);
21273
+ const dragStartRef = React9.useRef(null);
21274
+ const dragXRef = React9.useRef(0);
21275
+ const dismiss = React9.useCallback(() => {
20027
21276
  setExiting(true);
20028
21277
  setTimeout(() => onDismiss(toast.id), 280);
20029
21278
  }, [onDismiss, toast.id]);
20030
- const armAutoDismiss = React5.useCallback(() => {
21279
+ const armAutoDismiss = React9.useCallback(() => {
20031
21280
  if (timerRef.current) clearTimeout(timerRef.current);
20032
21281
  const duration2 = toast.duration ?? 6e3;
20033
21282
  if (duration2 > 0) timerRef.current = setTimeout(dismiss, duration2);
20034
21283
  }, [dismiss, toast.duration]);
20035
- React5.useEffect(() => {
21284
+ React9.useEffect(() => {
20036
21285
  armAutoDismiss();
20037
21286
  return () => {
20038
21287
  if (timerRef.current) clearTimeout(timerRef.current);
@@ -20112,10 +21361,10 @@ function ToastItem({ toast, onDismiss }) {
20112
21361
  }
20113
21362
  );
20114
21363
  }
20115
- var ToastContext = React5.createContext(null);
21364
+ var ToastContext = React9.createContext(null);
20116
21365
  function ToastProvider({ children, maxVisible }) {
20117
- const [toasts, setToasts] = React5.useState([]);
20118
- const addToast = React5.useCallback((data) => {
21366
+ const [toasts, setToasts] = React9.useState([]);
21367
+ const addToast = React9.useCallback((data) => {
20119
21368
  const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
20120
21369
  setToasts((prev) => {
20121
21370
  const next = [...prev, { ...data, id }];
@@ -20123,10 +21372,10 @@ function ToastProvider({ children, maxVisible }) {
20123
21372
  });
20124
21373
  return id;
20125
21374
  }, [maxVisible]);
20126
- const update = React5.useCallback((id, patch) => {
21375
+ const update = React9.useCallback((id, patch) => {
20127
21376
  setToasts((prev) => prev.map((t) => t.id === id ? { ...t, ...patch } : t));
20128
21377
  }, []);
20129
- const dismiss = React5.useCallback((id) => {
21378
+ const dismiss = React9.useCallback((id) => {
20130
21379
  setToasts((prev) => prev.filter((t) => t.id !== id));
20131
21380
  }, []);
20132
21381
  return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { toast: addToast, update, dismiss }, children: [
@@ -20135,15 +21384,15 @@ function ToastProvider({ children, maxVisible }) {
20135
21384
  ] });
20136
21385
  }
20137
21386
  function useToast() {
20138
- const ctx = React5.useContext(ToastContext);
21387
+ const ctx = React9.useContext(ToastContext);
20139
21388
  if (!ctx) throw new Error("useToast must be used within a ToastProvider");
20140
21389
  return ctx;
20141
21390
  }
20142
21391
  var INTERVALS = [1e3, 2e3, 4e3, 5e3, 7e3, 1e4, 12e3];
20143
21392
  function useAdaptivePolling({ enabled, onPoll }) {
20144
- const onPollRef = React5.useRef(onPoll);
21393
+ const onPollRef = React9.useRef(onPoll);
20145
21394
  onPollRef.current = onPoll;
20146
- React5.useEffect(() => {
21395
+ React9.useEffect(() => {
20147
21396
  if (!enabled) return;
20148
21397
  let cancelled = false;
20149
21398
  let timeoutId = null;
@@ -20316,7 +21565,7 @@ var OpenMailButton = styled10__default.default.a`
20316
21565
  }
20317
21566
  `;
20318
21567
  var ContactPopup = ({ onClose }) => {
20319
- const [copied, setCopied] = React5.useState(false);
21568
+ const [copied, setCopied] = React9.useState(false);
20320
21569
  const email = "admin@loafmarkets.com";
20321
21570
  const handleCopy = async () => {
20322
21571
  try {
@@ -20525,7 +21774,7 @@ var DisclaimerText = styled10__default.default.p`
20525
21774
  max-width: 100%;
20526
21775
  `;
20527
21776
  var SiteFooter = () => {
20528
- const [showContactPopup, setShowContactPopup] = React5.useState(false);
21777
+ const [showContactPopup, setShowContactPopup] = React9.useState(false);
20529
21778
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20530
21779
  /* @__PURE__ */ jsxRuntime.jsx(FooterContainer, { children: /* @__PURE__ */ jsxRuntime.jsxs(FooterContent, { children: [
20531
21780
  /* @__PURE__ */ jsxRuntime.jsxs(FooterTop, { children: [
@@ -20614,10 +21863,10 @@ function extractSparkline(candles, maxPoints = 20) {
20614
21863
  }
20615
21864
  return points;
20616
21865
  }
20617
- var SparklineChart = React5__namespace.default.memo(function SparklineChart2({ data, width, height, positive }) {
20618
- const [hoverX, setHoverX] = React5.useState(null);
20619
- const svgRef = React5.useRef(null);
20620
- const { linePath, fillPath, points } = React5.useMemo(() => {
21866
+ var SparklineChart = React9__namespace.default.memo(function SparklineChart2({ data, width, height, positive }) {
21867
+ const [hoverX, setHoverX] = React9.useState(null);
21868
+ const svgRef = React9.useRef(null);
21869
+ const { linePath, fillPath, points } = React9.useMemo(() => {
20621
21870
  const mn = Math.min(...data);
20622
21871
  const mx = Math.max(...data);
20623
21872
  const range = mx - mn || 1;
@@ -20630,7 +21879,7 @@ var SparklineChart = React5__namespace.default.memo(function SparklineChart2({ d
20630
21879
  const fill = `${line} L${width},${height} L0,${height} Z`;
20631
21880
  return { linePath: line, fillPath: fill, points: pts };
20632
21881
  }, [data, width, height]);
20633
- const interpolated = React5.useMemo(() => {
21882
+ const interpolated = React9.useMemo(() => {
20634
21883
  if (hoverX == null || points.length < 2) return null;
20635
21884
  const stepX = width / (data.length - 1);
20636
21885
  const rawIdx = hoverX / stepX;
@@ -20643,14 +21892,14 @@ var SparklineChart = React5__namespace.default.memo(function SparklineChart2({ d
20643
21892
  price: lerp(data[i0], data[i1], t)
20644
21893
  };
20645
21894
  }, [hoverX, points, data, width]);
20646
- const handleMouseMove = React5.useCallback((e) => {
21895
+ const handleMouseMove = React9.useCallback((e) => {
20647
21896
  const svg = svgRef.current;
20648
21897
  if (!svg) return;
20649
21898
  const rect = svg.getBoundingClientRect();
20650
21899
  const x = Math.max(0, Math.min(width, e.clientX - rect.left));
20651
21900
  setHoverX(x);
20652
21901
  }, [width]);
20653
- const handleMouseLeave = React5.useCallback(() => setHoverX(null), []);
21902
+ const handleMouseLeave = React9.useCallback(() => setHoverX(null), []);
20654
21903
  if (data.length < 2) return null;
20655
21904
  const color = positive ? "#00C076" : "#FF5757";
20656
21905
  const gradId = `spark-grad-${positive ? "up" : "dn"}`;
@@ -20768,6 +22017,7 @@ exports.PropertyPhotoGallery = PropertyPhotoGallery;
20768
22017
  exports.PropertySubheader = PropertySubheader;
20769
22018
  exports.PropertyTour = PropertyTour;
20770
22019
  exports.PropertyValuation = PropertyValuation;
22020
+ exports.SentimentBar = SentimentBar;
20771
22021
  exports.SiteFooter = SiteFooter;
20772
22022
  exports.Skeleton = Skeleton;
20773
22023
  exports.SlideDigit = SlideDigit;
@@ -20776,10 +22026,13 @@ exports.ToastProvider = ToastProvider;
20776
22026
  exports.TradeConfirmationModal = TradeConfirmationModal;
20777
22027
  exports.TradingSlider = TradingSlider;
20778
22028
  exports.YourOrders = YourOrders;
22029
+ exports.__resetDismissedBreaking = __resetDismissedBreaking;
20779
22030
  exports.badgeVariants = badgeVariants;
20780
22031
  exports.buttonVariants = buttonVariants;
20781
22032
  exports.extractSparkline = extractSparkline;
22033
+ exports.formatAge = formatAge;
20782
22034
  exports.hasPendingActivity = hasPendingActivity;
22035
+ exports.rowAgeLabel = rowAgeLabel;
20783
22036
  exports.useAdaptivePolling = useAdaptivePolling;
20784
22037
  exports.useToast = useToast;
20785
22038
  //# sourceMappingURL=index.js.map