@bearmenu/ui 0.8.10 → 0.8.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/{chunk-UKBNQO6Q.js → chunk-2CXU5WZO.js} +1 -1
  2. package/dist/{chunk-62ES6N32.js → chunk-43RC7MHY.js} +1 -1
  3. package/dist/{chunk-Q6QH52LJ.js → chunk-6TEEY5YA.js} +2 -2
  4. package/dist/{chunk-UDN7UHJW.js → chunk-7A42J73Q.js} +3 -2
  5. package/dist/{chunk-5RWTOT5Y.js → chunk-CNJQUHCU.js} +11 -1
  6. package/dist/{chunk-TH6W2PWG.js → chunk-UDTG3RSE.js} +1 -1
  7. package/dist/{chunk-H3BV4VAG.js → chunk-VAXOQS7W.js} +14 -2
  8. package/dist/{chunk-SY6RV476.js → chunk-WCTHZKU7.js} +10 -21
  9. package/dist/{chunk-AKQ57NXY.js → chunk-ZQ53AGML.js} +2 -2
  10. package/dist/components/alert-dialog.js +1 -1
  11. package/dist/components/badge.js +1 -1
  12. package/dist/components/button.d.ts +2 -2
  13. package/dist/components/button.js +1 -1
  14. package/dist/components/calendar.js +1 -1
  15. package/dist/components/carousel.js +1 -1
  16. package/dist/components/combobox.js +1 -1
  17. package/dist/components/concept-compare-rail.js +2 -2
  18. package/dist/components/concept-compare.d.ts +1 -1
  19. package/dist/components/concept-compare.js +31 -10
  20. package/dist/components/concept-convergence.js +2 -2
  21. package/dist/components/empty-state.js +1 -1
  22. package/dist/components/event-detail-panel.js +1 -1
  23. package/dist/components/event-list-row-wide.js +1 -1
  24. package/dist/components/filter-category-row.js +1 -1
  25. package/dist/components/glass-ground.d.ts +26 -31
  26. package/dist/components/glass-ground.js +1 -1
  27. package/dist/components/haptic-button.js +1 -1
  28. package/dist/components/input-group.d.ts +2 -2
  29. package/dist/components/input.d.ts +1 -1
  30. package/dist/components/item.d.ts +15 -5
  31. package/dist/components/item.js +15 -10
  32. package/dist/components/kitchen-dossier.d.ts +9 -7
  33. package/dist/components/kitchen-dossier.js +31 -25
  34. package/dist/components/link-button.js +1 -1
  35. package/dist/components/menu-family-block.d.ts +22 -17
  36. package/dist/components/menu-family-block.js +62 -61
  37. package/dist/components/menu-family-card.js +2 -4
  38. package/dist/components/menu-family-tiles.d.ts +19 -0
  39. package/dist/components/menu-family-tiles.js +57 -0
  40. package/dist/components/menu-hub-hero.js +18 -11
  41. package/dist/components/menu-index-list.d.ts +31 -12
  42. package/dist/components/menu-index-list.js +68 -31
  43. package/dist/components/menu-intent-hero.d.ts +1 -1
  44. package/dist/components/menu-item.js +3 -3
  45. package/dist/components/menu-mocks.d.ts +10 -3
  46. package/dist/components/menu-mocks.js +21 -9
  47. package/dist/components/menu-types.d.ts +33 -10
  48. package/dist/components/multi-select-combobox.js +2 -2
  49. package/dist/components/pagination.js +1 -1
  50. package/dist/components/photo-ground.d.ts +8 -2
  51. package/dist/components/photo-ground.js +1 -1
  52. package/dist/components/place-details-mobile.js +1 -1
  53. package/dist/components/searchable-select.js +1 -1
  54. package/dist/components/signature-chip.d.ts +2 -2
  55. package/dist/components/signature-chip.js +2 -2
  56. package/dist/components/sliding-panels.js +1 -1
  57. package/dist/components/top-ranking-entry.js +3 -3
  58. package/dist/components/venue-grade-dimensions.js +1 -1
  59. package/dist/components/venue-quotes.d.ts +1 -1
  60. package/dist/components/venue-quotes.js +1 -1
  61. package/dist/components/venue-wall.js +5 -3
  62. package/dist/components/weekday-theme-banner.d.ts +24 -3
  63. package/dist/components/weekday-theme-banner.js +63 -15
  64. package/package.json +1 -1
  65. package/src/components/badge.tsx +1 -1
  66. package/src/components/button.stories.tsx +25 -2
  67. package/src/components/button.tsx +14 -2
  68. package/src/components/colour-dictionary.stories.tsx +1 -1
  69. package/src/components/concept-compare-rail.tsx +2 -1
  70. package/src/components/concept-compare.stories.tsx +3 -3
  71. package/src/components/concept-compare.tsx +50 -14
  72. package/src/components/glass-ground.tsx +31 -56
  73. package/src/components/item.tsx +69 -45
  74. package/src/components/kitchen-dossier.stories.tsx +1 -1
  75. package/src/components/kitchen-dossier.tsx +60 -40
  76. package/src/components/menu-family-block.stories.tsx +3 -3
  77. package/src/components/menu-family-block.tsx +94 -98
  78. package/src/components/menu-family-card.stories.tsx +2 -2
  79. package/src/components/menu-family-card.tsx +6 -13
  80. package/src/components/menu-family-tiles.stories.tsx +54 -0
  81. package/src/components/menu-family-tiles.test.tsx +30 -0
  82. package/src/components/menu-family-tiles.tsx +132 -0
  83. package/src/components/menu-hub-hero.test.tsx +39 -0
  84. package/src/components/menu-hub-hero.tsx +30 -12
  85. package/src/components/menu-index-list.stories.tsx +6 -1
  86. package/src/components/menu-index-list.tsx +101 -54
  87. package/src/components/menu-intent-hero.tsx +1 -1
  88. package/src/components/menu-mocks.ts +32 -9
  89. package/src/components/menu-types.ts +32 -9
  90. package/src/components/photo-ground.tsx +14 -2
  91. package/src/components/signature-chip.tsx +3 -3
  92. package/src/components/venue-grade-dimensions.tsx +9 -2
  93. package/src/components/venue-quotes.stories.tsx +1 -1
  94. package/src/components/venue-quotes.tsx +4 -2
  95. package/src/components/venue-wall.tsx +9 -4
  96. package/src/components/weekday-theme-banner.stories.tsx +43 -4
  97. package/src/components/weekday-theme-banner.tsx +95 -18
  98. package/dist/components/menu-intent-tiles.d.ts +0 -31
  99. package/dist/components/menu-intent-tiles.js +0 -50
  100. package/src/components/menu-intent-tiles.stories.tsx +0 -54
  101. package/src/components/menu-intent-tiles.tsx +0 -76
@@ -12,7 +12,7 @@ var badgeVariants = cva(
12
12
  secondary: "border-transparent bg-secondary text-secondary-foreground",
13
13
  destructive: "border-transparent bg-destructive text-destructive-foreground",
14
14
  outline: "text-foreground border-border",
15
- overlay: "border-transparent bg-foreground/70 text-background backdrop-blur-sm",
15
+ overlay: "border-transparent bg-foreground/80 text-background",
16
16
  glass: "glass text-foreground border-border/50",
17
17
  success: "border-transparent bg-success text-success-foreground",
18
18
  warning: "border-transparent bg-warning text-warning-foreground",
@@ -8,7 +8,7 @@ function VenueQuotes({ quotes, onCite, citeLabel, limit, className }) {
8
8
  var _a, _b;
9
9
  const citations = (_b = (_a = quote.review_ids) == null ? void 0 : _a.length) != null ? _b : 0;
10
10
  const canCite = !!onCite && citations > 0;
11
- const text = /* @__PURE__ */ jsx("blockquote", { className: "border-l-2 border-border pl-3 font-serif text-[13px] italic leading-[1.45] text-muted-foreground", children: `\u201C${quote.text}\u201D` });
11
+ const text = /* @__PURE__ */ jsx("blockquote", { className: "border-l-2 border-border pl-3 font-serif text-[13px] leading-[1.45] text-muted-foreground", children: `\u201C${quote.text}\u201D` });
12
12
  if (!canCite) return /* @__PURE__ */ jsx("div", { children: text }, index);
13
13
  return /* @__PURE__ */ jsx(
14
14
  "button",
@@ -1,4 +1,4 @@
1
- import { Badge } from './chunk-UKBNQO6Q.js';
1
+ import { Badge } from './chunk-2CXU5WZO.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
@@ -25,7 +25,7 @@ function SignatureChip({
25
25
  className: cn(
26
26
  shared,
27
27
  "inline-flex items-center rounded-full border border-dashed",
28
- onImage ? "border-background/70 bg-foreground/70 text-background backdrop-blur-sm hover:bg-foreground/85" : "border-accent/40 text-accent hover:bg-accent/10",
28
+ onImage ? "border-background/70 bg-foreground/80 text-background hover:bg-foreground/90" : "border-accent/40 text-accent hover:bg-accent/10",
29
29
  "focus-visible:outline-none focus-visible:ring-2",
30
30
  onImage ? "focus-visible:ring-background/70" : "focus-visible:ring-accent/40",
31
31
  className
@@ -1,11 +1,12 @@
1
1
  import { SnapRail, SnapRailDots } from './chunk-DTXNDLSE.js';
2
- import { PhotoGround } from './chunk-5RWTOT5Y.js';
2
+ import { PhotoGround } from './chunk-CNJQUHCU.js';
3
3
  import { cn } from './chunk-FEK5XGZW.js';
4
4
  import * as React from 'react';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
6
 
7
7
  var FOOT_GLASS = cn(
8
- "before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:content-[''] before:backdrop-blur-lg",
8
+ // Ink only no backdrop-blur; see `GlassGround` for the measurement.
9
+ "before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:content-['']",
9
10
  "before:bg-[oklch(0.16_0.012_55_/_0.9)]",
10
11
  "lg:before:[mask-image:linear-gradient(to_top,black_60%,transparent_100%)] lg:before:bg-[linear-gradient(to_top,oklch(0.16_0.012_55_/_0.88)_0%,oklch(0.16_0.012_55_/_0.84)_60%,oklch(0.16_0.012_55_/_0.4)_85%,oklch(0.16_0.012_55_/_0)_100%)]"
11
12
  );
@@ -14,6 +14,7 @@ function PhotoGround({
14
14
  overlay,
15
15
  overlayClassName,
16
16
  loading = "lazy",
17
+ glyphClassName,
17
18
  className
18
19
  }) {
19
20
  const initialOf = (index) => {
@@ -39,7 +40,16 @@ function PhotoGround({
39
40
  /* Never a grey box: the ground with the venue's initial. A missing
40
41
  photograph is not a broken image, and drawing one as a placeholder
41
42
  makes a real city look unfinished. */
42
- /* @__PURE__ */ jsx("span", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "font-serif text-[64px] font-semibold leading-none text-white/15", children: initialOf(index) }) })
43
+ /* @__PURE__ */ jsx("span", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(
44
+ "span",
45
+ {
46
+ className: cn(
47
+ "font-serif text-[64px] font-semibold leading-none text-white/15",
48
+ glyphClassName
49
+ ),
50
+ children: initialOf(index)
51
+ }
52
+ ) })
43
53
  ) }, index);
44
54
  };
45
55
  return /* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: cn("absolute inset-0 block", PHOTO_GROUND, className), children: [
@@ -1,4 +1,4 @@
1
- import { SignatureChip } from './chunk-Q6QH52LJ.js';
1
+ import { SignatureChip } from './chunk-6TEEY5YA.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadValues } from './chunk-3GWWZKX7.js';
4
4
  import { memo } from 'react';
@@ -26,13 +26,23 @@ var buttonVariants = cva(
26
26
  * into a dark photo.
27
27
  *
28
28
  * Deliberately NOT theme-aware, and so deliberately different from
29
- * `Badge`'s `overlay` (`bg-foreground/70 text-background`, which
29
+ * `Badge`'s `overlay` (`bg-foreground/80 text-background`, which
30
30
  * inverts). A photo is equally a photo in both themes — this chrome has
31
31
  * to contrast with the image beneath it, not with the app canvas, so it
32
32
  * stays dark-on-light-glyph either way. Reconcile Badge to this, not the
33
33
  * reverse, if the two are ever unified.
34
34
  */
35
- overlay: "bg-black/40 text-white backdrop-blur-sm hover:bg-black/60 focus-visible:ring-white/70",
35
+ overlay: "bg-black/50 text-white hover:bg-black/65 focus-visible:ring-white/70",
36
+ /**
37
+ * The LABELLED action on a photo surface — "Open the menu", "See all
38
+ * 46 bars", "How we read menus" — where `overlay` is the unlabelled
39
+ * chrome. Glass on the ink: translucent white with a hairline, white
40
+ * type. Same reasoning as `overlay`: not theme-aware, because it
41
+ * contrasts with the photograph, not the canvas. Pair with `size="pill"`.
42
+ * Icons trail, never lead: `ArrowRight` when it navigates to a page,
43
+ * `ChevronRight` when it opens a sheet or drawer.
44
+ */
45
+ ink: "border border-white/20 bg-white/[0.16] text-white hover:bg-white/25 focus-visible:ring-white/70 focus-visible:ring-offset-0",
36
46
  brown: "bg-brown text-brown-foreground shadow-sm hover:bg-brown/85 hover:shadow",
37
47
  antagonist: "bg-primary-foreground text-primary shadow-sm hover:bg-accent hover:text-accent-foreground border border-border hover:border-accent"
38
48
  },
@@ -41,6 +51,8 @@ var buttonVariants = cva(
41
51
  sm: "h-9 rounded-lg px-4",
42
52
  default: "h-11 px-6 py-2",
43
53
  lg: "h-12 rounded-2xl px-8",
54
+ /** The `ink` action's shape. Owns the radius so no variant fights it. */
55
+ pill: "h-11 rounded-full px-5 text-[13.5px] font-bold",
44
56
  icon: "h-11 w-11 rounded-full",
45
57
  "icon-xs": "h-8 w-8 rounded-full [&_svg]:size-3.5",
46
58
  "icon-sm": "h-9 w-9 rounded-full",
@@ -1,18 +1,10 @@
1
1
  import { cn } from './chunk-FEK5XGZW.js';
2
2
  import { __spreadProps, __spreadValues } from './chunk-3GWWZKX7.js';
3
- import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { jsx } from 'react/jsx-runtime';
4
4
 
5
5
  var STOPS = [0, 0.25, 0.5, 0.75, 1];
6
6
  var EASE = [0, 0.06, 0.25, 0.56, 1];
7
- var FROST_SOFT = "[mask-image:linear-gradient(var(--glass-dir),transparent_var(--glass-s0),rgba(0,0,0,0.25)_var(--glass-s1),black_var(--glass-s2))] lg:[mask-image:linear-gradient(var(--glass-lg-dir),transparent_var(--glass-lg-s0),rgba(0,0,0,0.25)_var(--glass-lg-s1),black_var(--glass-lg-s2))]";
8
- var FROST_HEAVY = "[mask-image:linear-gradient(var(--glass-dir),transparent_var(--glass-s1),rgba(0,0,0,0.25)_var(--glass-s2),rgba(0,0,0,0.6)_var(--glass-s3),black_var(--glass-s4))] lg:[mask-image:linear-gradient(var(--glass-lg-dir),transparent_var(--glass-lg-s1),rgba(0,0,0,0.25)_var(--glass-lg-s2),rgba(0,0,0,0.6)_var(--glass-lg-s3),black_var(--glass-lg-s4))]";
9
7
  var INK = "bg-[linear-gradient(var(--glass-dir),oklch(0.16_0.012_55_/_0)_var(--glass-s0),oklch(0.16_0.012_55_/_var(--glass-a1))_var(--glass-s1),oklch(0.16_0.012_55_/_var(--glass-a2))_var(--glass-s2),oklch(0.16_0.012_55_/_var(--glass-a3))_var(--glass-s3),oklch(0.16_0.012_55_/_var(--glass-a4))_var(--glass-s4),oklch(0.16_0.012_55_/_var(--glass-a-peak))_100%)] lg:bg-[linear-gradient(var(--glass-lg-dir),oklch(0.16_0.012_55_/_0)_var(--glass-lg-s0),oklch(0.16_0.012_55_/_var(--glass-a1))_var(--glass-lg-s1),oklch(0.16_0.012_55_/_var(--glass-a2))_var(--glass-lg-s2),oklch(0.16_0.012_55_/_var(--glass-a3))_var(--glass-lg-s3),oklch(0.16_0.012_55_/_var(--glass-a4))_var(--glass-lg-s4),oklch(0.16_0.012_55_/_var(--glass-a-peak))_100%)]";
10
- var BLUR = {
11
- sm: ["backdrop-blur-[2px]", "backdrop-blur-sm"],
12
- md: ["backdrop-blur-sm", "backdrop-blur-md"],
13
- lg: ["backdrop-blur-md", "backdrop-blur-lg"],
14
- xl: ["backdrop-blur-lg", "backdrop-blur-xl"]
15
- };
16
8
  function measure(value) {
17
9
  const match = value.trim().match(/^(-?\d*\.?\d+)\s*([a-z%]*)$/i);
18
10
  if (!match) throw new Error(`GlassGround: cannot read stop "${value}"`);
@@ -23,13 +15,7 @@ function positions(clear, full) {
23
15
  const [to] = measure(full);
24
16
  return STOPS.map((fraction) => `${from + (to - from) * fraction}${unit}`);
25
17
  }
26
- function GlassGround({
27
- stops,
28
- lgStops = stops,
29
- peak = 0.96,
30
- blur = "xl",
31
- className
32
- }) {
18
+ function GlassGround({ stops, lgStops = stops, peak = 0.96, className }) {
33
19
  const base = positions(stops.clear, stops.full);
34
20
  const lg = positions(lgStops.clear, lgStops.full);
35
21
  const style = __spreadProps(__spreadValues(__spreadValues(__spreadValues({
@@ -38,11 +24,14 @@ function GlassGround({
38
24
  }, Object.fromEntries(base.map((position, index) => [`--glass-s${index}`, position]))), Object.fromEntries(lg.map((position, index) => [`--glass-lg-s${index}`, position]))), Object.fromEntries(EASE.slice(1).map((share, index) => [`--glass-a${index + 1}`, String(peak * 0.8 * share)]))), {
39
25
  "--glass-a-peak": String(peak)
40
26
  });
41
- return /* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: cn("pointer-events-none absolute inset-0 block", className), style, children: [
42
- /* @__PURE__ */ jsx("span", { className: cn("absolute inset-0", BLUR[blur][0], FROST_SOFT) }),
43
- /* @__PURE__ */ jsx("span", { className: cn("absolute inset-0", BLUR[blur][1], FROST_HEAVY) }),
44
- /* @__PURE__ */ jsx("span", { className: cn("absolute inset-0", INK) })
45
- ] });
27
+ return /* @__PURE__ */ jsx(
28
+ "span",
29
+ {
30
+ "aria-hidden": true,
31
+ className: cn("pointer-events-none absolute inset-0 block", INK, className),
32
+ style
33
+ }
34
+ );
46
35
  }
47
36
 
48
37
  export { GlassGround };
@@ -38,11 +38,11 @@ function VenueGradeDimensions({
38
38
  "div",
39
39
  {
40
40
  "aria-hidden": true,
41
- className: "relative block h-[3px] overflow-hidden rounded-full bg-muted",
41
+ className: "relative block h-[3px] overflow-hidden rounded-full bg-current/15",
42
42
  children: /* @__PURE__ */ jsx(
43
43
  "span",
44
44
  {
45
- className: "absolute inset-y-0 left-0 rounded-full bg-[var(--gradient-primary,currentColor)]",
45
+ className: "absolute inset-y-0 left-0 rounded-full bg-current bg-[image:var(--gradient-primary)]",
46
46
  style: { width: `${Math.min(100, Math.max(0, value))}%` }
47
47
  }
48
48
  )
@@ -1,4 +1,4 @@
1
- import { buttonVariants } from '../chunk-H3BV4VAG.js';
1
+ import { buttonVariants } from '../chunk-VAXOQS7W.js';
2
2
  import '../chunk-R47NEOSI.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
@@ -1,3 +1,3 @@
1
- export { Badge, badgeVariants } from '../chunk-UKBNQO6Q.js';
1
+ export { Badge, badgeVariants } from '../chunk-2CXU5WZO.js';
2
2
  import '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-3GWWZKX7.js';
@@ -3,8 +3,8 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const buttonVariants: (props?: ({
6
- variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "glass" | "overlay" | "brown" | "antagonist" | null | undefined;
7
- size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
6
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "antagonist" | null | undefined;
7
+ size?: "default" | "xs" | "sm" | "lg" | "pill" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
8
8
  fullWidth?: boolean | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
@@ -1,4 +1,4 @@
1
- export { Button, buttonVariants } from '../chunk-H3BV4VAG.js';
1
+ export { Button, buttonVariants } from '../chunk-VAXOQS7W.js';
2
2
  import '../chunk-R47NEOSI.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-3GWWZKX7.js';
@@ -1,4 +1,4 @@
1
- import { buttonVariants, Button } from '../chunk-H3BV4VAG.js';
1
+ import { buttonVariants, Button } from '../chunk-VAXOQS7W.js';
2
2
  import '../chunk-R47NEOSI.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadValues, __spreadProps } from '../chunk-3GWWZKX7.js';
@@ -1,4 +1,4 @@
1
- import { Button } from '../chunk-H3BV4VAG.js';
1
+ import { Button } from '../chunk-VAXOQS7W.js';
2
2
  import '../chunk-R47NEOSI.js';
3
3
  import { cn } from '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
@@ -1,7 +1,7 @@
1
1
  import { Popover, PopoverTrigger, PopoverContent } from '../chunk-66MAPLXS.js';
2
2
  import { Command, CommandInput, CommandList, CommandLoading, CommandEmpty, CommandGroup, CommandItem } from '../chunk-XNA2INVQ.js';
3
3
  import '../chunk-FRPPIXMY.js';
4
- import { Button } from '../chunk-H3BV4VAG.js';
4
+ import { Button } from '../chunk-VAXOQS7W.js';
5
5
  import '../chunk-R47NEOSI.js';
6
6
  import { cn } from '../chunk-FEK5XGZW.js';
7
7
  import '../chunk-3GWWZKX7.js';
@@ -1,5 +1,5 @@
1
- export { ConceptCompareRail } from '../chunk-UDN7UHJW.js';
1
+ export { ConceptCompareRail } from '../chunk-7A42J73Q.js';
2
2
  import '../chunk-DTXNDLSE.js';
3
- import '../chunk-5RWTOT5Y.js';
3
+ import '../chunk-CNJQUHCU.js';
4
4
  import '../chunk-FEK5XGZW.js';
5
5
  import '../chunk-3GWWZKX7.js';
@@ -69,7 +69,7 @@ type ConceptCompareFigure = {
69
69
  type ConceptCompareLabels = {
70
70
  /** Small caps kicker, e.g. "DISH CONCEPT". */
71
71
  kind: string;
72
- /** The badge on the lowest-priced room, e.g. "CHEAPEST". */
72
+ /** The badge on the lowest-priced room, e.g. "CHEAPEST" — the fallback when a row carries no `badge`. */
73
73
  cheapest: string;
74
74
  /** The badge on every other room, e.g. "#2". Defaults to `#${rank}`. */
75
75
  rank?: (rank: number) => string;
@@ -1,7 +1,7 @@
1
1
  import { Separator } from '../chunk-WSRWFA6K.js';
2
- import { ConceptCompareRail } from '../chunk-UDN7UHJW.js';
2
+ import { ConceptCompareRail } from '../chunk-7A42J73Q.js';
3
3
  import '../chunk-DTXNDLSE.js';
4
- import { PhotoGround, PHOTO_GROUND } from '../chunk-5RWTOT5Y.js';
4
+ import { PhotoGround, PHOTO_GROUND } from '../chunk-CNJQUHCU.js';
5
5
  import { Skeleton } from '../chunk-QXHMPJ35.js';
6
6
  import { cn } from '../chunk-FEK5XGZW.js';
7
7
  import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
@@ -20,7 +20,7 @@ var initialOf = (name) => {
20
20
  var GROUND = PHOTO_GROUND;
21
21
  var PHOTO_OVERLAY_HOVER = "transition-opacity duration-300 group-hover/room:opacity-0 motion-reduce:transition-none";
22
22
  var ROOM_SCRIM = "absolute inset-0 bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0)_0%,oklch(0.16_0.012_55_/_0)_30%,oklch(0.16_0.012_55_/_0.55)_58%,oklch(0.16_0.012_55_/_0.9)_100%)]";
23
- var HEAD_GLASS = "before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:content-[''] before:backdrop-blur-lg before:[mask-image:linear-gradient(to_bottom,black_35%,transparent_100%)] before:bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.8)_0%,oklch(0.16_0.012_55_/_0.6)_35%,oklch(0.16_0.012_55_/_0.22)_75%,oklch(0.16_0.012_55_/_0)_100%)]";
23
+ var HEAD_GLASS = "before:pointer-events-none before:absolute before:inset-0 before:-z-10 before:content-[''] before:bg-[linear-gradient(to_bottom,oklch(0.16_0.012_55_/_0.86)_0%,oklch(0.16_0.012_55_/_0.7)_35%,oklch(0.16_0.012_55_/_0.28)_75%,oklch(0.16_0.012_55_/_0)_100%)]";
24
24
  var COLUMNS = {
25
25
  1: "lg:grid-cols-1",
26
26
  2: "lg:grid-cols-2",
@@ -106,8 +106,11 @@ function ConceptCompare({
106
106
  actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 [&>*]:w-full lg:[&>*]:w-auto", children: actions })
107
107
  ] }) : void 0,
108
108
  children: rooms.map((room, index) => {
109
+ var _a2, _b2;
109
110
  const href = hrefs == null ? void 0 : hrefs[room.place_slug];
110
- const isCheapest = room.price === cheapest;
111
+ const badge = (_a2 = room.badge) != null ? _a2 : room.price === cheapest ? labels.cheapest : rankOf(index + 1);
112
+ const isCheapest = badge === labels.cheapest;
113
+ const lead = (_b2 = room.lead) != null ? _b2 : isCheapest ? "price" : void 0;
111
114
  const roomClass = cn(
112
115
  /* Transparent on the phone — the card behind it is the room's
113
116
  photograph — with only its scrim and its line. A photograph of
@@ -136,26 +139,35 @@ function ConceptCompare({
136
139
  {
137
140
  className: cn(
138
141
  "inline-flex h-[22px] w-max items-center gap-1 rounded-full px-2 text-[10px] font-extrabold uppercase tracking-[0.08em]",
139
- isCheapest ? "bg-success text-white" : "bg-white/15 text-white/85 backdrop-blur-[2px]"
142
+ isCheapest ? "bg-success text-white" : "bg-white/20 text-white/85"
140
143
  ),
141
144
  children: [
142
145
  isCheapest && /* @__PURE__ */ jsx(ArrowDown, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
143
- isCheapest ? labels.cheapest : rankOf(index + 1)
146
+ badge
144
147
  ]
145
148
  }
146
149
  ),
147
150
  /* @__PURE__ */ jsxs("span", { className: "mt-2.5 flex items-center gap-1.5 text-white", children: [
148
151
  /* @__PURE__ */ jsx(MapPin, { className: "h-3.5 w-3.5 shrink-0 text-white/70", "aria-hidden": true }),
149
152
  /* @__PURE__ */ jsx("b", { className: "min-w-0 flex-1 truncate text-[15px] font-bold leading-tight", children: room.place_name }),
150
- room.rating !== void 0 && /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1 text-[12px] text-white/70", children: [
153
+ room.grade ? /* @__PURE__ */ jsx(
154
+ "span",
155
+ {
156
+ className: cn(
157
+ "shrink-0 text-[14px] font-extrabold leading-none tabular-nums text-[oklch(0.82_0.15_85)]",
158
+ lead === "grade" && "text-[16px]"
159
+ ),
160
+ children: room.grade
161
+ }
162
+ ) : room.rating !== void 0 && /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1 text-[12px] text-white/70", children: [
151
163
  /* @__PURE__ */ jsx(Star, { className: "h-3 w-3 shrink-0", "aria-hidden": true }),
152
164
  /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: room.rating })
153
165
  ] })
154
166
  ] }),
155
167
  room.place_area && /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-[12px] text-white/70", children: room.place_area }),
156
- /* @__PURE__ */ jsx("span", { className: "mt-2 block truncate font-serif text-[14px] italic text-white/90", children: room.alias }),
168
+ /* @__PURE__ */ jsx("span", { className: "mt-2 block truncate font-serif text-[14px] text-white/90", children: room.alias }),
157
169
  /* @__PURE__ */ jsx(Separator, { className: "my-2.5 via-white/20" }),
158
- /* @__PURE__ */ jsxs("span", { className: "flex items-baseline gap-2", children: [
170
+ /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
159
171
  /* @__PURE__ */ jsx(
160
172
  "b",
161
173
  {
@@ -166,7 +178,16 @@ function ConceptCompare({
166
178
  children: formatPrice(room.price)
167
179
  }
168
180
  ),
169
- room.mentions !== void 0 && room.mentions > 0 && /* @__PURE__ */ jsx("span", { className: "text-[11.5px] text-white/65", children: labels.mentions(room.mentions) })
181
+ room.mentions !== void 0 && room.mentions > 0 && /* @__PURE__ */ jsx(
182
+ "span",
183
+ {
184
+ className: cn(
185
+ "text-[11.5px]",
186
+ lead === "mentions" ? "font-bold text-white" : "text-white/65"
187
+ ),
188
+ children: labels.mentions(room.mentions)
189
+ }
190
+ )
170
191
  ] })
171
192
  ] });
172
193
  return href ? /* @__PURE__ */ jsx(
@@ -1,7 +1,7 @@
1
- import { PhotoGround } from '../chunk-5RWTOT5Y.js';
1
+ import { PhotoGround } from '../chunk-CNJQUHCU.js';
2
2
  import { Convergence } from '../chunk-MZL7CGCL.js';
3
3
  import '../chunk-LEAYBICI.js';
4
- import { Badge } from '../chunk-UKBNQO6Q.js';
4
+ import { Badge } from '../chunk-2CXU5WZO.js';
5
5
  import { cn } from '../chunk-FEK5XGZW.js';
6
6
  import '../chunk-3GWWZKX7.js';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Button } from '../chunk-H3BV4VAG.js';
1
+ import { Button } from '../chunk-VAXOQS7W.js';
2
2
  import '../chunk-R47NEOSI.js';
3
3
  import { Text } from '../chunk-7BWTYWM3.js';
4
4
  import { cn } from '../chunk-FEK5XGZW.js';
@@ -2,7 +2,7 @@ import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
2
2
  import { Separator } from '../chunk-WSRWFA6K.js';
3
3
  import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
4
4
  import { Skeleton } from '../chunk-QXHMPJ35.js';
5
- import { Button } from '../chunk-H3BV4VAG.js';
5
+ import { Button } from '../chunk-VAXOQS7W.js';
6
6
  import '../chunk-R47NEOSI.js';
7
7
  import { cn } from '../chunk-FEK5XGZW.js';
8
8
  import { __spreadProps, __spreadValues, __objRest } from '../chunk-3GWWZKX7.js';
@@ -3,7 +3,7 @@ import { Tag } from '../chunk-ZDAHKI3A.js';
3
3
  import { Separator } from '../chunk-WSRWFA6K.js';
4
4
  import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
5
5
  import { Skeleton } from '../chunk-QXHMPJ35.js';
6
- import { buttonVariants } from '../chunk-H3BV4VAG.js';
6
+ import { buttonVariants } from '../chunk-VAXOQS7W.js';
7
7
  import '../chunk-R47NEOSI.js';
8
8
  import { cn } from '../chunk-FEK5XGZW.js';
9
9
  import { __objRest, __spreadValues } from '../chunk-3GWWZKX7.js';
@@ -1,5 +1,5 @@
1
1
  import { Text } from '../chunk-7BWTYWM3.js';
2
- import { Badge } from '../chunk-UKBNQO6Q.js';
2
+ import { Badge } from '../chunk-2CXU5WZO.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import '../chunk-3GWWZKX7.js';
5
5
  import { ChevronRight } from 'lucide-react';
@@ -1,46 +1,46 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  /**
4
- * GlassGround — a frosted, inked caption rising out of one edge of a
5
- * photograph.
4
+ * GlassGround — an inked caption rising out of one edge of a photograph.
6
5
  *
7
- * Layers over a `PhotoGround`: two masked `backdrop-blur`s (the frost) and
8
- * an ink gradient (the contrast), running in one direction absent where the
9
- * photograph is the subject, solid where the type is. `MenuFamilyBlock` drew
10
- * this first; this is the same idea with the stops as data, so a card can say
11
- * "clear for 128px, then glass" without a sixth copy of the gradient strings.
6
+ * One layer over a `PhotoGround`: an ink gradient running in one direction —
7
+ * absent where the photograph is the subject, solid where the type is.
8
+ * `MenuFamilyBlock` drew this first; this is the same idea with the stops as
9
+ * data, so a card can say "clear for 128px, then ink" without a sixth copy of
10
+ * the gradient string.
12
11
  *
13
- * ## Why two blurs, and why the ramps are eased
12
+ * ## Why there is no blur any more
14
13
  *
15
- * One blur under a linear mask has an edge: the eye reads the line where
16
- * sharp becomes soft, however gently the mask fades it in. Two blurs — a
17
- * light one that starts early and a heavier one that starts late — make the
18
- * softening itself a gradient (the "progressive blur" of a phone's lock
19
- * screen), and every ramp here is an ease-in through five stops rather than
20
- * a straight line, because a straight ramp has a visible crease at each end
21
- * where its slope changes.
14
+ * This used to be two masked `backdrop-blur`s under the ink a progressive
15
+ * frost. Measured on `/menu` in production (2026-09-14): the page carried 73
16
+ * backdrop-filter composited layers, six dossiers' worth of these among them,
17
+ * and the main thread spent 9 ms per scrolled frame re-layerising them
18
+ * (2.7 s over a six-second fling; 56 ms with backdrop-filter disabled). A
19
+ * frost is not worth a page that cannot scroll on a phone, so the caption
20
+ * rests on the ink alone, eased through five stops so the ramp has no crease.
21
+ * See `docs/audits/audit-menu-page-performance-2026-09-14.md` in the app.
22
22
  *
23
23
  * ## Why the stops are custom properties
24
24
  *
25
- * Tailwind emits only the classes it can read verbatim, so the gradients
26
- * cannot be assembled from props into a class. The classes below are literal
27
- * and read `--glass-*` variables; the component writes those inline, having
25
+ * Tailwind emits only the classes it can read verbatim, so the gradient
26
+ * cannot be assembled from props into a class. The class below is literal and
27
+ * reads `--glass-*` variables; the component writes those inline, having
28
28
  * interpolated the quarter stops in JS (`clear` and `full` must share a
29
29
  * unit). Same mechanism as `HueChip`'s hue. The ink's colour is the
30
30
  * package's one scrim literal, `oklch(0.16 0.012 55)`, never `var(--scrim)`.
31
31
  *
32
32
  * ## The ramp ends where the type begins
33
33
  *
34
- * `clear` is where the frost starts, `full` where it and the ink are solid.
35
- * Set `full` to the exact seam the content starts at — a ramp that runs past
36
- * the seam puts the first row of type on half-frost.
34
+ * `clear` is where the ink starts, `full` where it is solid. Set `full` to
35
+ * the exact seam the content starts at — a ramp that runs past the seam puts
36
+ * the first row of type on half-ink.
37
37
  */
38
38
  type GlassStops = {
39
39
  /** Which way the ink runs — toward the type. */
40
40
  direction: "to bottom" | "to right";
41
- /** Where the frost begins, e.g. `"0px"` or `"24%"`. */
41
+ /** Where the ink begins, e.g. `"0px"` or `"24%"`. */
42
42
  clear: string;
43
- /** Where frost and ink are solid — the seam the content starts at. Same unit as `clear`. */
43
+ /** Where the ink is solid — the seam the content starts at. Same unit as `clear`. */
44
44
  full: string;
45
45
  };
46
46
  type GlassGroundProps = {
@@ -49,18 +49,13 @@ type GlassGroundProps = {
49
49
  lgStops?: GlassStops;
50
50
  /**
51
51
  * How dark the ink gets at the far edge, 0–1. `0.96` is a caption the
52
- * photograph is only a texture under; `0.4` is a photograph the caption is
52
+ * photograph is only a texture under; `0.6` is a photograph the caption is
53
53
  * drawn on — the type is lifted, the room stays a room.
54
54
  */
55
55
  peak?: number;
56
- /**
57
- * How much the frost softens the photograph where it is solid. `xl` turns
58
- * a room into colour; `sm` keeps it a room and only takes the edge off the
59
- * detail behind the type.
60
- */
61
- blur?: "sm" | "md" | "lg" | "xl";
56
+ /** Placement only. The ink is a `bg-*` on this same element, so a background here would replace it. */
62
57
  className?: string;
63
58
  };
64
- declare function GlassGround({ stops, lgStops, peak, blur, className, }: GlassGroundProps): react_jsx_runtime.JSX.Element;
59
+ declare function GlassGround({ stops, lgStops, peak, className }: GlassGroundProps): react_jsx_runtime.JSX.Element;
65
60
 
66
61
  export { GlassGround, type GlassGroundProps, type GlassStops };
@@ -1,3 +1,3 @@
1
- export { GlassGround } from '../chunk-SY6RV476.js';
1
+ export { GlassGround } from '../chunk-WCTHZKU7.js';
2
2
  import '../chunk-FEK5XGZW.js';
3
3
  import '../chunk-3GWWZKX7.js';
@@ -1,4 +1,4 @@
1
- import { Button } from '../chunk-H3BV4VAG.js';
1
+ import { Button } from '../chunk-VAXOQS7W.js';
2
2
  import { useHaptic } from '../chunk-R47NEOSI.js';
3
3
  import '../chunk-FEK5XGZW.js';
4
4
  import { __objRest, __spreadProps, __spreadValues } from '../chunk-3GWWZKX7.js';
@@ -4,11 +4,11 @@ import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const inputGroupVariants: (props?: ({
6
6
  size?: "default" | "sm" | "lg" | null | undefined;
7
- shape?: "rounded" | "pill" | null | undefined;
7
+ shape?: "pill" | "rounded" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  declare const InputGroup: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
10
10
  size?: "default" | "sm" | "lg" | null | undefined;
11
- shape?: "rounded" | "pill" | null | undefined;
11
+ shape?: "pill" | "rounded" | null | undefined;
12
12
  } & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
13
13
  declare const InputGroupInput: React.ForwardRefExoticComponent<React.InputHTMLAttributes<HTMLInputElement> & React.RefAttributes<HTMLInputElement>>;
14
14
  declare const InputGroupAddon: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
@@ -4,7 +4,7 @@ import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const inputVariants: (props?: ({
6
6
  size?: "default" | "sm" | "lg" | null | undefined;
7
- shape?: "rounded" | "pill" | null | undefined;
7
+ shape?: "pill" | "rounded" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">, VariantProps<typeof inputVariants> {
10
10
  }
@@ -14,10 +14,20 @@ declare const Item: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDiv
14
14
  } & class_variance_authority_types.ClassProp) | undefined) => string> & {
15
15
  asChild?: boolean;
16
16
  } & React.RefAttributes<HTMLDivElement>>;
17
- declare const ItemMedia: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
18
- declare const ItemContent: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
19
- declare const ItemTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
20
- declare const ItemDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
21
- declare const ItemActions: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
17
+ declare const ItemMedia: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
18
+ asChild?: boolean;
19
+ } & React.RefAttributes<HTMLDivElement>>;
20
+ declare const ItemContent: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
21
+ asChild?: boolean;
22
+ } & React.RefAttributes<HTMLDivElement>>;
23
+ declare const ItemTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
24
+ asChild?: boolean;
25
+ } & React.RefAttributes<HTMLDivElement>>;
26
+ declare const ItemDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
27
+ asChild?: boolean;
28
+ } & React.RefAttributes<HTMLDivElement>>;
29
+ declare const ItemActions: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
30
+ asChild?: boolean;
31
+ } & React.RefAttributes<HTMLDivElement>>;
22
32
 
23
33
  export { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle, itemVariants };