@aparte/plugin-cards 0.0.0-stage → 0.29.1
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/LICENSE +21 -0
- package/README.md +151 -2
- package/dist/carousel-DwgHvriV.js +63 -0
- package/dist/carousel-DwgHvriV.js.map +1 -0
- package/dist/controls-BYUm4aRV.js +62 -0
- package/dist/controls-BYUm4aRV.js.map +1 -0
- package/dist/format-BFq79ydr.js +728 -0
- package/dist/format-BFq79ydr.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +120 -0
- package/dist/index.js.map +1 -0
- package/dist/items/icons.d.ts +12 -0
- package/dist/items/icons.d.ts.map +1 -0
- package/dist/items/index.d.ts +100 -0
- package/dist/items/index.d.ts.map +1 -0
- package/dist/items.js +698 -0
- package/dist/items.js.map +1 -0
- package/dist/kit/carousel.d.ts +17 -0
- package/dist/kit/carousel.d.ts.map +1 -0
- package/dist/kit/controls.d.ts +51 -0
- package/dist/kit/controls.d.ts.map +1 -0
- package/dist/kit/define.d.ts +201 -0
- package/dist/kit/define.d.ts.map +1 -0
- package/dist/kit/dom.d.ts +40 -0
- package/dist/kit/dom.d.ts.map +1 -0
- package/dist/kit/fence.d.ts +39 -0
- package/dist/kit/fence.d.ts.map +1 -0
- package/dist/kit/format.d.ts +49 -0
- package/dist/kit/format.d.ts.map +1 -0
- package/dist/kit/rating.d.ts +19 -0
- package/dist/kit/rating.d.ts.map +1 -0
- package/dist/kit/sparkline.d.ts +19 -0
- package/dist/kit/sparkline.d.ts.map +1 -0
- package/dist/kit/strings.d.ts +139 -0
- package/dist/kit/strings.d.ts.map +1 -0
- package/dist/link/icons.d.ts +16 -0
- package/dist/link/icons.d.ts.map +1 -0
- package/dist/link/index.d.ts +98 -0
- package/dist/link/index.d.ts.map +1 -0
- package/dist/link.js +387 -0
- package/dist/link.js.map +1 -0
- package/dist/media/icons.d.ts +28 -0
- package/dist/media/icons.d.ts.map +1 -0
- package/dist/media/index.d.ts +107 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media.js +610 -0
- package/dist/media.js.map +1 -0
- package/dist/order/icons.d.ts +49 -0
- package/dist/order/icons.d.ts.map +1 -0
- package/dist/order/index.d.ts +204 -0
- package/dist/order/index.d.ts.map +1 -0
- package/dist/order.js +1843 -0
- package/dist/order.js.map +1 -0
- package/dist/place/icons.d.ts +18 -0
- package/dist/place/icons.d.ts.map +1 -0
- package/dist/place/index.d.ts +207 -0
- package/dist/place/index.d.ts.map +1 -0
- package/dist/place.js +1456 -0
- package/dist/place.js.map +1 -0
- package/dist/plan/icons.d.ts +25 -0
- package/dist/plan/icons.d.ts.map +1 -0
- package/dist/plan/index.d.ts +153 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan.js +1191 -0
- package/dist/plan.js.map +1 -0
- package/dist/product/icons.d.ts +16 -0
- package/dist/product/icons.d.ts.map +1 -0
- package/dist/product/index.d.ts +133 -0
- package/dist/product/index.d.ts.map +1 -0
- package/dist/product.js +1245 -0
- package/dist/product.js.map +1 -0
- package/dist/rating-CHVajQ2b.js +35 -0
- package/dist/rating-CHVajQ2b.js.map +1 -0
- package/dist/score/icons.d.ts +35 -0
- package/dist/score/icons.d.ts.map +1 -0
- package/dist/score/index.d.ts +185 -0
- package/dist/score/index.d.ts.map +1 -0
- package/dist/score.js +1843 -0
- package/dist/score.js.map +1 -0
- package/dist/sparkline-C-cA9obz.js +56 -0
- package/dist/sparkline-C-cA9obz.js.map +1 -0
- package/dist/stats/icons.d.ts +19 -0
- package/dist/stats/icons.d.ts.map +1 -0
- package/dist/stats/index.d.ts +137 -0
- package/dist/stats/index.d.ts.map +1 -0
- package/dist/stats.js +1085 -0
- package/dist/stats.js.map +1 -0
- package/dist/stock/chart.d.ts +135 -0
- package/dist/stock/chart.d.ts.map +1 -0
- package/dist/stock/icons.d.ts +15 -0
- package/dist/stock/icons.d.ts.map +1 -0
- package/dist/stock/index.d.ts +195 -0
- package/dist/stock/index.d.ts.map +1 -0
- package/dist/stock.js +1013 -0
- package/dist/stock.js.map +1 -0
- package/dist/weather/conditions.d.ts +25 -0
- package/dist/weather/conditions.d.ts.map +1 -0
- package/dist/weather/icons.d.ts +12 -0
- package/dist/weather/icons.d.ts.map +1 -0
- package/dist/weather/index.d.ts +146 -0
- package/dist/weather/index.d.ts.map +1 -0
- package/dist/weather.js +1162 -0
- package/dist/weather.js.map +1 -0
- package/package.json +137 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"place.js","sources":["../src/place/icons.ts","../src/place/place.css?raw","../src/place/index.ts"],"sourcesContent":["/**\n * The place card's glyphs: one 24 × 24 line drawing each, in `currentColor`, so the sheet\n * colours them with the text around them — the pin, the three actions' signs, and one\n * glyph per kind of place for the placeholder and the badge.\n *\n * They live here and not in core's `icons/`: core draws no place. They are constants of\n * the package, the only markup the card parses.\n */\n\n/** The kinds of place a glyph (and a word) exists for; anything else is a `place`. */\nexport type PlaceKind = 'restaurant' | 'cafe' | 'bar' | 'hotel' | 'shop' | 'museum' | 'park' | 'gym' | 'pharmacy' | 'place';\n\nconst svg = (body: string) =>\n `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.75\" stroke-linecap=\"round\" stroke-linejoin=\"round\" xmlns=\"http://www.w3.org/2000/svg\">${body}</svg>`; // safe-text: this package's own SVG, built from its glyph constants\n\nexport const PIN = svg('<path d=\"M12 21s-6.5-5.6-6.5-11a6.5 6.5 0 0 1 13 0c0 5.4-6.5 11-6.5 11z\"/><circle cx=\"12\" cy=\"10\" r=\"2.4\"/>');\nexport const PHONE = svg('<path d=\"M5.2 4h3l1.6 4-2 1.3a10.5 10.5 0 0 0 5 5l1.3-2 4 1.6v3a2 2 0 0 1-2.1 2A15.2 15.2 0 0 1 3.2 6.1 2 2 0 0 1 5.2 4z\"/>');\nexport const GLOBE = svg('<circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M3.5 12h17M12 3.5c2.4 2.4 3.5 5.3 3.5 8.5s-1.1 6.1-3.5 8.5c-2.4-2.4-3.5-5.3-3.5-8.5s1.1-6.1 3.5-8.5z\"/>');\nexport const DIRECTIONS = svg('<path d=\"M12 2.8 21.2 12 12 21.2 2.8 12z\"/><path d=\"M9.2 14.6v-2.4a1.4 1.4 0 0 1 1.4-1.4h4.6M13.4 8.8l1.9 2-1.9 2\"/>');\nexport const CLOCK = svg('<circle cx=\"12\" cy=\"12\" r=\"8.5\"/><path d=\"M12 7.5V12l3 2\"/>');\n\nconst KIND_GLYPHS: Record<PlaceKind, string> = {\n restaurant: svg('<path d=\"M7 3v18M4.6 3v4.8A2.4 2.4 0 0 0 7 10.2a2.4 2.4 0 0 0 2.4-2.4V3M17 21V3c-2.3 1.4-3.5 4-3.5 7.2V13H17\"/>'),\n cafe: svg('<path d=\"M4.5 9h11v5.5a4.5 4.5 0 0 1-4.5 4.5H9a4.5 4.5 0 0 1-4.5-4.5z\"/><path d=\"M15.5 10.5h1.3a2.6 2.6 0 0 1 0 5.2h-1.6M8 3.5c-.6.8-.6 1.7 0 2.5M11.5 3.5c-.6.8-.6 1.7 0 2.5\"/>'),\n bar: svg('<path d=\"M5 4h14l-7 8z\"/><path d=\"M12 12v8M8.5 20h7M8.6 8h6.8\"/>'),\n hotel: svg('<path d=\"M3 18.5V6M3 14h18v4.5M21 14v-2.5a3 3 0 0 0-3-3h-7V14\"/><circle cx=\"7\" cy=\"10.5\" r=\"1.8\"/>'),\n shop: svg('<path d=\"M5.5 8h13l-1 12.5h-11z\"/><path d=\"M9 10V7a3 3 0 0 1 6 0v3\"/>'),\n museum: svg('<path d=\"M3.5 9.5 12 4l8.5 5.5zM5 20.5h14M6.5 11.5v6.5M10 11.5v6.5M14 11.5v6.5M17.5 11.5v6.5\"/>'),\n park: svg('<path d=\"M12 21v-5M12 3 6.5 11h3L6 16h12l-3.5-5h3z\"/>'),\n gym: svg('<path d=\"M6.5 7v10M17.5 7v10M3.5 9.5v5M20.5 9.5v5M6.5 12h11\"/>'),\n pharmacy: svg('<rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"4\"/><path d=\"M12 8.5v7M8.5 12h7\"/>'),\n place: PIN,\n};\n\n/** The glyph for a kind of place. */\nexport function kindGlyph(kind: PlaceKind): string {\n return KIND_GLYPHS[kind];\n}\n","export default \"/* =========================================\\n The place card — @aparte/plugin-cards/place\\n =========================================\\n Three variants of one card, chosen by `data-variant` on its root:\\n card a tile: the photo with its category, the name, the rating, whether it is\\n open, the address, three buttons. Several scroll sideways as tiles.\\n compact one row: a thumbnail, the name and the distance, the rating, the status.\\n Several are stacked rows in one card.\\n detail one place in full: the tile's head, the buttons, the ways in (address,\\n phone, site), the week's hours with today marked, the tags.\\n Every colour comes from core's tokens, or from a `--aparte-place-*` token here: the\\n three status inks and one hue per kind of place, which tint the placeholder and the\\n marker. A theme repaints the card by setting them.\\n */\\n\\n.aparte-place-card {\\n /* What \\\"open\\\", \\\"closes soon\\\" and \\\"closed\\\" are written in: the derived inks, which are\\n readable as text on either ground. */\\n --aparte-place-open: var(--aparte-success-ink);\\n --aparte-place-soon: var(--aparte-warning-ink);\\n --aparte-place-closed: var(--aparte-error-ink);\\n --aparte-place-media-ratio: 16 / 9;\\n --aparte-place-detail-ratio: 2 / 1;\\n --aparte-place-thumb-size: 3.5rem;\\n --aparte-place-on-hue: #ffffff;\\n\\n /* One hue per kind of place: the marker on the placeholder, the badge's glyph. */\\n --aparte-place-kind-restaurant: #e8710a;\\n --aparte-place-kind-cafe: #a0612b;\\n --aparte-place-kind-bar: #9c3fd1;\\n --aparte-place-kind-hotel: #2f6fdf;\\n --aparte-place-kind-shop: #d6336c;\\n --aparte-place-kind-museum: #5b5bd6;\\n --aparte-place-kind-park: #2f9e44;\\n --aparte-place-kind-gym: #e03131;\\n --aparte-place-kind-pharmacy: #0c9488;\\n --aparte-place-kind-place: var(--aparte-primary);\\n}\\n\\n/* A tile reads its kind's hue once; everything inside it says `--aparte-place-hue`. */\\n.aparte-place { --aparte-place-hue: var(--aparte-place-kind-place); }\\n.aparte-place[data-kind=\\\"restaurant\\\"] { --aparte-place-hue: var(--aparte-place-kind-restaurant); }\\n.aparte-place[data-kind=\\\"cafe\\\"] { --aparte-place-hue: var(--aparte-place-kind-cafe); }\\n.aparte-place[data-kind=\\\"bar\\\"] { --aparte-place-hue: var(--aparte-place-kind-bar); }\\n.aparte-place[data-kind=\\\"hotel\\\"] { --aparte-place-hue: var(--aparte-place-kind-hotel); }\\n.aparte-place[data-kind=\\\"shop\\\"] { --aparte-place-hue: var(--aparte-place-kind-shop); }\\n.aparte-place[data-kind=\\\"museum\\\"] { --aparte-place-hue: var(--aparte-place-kind-museum); }\\n.aparte-place[data-kind=\\\"park\\\"] { --aparte-place-hue: var(--aparte-place-kind-park); }\\n.aparte-place[data-kind=\\\"gym\\\"] { --aparte-place-hue: var(--aparte-place-kind-gym); }\\n.aparte-place[data-kind=\\\"pharmacy\\\"] { --aparte-place-hue: var(--aparte-place-kind-pharmacy); }\\n\\n/* A single tile is narrower than the card's default: it is a photo and five lines. */\\n.aparte-place-card[data-variant=\\\"card\\\"] { --aparte-rich-card-max-inline-size: 22rem; }\\n\\n/* ── The place ───────────────────────────────────────────────────────── */\\n\\n.aparte-place {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n min-inline-size: 0;\\n color: var(--aparte-text);\\n}\\n\\n.aparte-place__body {\\n display: flex;\\n flex: 1;\\n flex-direction: column;\\n gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n padding: var(--aparte-space-6) var(--aparte-space-7) var(--aparte-space-7);\\n}\\n\\n.aparte-place__name {\\n overflow: hidden;\\n font-size: var(--aparte-font-size-lg);\\n font-weight: var(--aparte-font-weight-semibold);\\n letter-spacing: -0.01em;\\n line-height: 1.25;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.aparte-place__link {\\n color: inherit;\\n text-decoration: none;\\n border-radius: var(--aparte-radius-xs);\\n}\\n\\n.aparte-place__link:hover {\\n text-decoration: underline;\\n text-decoration-thickness: 1px;\\n text-underline-offset: 0.18em;\\n}\\n\\n.aparte-place__link:focus-visible {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: var(--aparte-focus-outline-offset);\\n}\\n\\n/* A tile, a row and a lone card are one target: the name's link covers the whole of it,\\n and its buttons sit above that cover. The ring is then drawn around the target, inset,\\n because the card clips what passes its edge. */\\n.aparte-place--tile .aparte-place__name .aparte-place__link::after,\\n.aparte-place__row .aparte-place__name .aparte-place__link::after,\\n.aparte-place-card[data-variant=\\\"card\\\"] > .aparte-place .aparte-place__name .aparte-place__link::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: 0;\\n border-radius: inherit;\\n}\\n\\n.aparte-place--tile .aparte-place__name .aparte-place__link:focus-visible,\\n.aparte-place__row .aparte-place__name .aparte-place__link:focus-visible,\\n.aparte-place-card[data-variant=\\\"card\\\"] > .aparte-place .aparte-place__name .aparte-place__link:focus-visible {\\n outline: none;\\n}\\n\\n.aparte-place--tile .aparte-place__name .aparte-place__link:focus-visible::after,\\n.aparte-place__row .aparte-place__name .aparte-place__link:focus-visible::after,\\n.aparte-place-card[data-variant=\\\"card\\\"] > .aparte-place .aparte-place__name .aparte-place__link:focus-visible::after {\\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\\n outline-offset: calc(var(--aparte-focus-outline-width) * -1);\\n}\\n\\n.aparte-place--tile:hover .aparte-place__name .aparte-place__link,\\n.aparte-place__row:hover .aparte-place__name .aparte-place__link {\\n text-decoration: underline;\\n text-decoration-thickness: 1px;\\n text-underline-offset: 0.18em;\\n}\\n\\n.aparte-place__dot {\\n flex: none;\\n color: var(--aparte-text-muted);\\n opacity: 0.7;\\n}\\n\\n.aparte-place__score {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n column-gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-place__price {\\n white-space: nowrap;\\n letter-spacing: 0.04em;\\n}\\n\\n.aparte-place__price-on {\\n color: var(--aparte-text);\\n font-weight: var(--aparte-font-weight-medium);\\n}\\n\\n.aparte-place__price-off { opacity: 0.35; }\\n\\n.aparte-place__category {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n/* ── Open, closes soon, closed ───────────────────────────────────────── */\\n\\n.aparte-place__status {\\n --aparte-place-status: var(--aparte-place-open);\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n column-gap: var(--aparte-space-2);\\n margin: 0;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-place__status[data-status=\\\"soon\\\"] { --aparte-place-status: var(--aparte-place-soon); }\\n.aparte-place__status[data-status=\\\"closed\\\"] { --aparte-place-status: var(--aparte-place-closed); }\\n\\n.aparte-place__status-dot {\\n position: relative;\\n flex: none;\\n inline-size: 0.5rem;\\n block-size: 0.5rem;\\n margin-inline-end: var(--aparte-space-1);\\n border-radius: var(--aparte-radius-full);\\n background: var(--aparte-place-status);\\n box-shadow: 0 0 0 3px color-mix(in oklab, var(--aparte-place-status) 20%, transparent);\\n}\\n\\n/* An open place breathes: a ring leaves the dot every few seconds. Still under reduced motion. */\\n.aparte-place__status[data-status=\\\"open\\\"] .aparte-place__status-dot::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset: 0;\\n border-radius: inherit;\\n background: var(--aparte-place-status);\\n animation: aparte-place-pulse 2.6s ease-out infinite;\\n}\\n\\n.aparte-place__state {\\n color: var(--aparte-place-status);\\n font-weight: var(--aparte-font-weight-semibold);\\n}\\n\\n@keyframes aparte-place-pulse {\\n 0% { opacity: 0.55; transform: scale(1); }\\n 70%, 100% { opacity: 0; transform: scale(2.6); }\\n}\\n\\n/* ── Address and the lines with a glyph ──────────────────────────────── */\\n\\n.aparte-place__address {\\n display: flex;\\n align-items: center;\\n gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n margin: 0;\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n white-space: nowrap;\\n}\\n\\n.aparte-place__address-text {\\n min-inline-size: 0;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.aparte-place__distance {\\n flex: none;\\n color: var(--aparte-text);\\n font-weight: var(--aparte-font-weight-medium);\\n white-space: nowrap;\\n}\\n\\n.aparte-place__line-glyph {\\n --aparte-rich-card-glyph-size: 1rem;\\n color: var(--aparte-text-muted);\\n}\\n\\n/* ── The photo, or its placeholder ───────────────────────────────────── */\\n\\n.aparte-place__media {\\n position: relative;\\n flex: none;\\n overflow: hidden;\\n isolation: isolate;\\n background: var(--aparte-surface-2);\\n}\\n\\n.aparte-place__media--wide { aspect-ratio: var(--aparte-place-media-ratio); }\\n\\n.aparte-place__img {\\n position: absolute;\\n inset: 0;\\n z-index: 1;\\n display: block;\\n inline-size: 100%;\\n block-size: 100%;\\n object-fit: cover;\\n transition: transform var(--aparte-duration-slower, 0.3s) ease;\\n}\\n\\n.aparte-place--tile:hover .aparte-place__img,\\n.aparte-place-card[data-variant=\\\"card\\\"] > .aparte-place:hover .aparte-place__img {\\n transform: scale(1.04);\\n}\\n\\n/* No photo: a soft map in the kind's hue — two avenues, a grid of streets, a glow — and\\n the kind's marker standing on it. Decoration, drawn by the sheet: no map tile is fetched. */\\n.aparte-place__placeholder {\\n --aparte-place-street: color-mix(in oklab, var(--aparte-surface-1) 72%, transparent);\\n --aparte-place-avenue: color-mix(in oklab, var(--aparte-surface-1) 92%, transparent);\\n position: absolute;\\n inset: 0;\\n display: grid;\\n place-items: center;\\n background:\\n radial-gradient(circle at 50% 48%, color-mix(in oklab, var(--aparte-place-hue) 24%, transparent) 0 14%, transparent 48%),\\n linear-gradient(118deg, transparent 0 36%, var(--aparte-place-avenue) 36% 39.5%, transparent 39.5%),\\n linear-gradient(22deg, transparent 0 63%, var(--aparte-place-avenue) 63% 65.5%, transparent 65.5%),\\n repeating-linear-gradient(118deg, transparent 0 22px, var(--aparte-place-street) 22px 24px),\\n repeating-linear-gradient(28deg, transparent 0 31px, var(--aparte-place-street) 31px 33px),\\n color-mix(in oklab, var(--aparte-place-hue) 13%, var(--aparte-surface-2));\\n}\\n\\n/* The marker's shadow on the ground. */\\n.aparte-place__placeholder::after {\\n content: \\\"\\\";\\n position: absolute;\\n inset-block-start: calc(50% + 1.45rem);\\n inset-inline-start: 50%;\\n inline-size: 1.4rem;\\n block-size: 0.4rem;\\n margin-inline-start: -0.7rem;\\n border-radius: 50%;\\n background: rgb(0 0 0 / 0.22);\\n filter: blur(2px);\\n}\\n\\n/* A drop pin: a square with three round corners, turned so the sharp one points down. */\\n.aparte-place__marker {\\n display: grid;\\n place-items: center;\\n inline-size: 2.75rem;\\n block-size: 2.75rem;\\n margin-block-end: 0.9rem;\\n border-radius: 50% 50% 50% 0;\\n background: var(--aparte-place-hue);\\n color: var(--aparte-place-on-hue);\\n box-shadow:\\n 0 0 0 3px color-mix(in oklab, var(--aparte-surface-1) 85%, transparent),\\n 0 8px 16px -6px color-mix(in oklab, var(--aparte-place-hue) 70%, black);\\n transform: rotate(-45deg);\\n}\\n\\n.aparte-place__marker-glyph {\\n --aparte-rich-card-glyph-size: 1.3rem;\\n transform: rotate(45deg);\\n}\\n\\n.aparte-place__media--thumb {\\n inline-size: var(--aparte-place-thumb-size);\\n block-size: var(--aparte-place-thumb-size);\\n border-radius: var(--aparte-radius-lg);\\n}\\n\\n/* In a thumbnail the placeholder is only the kind's glyph on its tint. */\\n.aparte-place__media--thumb .aparte-place__placeholder {\\n background: color-mix(in oklab, var(--aparte-place-hue) 15%, var(--aparte-surface-1));\\n}\\n\\n.aparte-place__media--thumb .aparte-place__placeholder::after { content: none; }\\n\\n.aparte-place__media--thumb .aparte-place__marker {\\n inline-size: auto;\\n block-size: auto;\\n margin: 0;\\n border-radius: 0;\\n background: none;\\n box-shadow: none;\\n color: var(--aparte-place-hue);\\n transform: none;\\n}\\n\\n.aparte-place__media--thumb .aparte-place__marker-glyph {\\n --aparte-rich-card-glyph-size: 1.5rem;\\n transform: none;\\n}\\n\\n/* The category, over the photo: a frosted chip, which reads on any picture. */\\n.aparte-place__badge {\\n position: absolute;\\n inset-block-start: var(--aparte-space-5);\\n inset-inline-start: var(--aparte-space-5);\\n z-index: 2;\\n display: inline-flex;\\n align-items: center;\\n gap: var(--aparte-space-2);\\n max-inline-size: calc(100% - var(--aparte-space-5) * 2);\\n padding-block: var(--aparte-space-2);\\n padding-inline: var(--aparte-space-3) var(--aparte-space-4);\\n border-radius: var(--aparte-radius-full);\\n background: color-mix(in oklab, var(--aparte-surface-1) 86%, transparent);\\n backdrop-filter: blur(8px) saturate(1.4);\\n box-shadow: 0 1px 4px rgb(0 0 0 / 0.14);\\n color: var(--aparte-text);\\n font-size: var(--aparte-font-size-sm);\\n font-weight: var(--aparte-font-weight-medium);\\n line-height: 1.2;\\n}\\n\\n.aparte-place__badge-glyph {\\n --aparte-rich-card-glyph-size: 0.95rem;\\n color: var(--aparte-place-hue);\\n}\\n\\n/* ── Buttons ─────────────────────────────────────────────────────────── */\\n\\n.aparte-place__actions {\\n position: relative;\\n z-index: 3;\\n display: flex;\\n flex-wrap: wrap;\\n gap: var(--aparte-space-3);\\n margin-block-start: var(--aparte-space-5);\\n}\\n\\n.aparte-place__action {\\n gap: var(--aparte-space-2);\\n}\\n\\n/* ── Several, side by side ───────────────────────────────────────────── */\\n\\n/* Tiles in a row carry their own frame, so the card around them steps back. */\\n.aparte-place-card:has(> .aparte-place__collection) {\\n --aparte-rich-card-max-inline-size: 40rem;\\n overflow: visible;\\n border-color: transparent;\\n background: transparent;\\n}\\n\\n.aparte-place__collection {\\n display: grid;\\n gap: var(--aparte-space-4);\\n min-inline-size: 0;\\n}\\n\\n.aparte-place__collection .aparte-rich-card__carousel {\\n --aparte-rich-card-slide-size: min(15rem, 80%);\\n}\\n\\n.aparte-place__heading {\\n display: flex;\\n align-items: center;\\n gap: var(--aparte-space-3);\\n min-inline-size: 0;\\n font-size: var(--aparte-font-size-md);\\n font-weight: var(--aparte-font-weight-semibold);\\n}\\n\\n.aparte-place__heading-text {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.aparte-place__collection > .aparte-place__heading { padding-inline: var(--aparte-space-2); }\\n\\n.aparte-place--tile {\\n block-size: 100%;\\n overflow: hidden;\\n border: var(--aparte-border-width) solid var(--aparte-border);\\n border-radius: var(--aparte-radius-xl);\\n background: var(--aparte-surface-1);\\n transition:\\n border-color var(--aparte-duration-base, 0.15s) ease,\\n box-shadow var(--aparte-duration-base, 0.15s) ease;\\n}\\n\\n.aparte-place--tile:hover {\\n border-color: color-mix(in oklab, var(--aparte-text) 20%, var(--aparte-border));\\n box-shadow: 0 10px 24px -16px rgb(0 0 0 / 0.5);\\n}\\n\\n.aparte-place--tile .aparte-place__body {\\n padding: var(--aparte-space-5) var(--aparte-space-6) var(--aparte-space-6);\\n}\\n\\n.aparte-place--tile .aparte-place__name { font-size: var(--aparte-font-size-base); }\\n\\n/* The buttons sit on the tile's floor, so a row of tiles lines them up. */\\n.aparte-place--tile .aparte-place__actions { margin-block-start: auto; padding-block-start: var(--aparte-space-5); }\\n\\n/* ── Compact: rows ───────────────────────────────────────────────────── */\\n\\n.aparte-place__row {\\n flex-direction: row;\\n align-items: center;\\n gap: var(--aparte-space-5);\\n padding: var(--aparte-space-5) var(--aparte-space-6);\\n transition: background-color var(--aparte-duration-fast, 0.12s) ease;\\n}\\n\\n.aparte-place__text {\\n display: flex;\\n flex: 1;\\n flex-direction: column;\\n gap: var(--aparte-space-1);\\n min-inline-size: 0;\\n}\\n\\n.aparte-place__row-head {\\n display: flex;\\n align-items: baseline;\\n gap: var(--aparte-space-3);\\n min-inline-size: 0;\\n}\\n\\n.aparte-place__row .aparte-place__name {\\n flex: 1;\\n min-inline-size: 0;\\n font-size: var(--aparte-font-size-base);\\n}\\n\\n.aparte-place__row .aparte-place__distance {\\n color: var(--aparte-text-muted);\\n font-size: var(--aparte-font-size-sm);\\n}\\n\\n.aparte-place__row .aparte-place__score,\\n.aparte-place__row .aparte-place__status { font-size: var(--aparte-font-size-xs); }\\n\\n.aparte-place__row .aparte-place__score { flex-wrap: nowrap; overflow: hidden; }\\n\\n.aparte-place__list {\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n}\\n\\n.aparte-place__list > li + li { border-block-start: var(--aparte-border-width) solid var(--aparte-border); }\\n\\n.aparte-place__list > .aparte-place__row:hover,\\n.aparte-place-card[data-variant=\\\"compact\\\"] > .aparte-place__row:hover {\\n background: color-mix(in oklab, var(--aparte-text) 4%, transparent);\\n}\\n\\n.aparte-place-card[data-variant=\\\"compact\\\"] > .aparte-place__heading {\\n padding: var(--aparte-space-5) var(--aparte-space-6) var(--aparte-space-3);\\n border-block-end: var(--aparte-border-width) solid var(--aparte-border);\\n}\\n\\n/* ── Detail ──────────────────────────────────────────────────────────── */\\n\\n.aparte-place--detail .aparte-place__media--wide { aspect-ratio: var(--aparte-place-detail-ratio); }\\n\\n.aparte-place--detail .aparte-place__body {\\n gap: var(--aparte-space-7);\\n padding: var(--aparte-space-7) var(--aparte-space-8) var(--aparte-space-8);\\n}\\n\\n.aparte-place__head {\\n display: flex;\\n flex-direction: column;\\n gap: var(--aparte-space-2);\\n min-inline-size: 0;\\n}\\n\\n.aparte-place--detail .aparte-place__name {\\n font-size: var(--aparte-font-size-xl);\\n white-space: normal;\\n}\\n\\n.aparte-place--detail .aparte-place__score,\\n.aparte-place--detail .aparte-place__status { font-size: var(--aparte-font-size-md); }\\n\\n.aparte-place--detail .aparte-place__actions { margin: 0; }\\n\\n.aparte-place__info {\\n display: grid;\\n gap: var(--aparte-space-5);\\n margin: 0;\\n padding: var(--aparte-space-6) 0 0;\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n list-style: none;\\n font-size: var(--aparte-font-size-md);\\n}\\n\\n.aparte-place__info > li {\\n display: flex;\\n align-items: flex-start;\\n gap: var(--aparte-space-4);\\n min-inline-size: 0;\\n overflow-wrap: anywhere;\\n}\\n\\n.aparte-place__info .aparte-place__line-glyph { margin-block-start: 0.1em; }\\n.aparte-place__info .aparte-place__address-text { white-space: normal; }\\n.aparte-place__info .aparte-place__link { color: var(--aparte-primary-ink, var(--aparte-text)); }\\n\\n.aparte-place__hours {\\n inline-size: 100%;\\n border-collapse: collapse;\\n font-size: var(--aparte-font-size-md);\\n}\\n\\n.aparte-place__hours-title {\\n padding-block: var(--aparte-space-6) var(--aparte-space-3);\\n border-block-start: var(--aparte-border-width) solid var(--aparte-border);\\n font-weight: var(--aparte-font-weight-semibold);\\n text-align: start;\\n}\\n\\n.aparte-place__hours-title .aparte-place__line-glyph {\\n margin-inline-end: var(--aparte-space-3);\\n vertical-align: -0.15em;\\n}\\n\\n.aparte-place__hours th,\\n.aparte-place__hours td {\\n padding-block: var(--aparte-space-2);\\n vertical-align: top;\\n}\\n\\n.aparte-place__hours th {\\n padding-inline: var(--aparte-space-3) var(--aparte-space-6);\\n color: var(--aparte-text-muted);\\n font-weight: var(--aparte-font-weight-normal);\\n text-align: start;\\n white-space: nowrap;\\n}\\n\\n/* `Intl` writes \\\"lundi\\\" for the middle of a sentence; a row's label starts with a capital. */\\n.aparte-place__hours th::first-letter { text-transform: uppercase; }\\n\\n.aparte-place__hours td {\\n padding-inline-end: var(--aparte-space-3);\\n text-align: end;\\n}\\n\\n.aparte-place__hours tr[data-closed] td { color: var(--aparte-place-closed); }\\n\\n/* Today: the first row, on a band of the accent, in full ink. */\\n.aparte-place__hours tr[aria-current] > * {\\n background: color-mix(in oklab, var(--aparte-primary) 10%, transparent);\\n color: var(--aparte-text);\\n font-weight: var(--aparte-font-weight-semibold);\\n}\\n\\n.aparte-place__hours tr[aria-current] > :first-child {\\n border-start-start-radius: var(--aparte-radius-md);\\n border-end-start-radius: var(--aparte-radius-md);\\n}\\n\\n.aparte-place__hours tr[aria-current] > :last-child {\\n border-start-end-radius: var(--aparte-radius-md);\\n border-end-end-radius: var(--aparte-radius-md);\\n}\\n\\n.aparte-place__tags {\\n display: flex;\\n flex-wrap: wrap;\\n gap: var(--aparte-space-2);\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n}\\n\\n/* ── Loading ─────────────────────────────────────────────────────────── */\\n\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-media {\\n block-size: auto;\\n border-radius: 0;\\n}\\n\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-thumb {\\n flex: none;\\n block-size: var(--aparte-place-thumb-size);\\n border-radius: var(--aparte-radius-lg);\\n}\\n\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-name { inline-size: 60%; block-size: 1.1rem; }\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-line { inline-size: 80%; }\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-line--short { inline-size: 50%; }\\n\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-actions {\\n display: flex;\\n gap: var(--aparte-space-3);\\n margin-block-start: var(--aparte-space-5);\\n}\\n\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-btn {\\n inline-size: 6rem;\\n block-size: 2rem;\\n border-radius: var(--aparte-radius-full);\\n}\\n\\n.aparte-place-card[data-state=\\\"loading\\\"] .aparte-place__sk-hours {\\n display: grid;\\n gap: var(--aparte-space-3);\\n margin-block-start: var(--aparte-space-5);\\n}\\n\\n/* ── Small screens, and stillness ────────────────────────────────────── */\\n\\n@media (max-width: 380px) {\\n .aparte-place__body { padding: var(--aparte-space-5) var(--aparte-space-6) var(--aparte-space-6); }\\n .aparte-place--detail .aparte-place__body { padding: var(--aparte-space-6); }\\n .aparte-place__actions > .aparte-place__action:not(.aparte-btn--icon) { flex: 1 1 auto; justify-content: center; }\\n .aparte-place__collection .aparte-rich-card__carousel { --aparte-rich-card-slide-size: 84%; }\\n .aparte-place__hours th { padding-inline-end: var(--aparte-space-4); }\\n .aparte-place-card { --aparte-place-thumb-size: 3rem; }\\n}\\n\\n@media (prefers-reduced-motion: reduce) {\\n .aparte-place--tile:hover .aparte-place__img,\\n .aparte-place-card[data-variant=\\\"card\\\"] > .aparte-place:hover .aparte-place__img { transform: none; }\\n .aparte-place__status-dot::after { content: none; }\\n}\\n\"","/**\n * @aparte/plugin-cards/place — a tool's places, drawn as cards: a restaurant, a shop, a\n * hotel, a venue, with its rating, whether it is open now, and the way there.\n *\n * import { setupPlaceCard } from '@aparte/plugin-cards/place';\n *\n * setupPlaceCard({ tool: 'search_places', map: (result) => result.results });\n *\n * One place or several (`[...]`, or `{ title, places: [...] }`). Three variants of one\n * card: `card` (a tile with its photo; several scroll sideways), `compact` (one row each,\n * stacked) and `detail` (one place in full, with its week of opening hours). Your tool keeps\n * its own fields: `readPlaces` reads the usual names for each (Google Places, both\n * generations, Yelp, OpenStreetMap-ish tools, what a model writes by hand), and `map` says\n * the rest.\n *\n * Whether a place is open is worked out when the card is drawn, from its weekly `hours`\n * (`isOpenAt`, `placeStatus`) — Google's current hours, holidays included, before its\n * regular week — else from the tool's own `openNow`. The three buttons a place\n * gets for free — Directions, Call, Website — appear only when its data can honour them,\n * and an app that passes its own `actions` replaces them.\n */\nimport type { AparteConfig } from '@aparte/core';\nimport { carousel } from '../kit/carousel.js';\nimport { defineCard, type CardContext, type CardSetupOptions } from '../kit/define.js';\nimport { el, glyph, num, safeUrl, str, type Loose } from '../kit/dom.js';\nimport { formatNumber, formatUnit } from '../kit/format.js';\nimport { rating } from '../kit/rating.js';\nimport { intlTag, word, type CardWord } from '../kit/strings.js';\nimport { CLOCK, DIRECTIONS, GLOBE, PHONE, PIN, kindGlyph, type PlaceKind } from './icons.js';\nimport placeStyles from './place.css?raw';\n\nexport type { PlaceKind } from './icons.js';\nexport type PlaceVariant = 'card' | 'compact' | 'detail';\n\n/** One opening range of the week, as a tool writes it. */\nexport interface PlaceHoursInput {\n /** 0 = Sunday … 6 = Saturday (7 reads as Sunday too), or an English day name (\"mon\", \"Monday\"). */\n day: number | string;\n /** \"09:00\", \"9:30\", \"0900\", \"21h30\", \"9 PM\". */\n open: string;\n /** Past midnight is fine (\"02:00\" after \"18:00\"). Missing, or \"24:00\", is midnight. */\n close?: string;\n}\n\n/** An opening range once read: minutes from the start of `day`. `end` passes 1440 when it closes after midnight. */\nexport interface PlaceHoursRange {\n day: number;\n start: number;\n end: number;\n}\n\n/**\n * A place as `map` returns it. Only `name` is needed; every other field adds a line when it\n * is there and nothing when it is not. `readPlaces` also reads the usual aliases (listed on\n * each field).\n */\nexport interface PlaceInput {\n /** Also `title`, `displayName`. */\n name: string;\n /** Shown as it is: \"Trattoria\", \"Boulangerie\". Also `primaryTypeDisplayName`, `categories[0]`. */\n category?: string;\n /** Google's `types`, read only to choose a glyph and, without `category`, a word. */\n types?: string[];\n /** An `http(s)` photo. Also `photo`, `imageUrl`, `thumbnail`, `photos[0]`. */\n image?: string;\n /** 0–5 (a 10-point score is halved). */\n rating?: number;\n /** Also `user_ratings_total`, `userRatingCount`, `reviews`, `review_count`. */\n reviewCount?: number;\n /** 1–4, `\"€€\"`, or Google's `\"PRICE_LEVEL_MODERATE\"`; any other text is shown as it is (\"€10–20\"). Also `price_level`. */\n priceLevel?: number | string;\n /** Also `formatted_address`, `formattedAddress`, `vicinity`, Yelp's `location.display_address`. */\n address?: string;\n /** In metres; a text (\"12 min walk\") is shown as it is. Also `distanceMeters`. */\n distance?: number | string;\n /** Also `formatted_phone_number`, `international_phone_number`, `nationalPhoneNumber`. */\n phone?: string;\n /** The place's own site. Also `websiteUri`. */\n website?: string;\n /** The place's page (on a map, a guide); the name links to it. Also `googleMapsUri`. */\n url?: string;\n /** Also `lat`/`lng`, `latitude`/`longitude`, `geometry.location`, `location`. */\n coordinates?: { lat: number; lng: number };\n /** Google's place id, which makes Directions land on the place itself. Also `place_id`. */\n placeId?: string;\n /** The tool's own answer; `hours` wins when both are given. Also `open_now`, `isOpen`, `opening_hours.open_now`, Yelp's `hours[0].is_open_now`. */\n openNow?: boolean;\n /**\n * The week's opening hours: `[{ day, open, close }]` (several ranges a day, closing past\n * midnight), Google's `periods` or `weekday_text`, Yelp's `hours`, or\n * `{ monday: \"09:00-18:00\", sunday: \"closed\" }`. Also `currentOpeningHours` (read first:\n * it has the holidays), `regularOpeningHours`, `opening_hours`, `openingHours`.\n */\n hours?: PlaceHoursInput[] | Record<string, unknown> | string[];\n /** The place's offset from UTC in minutes, so \"Open now\" is read on the place's clock. Also `utc_offset_minutes`. */\n utcOffset?: number;\n /** At most four short facts: \"Terrace\", \"Vegan\". Also `features`, `amenities`. */\n tags?: string[];\n}\n\n/** A price level once read: the tier, and the sign the source wrote it with, if it did. */\nexport interface PlacePrice {\n level: number;\n symbol?: string;\n}\n\n/** A place as the card draws it, once read. */\nexport interface Place {\n name: string;\n category?: string;\n kind: PlaceKind;\n image?: string;\n rating?: number;\n reviewCount?: number;\n price?: PlacePrice;\n priceText?: string;\n address?: string;\n distance?: number;\n distanceText?: string;\n phone?: string;\n website?: string;\n url?: string;\n coordinates?: { lat: number; lng: number };\n placeId?: string;\n openNow?: boolean;\n hours: PlaceHoursRange[];\n utcOffset?: number;\n tags: string[];\n}\n\n/** The card's data: one place or several, and the collection's title. */\nexport interface PlaceData {\n title?: string;\n places: Place[];\n}\n\n/** Whether a place is open at a moment, and when that changes (none: it never does). */\nexport interface PlaceStatus {\n open: boolean;\n changesAt?: Date;\n}\n\n/** How an app plugs the place card in: the kit's options, and two of the card's own. */\nexport interface PlaceCardOptions extends CardSetupOptions<PlaceData, PlaceVariant> {\n /**\n * The sign a price TIER (1–4) is drawn with. A tier is a scale, not an amount — Google\n * and Yelp return a number, not a currency — so the card cannot know the place's money.\n * `$` by default, the sign those APIs' own documentation uses; a European app passes `€`.\n * A tier the source wrote with its own sign (\"€€\") keeps it. Read aloud as\n * \"Price level 2 of 4\" either way.\n */\n currencySymbol?: string;\n /** The clock \"Open now\" is read against — the device's by default; a test or a replay passes its own. */\n now?: () => Date;\n /**\n * The Directions / Call / Website buttons on each place, drawn from its data (`true` by\n * default). They are the place's own; the app's `actions` are the card's, under it, and\n * one does not replace the other. `false` draws none.\n */\n builtIns?: boolean;\n}\n\nconst P = {\n cardsPlaceTitle: { en: 'Places', fr: 'Lieux', de: 'Orte', es: 'Lugares', it: 'Luoghi', ja: '場所', ko: '장소', pt: 'Lugares', ru: 'Места', zh: '地点' },\n cardsPlaceCount: { en: '{n} places', fr: '{n} lieux', de: '{n} Orte', es: '{n} lugares', it: '{n} luoghi', ja: '{n}件の場所', ko: '장소 {n}곳', pt: '{n} lugares', ru: 'Мест: {n}', zh: '{n} 个地点' },\n cardsPlaceOpen: { en: 'Open', fr: 'Ouvert', de: 'Geöffnet', es: 'Abierto', it: 'Aperto', ja: '営業中', ko: '영업 중', pt: 'Aberto', ru: 'Открыто', zh: '营业中' },\n cardsPlaceClosed: { en: 'Closed', fr: 'Fermé', de: 'Geschlossen', es: 'Cerrado', it: 'Chiuso', ja: '営業時間外', ko: '영업 종료', pt: 'Fechado', ru: 'Закрыто', zh: '已打烊' },\n cardsPlaceClosesSoon: { en: 'Closes soon', fr: 'Ferme bientôt', de: 'Schließt bald', es: 'Cierra pronto', it: 'Chiude a breve', ja: 'まもなく営業終了', ko: '곧 영업 종료', pt: 'Fecha em breve', ru: 'Скоро закроется', zh: '即将打烊' },\n cardsPlaceClosesAt: { en: 'Closes at {t}', fr: 'Ferme à {t}', de: 'Schließt um {t}', es: 'Cierra a las {t}', it: 'Chiude alle {t}', ja: '{t}に営業終了', ko: '{t}에 영업 종료', pt: 'Fecha às {t}', ru: 'Закроется в {t}', zh: '{t}打烊' },\n cardsPlaceClosesOn: { en: 'Closes {day} at {t}', fr: 'Ferme {day} à {t}', de: 'Schließt {day} um {t}', es: 'Cierra el {day} a las {t}', it: 'Chiude {day} alle {t}', ja: '{day}の{t}に営業終了', ko: '{day} {t}에 영업 종료', pt: 'Fecha {day} às {t}', ru: 'Закроется: {day}, {t}', zh: '{day}{t}打烊' },\n cardsPlaceOpensAt: { en: 'Opens at {t}', fr: 'Ouvre à {t}', de: 'Öffnet um {t}', es: 'Abre a las {t}', it: 'Apre alle {t}', ja: '{t}に営業開始', ko: '{t}에 영업 시작', pt: 'Abre às {t}', ru: 'Откроется в {t}', zh: '{t}开始营业' },\n cardsPlaceOpensTomorrow: { en: 'Opens tomorrow at {t}', fr: 'Ouvre demain à {t}', de: 'Öffnet morgen um {t}', es: 'Abre mañana a las {t}', it: 'Apre domani alle {t}', ja: '明日{t}に営業開始', ko: '내일 {t}에 영업 시작', pt: 'Abre amanhã às {t}', ru: 'Откроется завтра в {t}', zh: '明天{t}开始营业' },\n cardsPlaceOpensOn: { en: 'Opens {day} at {t}', fr: 'Ouvre {day} à {t}', de: 'Öffnet {day} um {t}', es: 'Abre el {day} a las {t}', it: 'Apre {day} alle {t}', ja: '{day}の{t}に営業開始', ko: '{day} {t}에 영업 시작', pt: 'Abre {day} às {t}', ru: 'Откроется: {day}, {t}', zh: '{day}{t}开始营业' },\n cardsPlaceAlwaysOpen: { en: 'Open 24 hours', fr: 'Ouvert 24 h/24', de: 'Rund um die Uhr geöffnet', es: 'Abierto 24 horas', it: 'Aperto 24 ore su 24', ja: '24時間営業', ko: '24시간 영업', pt: 'Aberto 24 horas', ru: 'Круглосуточно', zh: '24小时营业' },\n cardsPlaceDirections: { en: 'Directions', fr: 'Itinéraire', de: 'Route', es: 'Cómo llegar', it: 'Indicazioni', ja: 'ルート', ko: '길찾기', pt: 'Rotas', ru: 'Маршрут', zh: '路线' },\n cardsPlaceCall: { en: 'Call', fr: 'Appeler', de: 'Anrufen', es: 'Llamar', it: 'Chiama', ja: '電話', ko: '전화', pt: 'Ligar', ru: 'Позвонить', zh: '致电' },\n cardsPlaceWebsite: { en: 'Website', fr: 'Site web', de: 'Website', es: 'Sitio web', it: 'Sito web', ja: 'ウェブサイト', ko: '웹사이트', pt: 'Site', ru: 'Сайт', zh: '网站' },\n cardsPlaceHours: { en: 'Hours', fr: 'Horaires', de: 'Öffnungszeiten', es: 'Horario', it: 'Orari', ja: '営業時間', ko: '영업시간', pt: 'Horário', ru: 'Часы работы', zh: '营业时间' },\n cardsPlacePrice: { en: 'Price level {level} of {max}', fr: 'Gamme de prix {level} sur {max}', de: 'Preisniveau {level} von {max}', es: 'Nivel de precio {level} de {max}', it: 'Fascia di prezzo {level} su {max}', ja: '価格帯 {max}段階中{level}', ko: '가격대 {max}단계 중 {level}', pt: 'Faixa de preço {level} de {max}', ru: 'Уровень цен: {level} из {max}', zh: '价格等级 {level}/{max}' },\n cardsPlacePhoto: { en: 'Photo of {name}', fr: 'Photo de {name}', de: 'Foto von {name}', es: 'Foto de {name}', it: 'Foto di {name}', ja: '{name}の写真', ko: '{name} 사진', pt: 'Foto de {name}', ru: 'Фото: {name}', zh: '{name}的照片' },\n} satisfies Record<string, CardWord>;\n\n/** A kind's name, for the badge of a place whose tool gave only Google-style `types`. */\nconst KIND_WORDS: Record<Exclude<PlaceKind, 'place'>, CardWord> = {\n restaurant: { en: 'Restaurant', fr: 'Restaurant', de: 'Restaurant', es: 'Restaurante', it: 'Ristorante', ja: 'レストラン', ko: '음식점', pt: 'Restaurante', ru: 'Ресторан', zh: '餐厅' },\n cafe: { en: 'Café', fr: 'Café', de: 'Café', es: 'Cafetería', it: 'Caffè', ja: 'カフェ', ko: '카페', pt: 'Café', ru: 'Кафе', zh: '咖啡馆' },\n bar: { en: 'Bar', fr: 'Bar', de: 'Bar', es: 'Bar', it: 'Bar', ja: 'バー', ko: '바', pt: 'Bar', ru: 'Бар', zh: '酒吧' },\n hotel: { en: 'Hotel', fr: 'Hôtel', de: 'Hotel', es: 'Hotel', it: 'Hotel', ja: 'ホテル', ko: '호텔', pt: 'Hotel', ru: 'Отель', zh: '酒店' },\n shop: { en: 'Shop', fr: 'Boutique', de: 'Geschäft', es: 'Tienda', it: 'Negozio', ja: 'ショップ', ko: '상점', pt: 'Loja', ru: 'Магазин', zh: '商店' },\n museum: { en: 'Museum', fr: 'Musée', de: 'Museum', es: 'Museo', it: 'Museo', ja: '博物館', ko: '박물관', pt: 'Museu', ru: 'Музей', zh: '博物馆' },\n park: { en: 'Park', fr: 'Parc', de: 'Park', es: 'Parque', it: 'Parco', ja: '公園', ko: '공원', pt: 'Parque', ru: 'Парк', zh: '公园' },\n gym: { en: 'Gym', fr: 'Salle de sport', de: 'Fitnessstudio', es: 'Gimnasio', it: 'Palestra', ja: 'ジム', ko: '헬스장', pt: 'Academia', ru: 'Спортзал', zh: '健身房' },\n pharmacy: { en: 'Pharmacy', fr: 'Pharmacie', de: 'Apotheke', es: 'Farmacia', it: 'Farmacia', ja: '薬局', ko: '약국', pt: 'Farmácia', ru: 'Аптека', zh: '药店' },\n};\n\n/** The most places one card draws; a search that returns forty is a list, not a card. */\nconst MAX_PLACES = 10;\nconst MAX_TAGS = 4;\nconst PRICE_MAX = 4;\n/** Within this many minutes of closing, \"Open\" turns to \"Closes soon\". */\nconst SOON = 60;\nconst DAY = 1440;\nconst WEEK = 7 * DAY;\n\n// ── Reading ──────────────────────────────────────────────────────────────────\n\nconst DAY_NAMES = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n\nfunction readDay(value: unknown): number | undefined {\n const n = num(value);\n if (n !== undefined) return Number.isInteger(n) && n >= 0 && n <= 7 ? n % 7 : undefined;\n if (typeof value !== 'string') return undefined;\n const i = DAY_NAMES.indexOf(value.trim().slice(0, 3).toLowerCase());\n return i >= 0 ? i : undefined;\n}\n\n/** Minutes from midnight: \"09:00\", \"9:30\", \"0900\", \"21h30\", \"9 PM\", Google's `{ hour, minute }`. */\nexport function readTime(value: unknown): number | undefined {\n if (value && typeof value === 'object') {\n const o = value as Record<string, unknown>;\n const h = num(o['hour']);\n const m = num(o['minute']) ?? 0;\n return h !== undefined && h >= 0 && h <= 24 && m >= 0 && m < 60 ? h * 60 + m : undefined;\n }\n const s = str(value);\n if (!s) return undefined;\n const match = /^(\\d{1,2})(?:\\s*[:h.]\\s*)?(\\d{2})?\\s*(?:([ap])\\.?\\s*m\\.?)?$/i.exec(s);\n if (!match) return undefined;\n let h = Number(match[1]);\n const m = match[2] ? Number(match[2]) : 0;\n const half = match[3]?.toLowerCase();\n if (m > 59) return undefined;\n if (half) {\n if (h < 1 || h > 12) return undefined;\n h = (h % 12) + (half === 'p' ? 12 : 0);\n }\n if (h > 24 || (h === 24 && m > 0)) return undefined;\n return h * 60 + m;\n}\n\n/** The ranges a day's text says: \"09:00-12:00, 14:00-18:00\", \"9:00 AM – 5:00 PM\", \"Closed\", \"Open 24 hours\". */\nfunction rangesOfText(day: number, value: unknown): PlaceHoursRange[] {\n const parts = Array.isArray(value) ? value : typeof value === 'string' ? value.split(/\\s*[,;]\\s*/) : [];\n const out: PlaceHoursRange[] = [];\n for (const part of parts) {\n if (typeof part !== 'string') continue;\n const [from, to] = part.split(/\\s*[-–—]\\s*|\\s+to\\s+/i);\n // \"Open 24 hours\", \"24h/24\" — but not the end of a range: \"18h-24h\" closes at midnight.\n if (to === undefined && /24\\s*(h|hours|heures|\\/\\s*24)/i.test(part)) {\n out.push({ day, start: 0, end: DAY });\n continue;\n }\n let end = readTime(to);\n const start = sharedMeridiem(from, to, end) ?? readTime(from);\n if (start === undefined || end === undefined) continue;\n if (end <= start) end += DAY;\n out.push({ day, start, end });\n }\n return out;\n}\n\n/**\n * The start of a range that writes AM/PM once, at its end — Google's \"5:00 – 10:00 PM\" is\n * five in the evening. The end's meridiem is lent to the start only when that keeps the\n * start before the end: \"9:00 – 5:00 PM\" stays nine in the morning.\n */\nfunction sharedMeridiem(from: string | undefined, to: string | undefined, end: number | undefined): number | undefined {\n const MERIDIEM = /([ap])\\.?\\s*m\\.?\\s*$/i;\n const half = to !== undefined ? MERIDIEM.exec(to) : null;\n if (!from || !half || end === undefined || /[ap]\\.?\\s*m\\.?\\s*$/i.test(from)) return undefined;\n const start = readTime(`${from} ${half[1]}M`);\n return start !== undefined && start < end ? start : undefined;\n}\n\n/**\n * A range longer than a day — open from Friday evening to Sunday night, or around the clock\n * (Google writes that as one period with no close) — split at each midnight, so the week's\n * table shows every day it covers instead of the day it started.\n */\nfunction splitLong(range: PlaceHoursRange): PlaceHoursRange[] {\n if (range.end - range.start <= DAY) return [range];\n const out: PlaceHoursRange[] = [];\n let at = range.day * DAY + range.start;\n const stop = Math.min(range.day * DAY + range.end, range.day * DAY + range.start + WEEK);\n while (at < stop) {\n const midnight = (Math.floor(at / DAY) + 1) * DAY;\n const end = Math.min(stop, midnight);\n out.push({ day: Math.floor(at / DAY) % 7, start: at % DAY, end: end - Math.floor(at / DAY) * DAY });\n at = end;\n }\n return out;\n}\n\n/**\n * The week's opening hours from the shapes tools write them in: `[{ day, open, close }]`,\n * Google's `periods` (`{ open: { day, time | hour, minute }, close }`), its `weekday_text`\n * (\"Monday: 9:00 AM – 5:00 PM\"), or a week by name (`{ monday: \"09:00-18:00\" }`).\n * Anything it cannot read is left out.\n */\nexport function readHours(raw: unknown): PlaceHoursRange[] {\n if (!raw || typeof raw !== 'object') return [];\n if (!Array.isArray(raw)) {\n const o = raw as Record<string, unknown>;\n for (const key of ['periods', 'weekday_text', 'weekdayDescriptions']) {\n if (Array.isArray(o[key])) return readHours(o[key]);\n }\n const out: PlaceHoursRange[] = [];\n for (const [key, value] of Object.entries(o)) {\n if (!/^[a-z]+$/i.test(key)) continue;\n const day = readDay(key);\n if (day !== undefined) out.push(...rangesOfText(day, value));\n }\n return tidy(out);\n }\n const yelp = raw.filter((item): item is Loose => !!item && typeof item === 'object' && Array.isArray((item as Loose)['open']));\n if (yelp.length) return tidy(yelpRanges(yelp));\n const out: PlaceHoursRange[] = [];\n for (const item of raw) {\n if (typeof item === 'string') {\n const line = /^\\s*([A-Za-z]+)\\s*:\\s*(.+)$/.exec(item);\n const day = line ? readDay(line[1]) : undefined;\n if (line && day !== undefined) out.push(...rangesOfText(day, line[2]));\n continue;\n }\n if (!item || typeof item !== 'object') continue;\n const r = item as Record<string, unknown>;\n if (typeof r['start'] === 'number' && typeof r['end'] === 'number') {\n // Already read.\n const day = readDay(r['day']);\n if (day !== undefined && r['end'] > r['start']) out.push({ day, start: r['start'], end: r['end'] });\n continue;\n }\n if (r['open'] && typeof r['open'] === 'object') {\n // Google's period: the opening and the closing each carry their own day.\n const o = r['open'] as Record<string, unknown>;\n const day = readDay(o['day']);\n const start = readTime(o['time'] ?? o);\n if (day === undefined || start === undefined) continue;\n const c = r['close'];\n if (!c || typeof c !== 'object') {\n // Google's documented \"always open\" is one period, Sunday 00:00, with no close.\n // A missing close anywhere else is not documented: read it as midnight, as the\n // plain `{ day, open }` shape does, rather than as the whole week.\n out.push({ day, start, end: day === 0 && start === 0 ? WEEK : DAY });\n continue;\n }\n const cDay = readDay((c as Record<string, unknown>)['day']);\n const cTime = readTime((c as Record<string, unknown>)['time'] ?? c);\n if (cDay === undefined || cTime === undefined) continue;\n let end = ((cDay - day + 7) % 7) * DAY + cTime;\n if (end <= start) end += WEEK;\n out.push({ day, start, end });\n continue;\n }\n const day = readDay(r['day'] ?? r['weekday']);\n const start = readTime(r['open'] ?? r['opens'] ?? r['from']);\n if (day === undefined || start === undefined) continue;\n const close = r['close'] ?? r['closes'] ?? r['to'];\n let end = close === undefined || close === null || close === '' ? DAY : readTime(close);\n if (end === undefined) continue;\n if (end <= start) end += DAY;\n out.push({ day, start, end });\n }\n return tidy(out);\n}\n\n/**\n * Yelp Fusion's `hours`: `[{ hour_type, is_open_now, open: [{ day, start, end, is_overnight }] }]`,\n * where `day` 0 is MONDAY and the times are \"HHMM\" (\"0700\", \"2130\"). Only the regular week:\n * another `hour_type` (special hours) would mix into it.\n */\nfunction yelpRanges(entries: Loose[]): PlaceHoursRange[] {\n const regular = entries.filter((e) => !str(e['hour_type']) || /regular/i.test(String(e['hour_type'])));\n const out: PlaceHoursRange[] = [];\n for (const entry of regular.length ? regular : entries.slice(0, 1)) {\n for (const range of entry['open'] as unknown[]) {\n const r = (range ?? {}) as Loose;\n const n = num(r['day']);\n const hhmm = (v: unknown) => readTime(str(v)?.padStart(4, '0'));\n const start = hhmm(r['start']);\n let end = hhmm(r['end']);\n if (n === undefined || !Number.isInteger(n) || n < 0 || n > 6 || start === undefined || end === undefined) continue;\n // `is_overnight`: the end is on the next day, which an end before the start says too.\n if (end <= start) end += DAY;\n out.push({ day: (n + 1) % 7, start, end });\n }\n }\n return out;\n}\n\nfunction tidy(ranges: PlaceHoursRange[]): PlaceHoursRange[] {\n return ranges.flatMap(splitLong).sort((a, b) => a.day - b.day || a.start - b.start);\n}\n\n/** The week's open spans in minutes from Sunday 00:00, repeated a week either side and merged. */\nfunction spans(ranges: PlaceHoursRange[]): Array<[number, number]> {\n const list: Array<[number, number]> = [];\n for (const r of ranges) {\n for (const shift of [-WEEK, 0, WEEK]) list.push([r.day * DAY + r.start + shift, r.day * DAY + r.end + shift]);\n }\n list.sort((a, b) => a[0] - b[0]);\n const merged: Array<[number, number]> = [];\n for (const span of list) {\n const last = merged[merged.length - 1];\n // Touching spans are one: open 09:00–12:00 and 12:00–14:00 closes at 14:00.\n if (last && span[0] <= last[1]) last[1] = Math.max(last[1], span[1]);\n else merged.push([span[0], span[1]]);\n }\n return merged;\n}\n\n/**\n * Whether a place with these hours is open at `date`, and when that changes — read on\n * `date`'s own clock (pass the place's local time). `null` when the hours say nothing.\n * Hours take any shape `readHours` reads.\n */\nexport function placeStatus(hours: unknown, date: Date): PlaceStatus | null {\n const ranges = readHours(hours);\n if (!ranges.length) return null;\n const t = date.getDay() * DAY + date.getHours() * 60 + date.getMinutes();\n // A minute of the week as a time on `date`'s clock, built from its fields rather than\n // added to it: a daylight-saving change in between would move \"04:00\" to 03:00.\n const at = (minute: number) => new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay() + Math.floor(minute / DAY), 0, minute % DAY);\n const list = spans(ranges);\n const inside = list.find(([s, e]) => s <= t && t < e);\n if (inside) return inside[1] - inside[0] >= WEEK ? { open: true } : { open: true, changesAt: at(inside[1]) };\n const next = list.find(([s]) => s > t);\n return next ? { open: false, changesAt: at(next[0]) } : { open: false };\n}\n\n/** Whether a place with these hours is open at `date`. No hours, no answer: `false`. */\nexport function isOpenAt(hours: unknown, date: Date): boolean {\n return placeStatus(hours, date)?.open ?? false;\n}\n\n/**\n * `date` moved to the place's wall clock, when its UTC offset is known: the place's time,\n * read off the UTC fields of the shifted instant, written into a Date's local fields (which\n * is how `placeStatus` reads a clock). Adding the reader's `getTimezoneOffset()` instead is\n * an hour wrong whenever the reader's own zone changes its clocks in between.\n */\nfunction placeTime(place: Pick<Place, 'utcOffset'>, now: Date): Date {\n if (place.utcOffset === undefined) return now;\n const t = new Date(now.getTime() + place.utcOffset * 60_000);\n return new Date(t.getUTCFullYear(), t.getUTCMonth(), t.getUTCDate(), t.getUTCHours(), t.getUTCMinutes(), t.getUTCSeconds(), t.getUTCMilliseconds());\n}\n\nconst KIND_RULES: Array<[Exclude<PlaceKind, 'place'>, RegExp]> = [\n ['cafe', /\\bcaf[eé]s?\\b|coffee|tea ?room|bakery|boulangerie|p[aâ]tisserie|salon de th[eé]/],\n ['bar', /\\bbars?\\b|\\bpubs?\\b|brewery|\\bwine\\b|cocktail|night ?club/],\n ['restaurant', /restaurant|\\bfood\\b|meal|pizz|sushi|burger|bistro|brasserie|diner|eatery|trattoria|ramen|steak|cr[eê]perie/],\n ['hotel', /h[oô]tel|lodging|hostel|motel|\\binn\\b|resort|guest ?house|bed and breakfast|\\bb ?& ?b\\b/],\n ['museum', /museum|mus[eé]e|galler|monument|landmark|tourist attraction|\\bart\\b/],\n ['park', /\\bparks?\\b|\\bparcs?\\b|garden|jardin|beach|plage|\\bzoo\\b|campground/],\n ['gym', /\\bgyms?\\b|fitness|stadium|swimming|piscine/],\n ['pharmacy', /pharmac|drugstore|chemist/],\n ['shop', /shop|store|boutique|market|\\bmall\\b|grocery|supermarch|magasin|[eé]picerie/],\n];\n\n/** The kind of place, from its category, then its types in order — the first one that says. */\nfunction readKind(candidates: unknown[]): PlaceKind {\n for (const candidate of candidates) {\n const text = str(candidate)?.toLowerCase().replace(/[_-]+/g, ' ');\n if (!text) continue;\n for (const [kind, rule] of KIND_RULES) if (rule.test(text)) return kind;\n }\n return 'place';\n}\n\nconst PRICE_WORDS: Record<string, number> = {\n inexpensive: 1, cheap: 1, moderate: 2, expensive: 3, very_expensive: 4, 'very expensive': 4,\n};\n\nfunction readPrice(value: unknown): { price?: PlacePrice; priceText?: string } {\n const n = num(value);\n if (n !== undefined) return n >= 1 && n <= PRICE_MAX ? { price: { level: Math.round(n) } } : {};\n const s = str(value);\n if (!s) return {};\n const repeated = /^(\\p{Sc})\\1{0,3}$/u.exec(s);\n if (repeated) return { price: { level: s.length / repeated[1]!.length, symbol: repeated[1] } };\n const named = PRICE_WORDS[s.toLowerCase().replace(/^price_level_/, '')];\n if (named) return { price: { level: named } };\n if (/^price_level_/i.test(s)) return {};\n return s.length <= 24 ? { priceText: s } : {};\n}\n\nfunction readCoordinates(r: Loose): Place['coordinates'] {\n const candidates = [r['coordinates'], r['geometry']?.['location'], r['location'], r['position'], r['latlng'], r];\n for (const c of candidates) {\n if (!c || typeof c !== 'object') continue;\n const lat = num(c['lat'] ?? c['latitude']);\n const lng = num(c['lng'] ?? c['lon'] ?? c['long'] ?? c['longitude']);\n if (lat !== undefined && lng !== undefined && Math.abs(lat) <= 90 && Math.abs(lng) <= 180) return { lat, lng };\n }\n return undefined;\n}\n\n/**\n * A link a place's data gives — absolute `http(s)` only. A bare domain (\"trattoria.fr\") is read\n * as `https://` where asked. A path (`/img/a.jpg`) is refused, as the kit's `webUrl` refuses it:\n * it comes from a tool, and a photo's address is fetched on render, with the app's cookies.\n */\nfunction webUrl(value: unknown, guessScheme = false): string | undefined {\n let s = str(value);\n if (!s) return undefined;\n if (s.startsWith('//')) {\n s = `https:${s}`;\n } else if (!/^https?:\\/\\//i.test(s)) {\n // Not a link — Google's photo names (\"places/…/photos/…\") are not addresses a browser\n // can load, and a path on this site is not the tool's to ask for.\n if (!guessScheme || !/^[\\w-]+(\\.[\\w-]+)+(\\/|$)/.test(s)) return undefined;\n s = `https://${s}`;\n }\n const url = safeUrl(s);\n return url && /^https?:/i.test(url) ? url : undefined;\n}\n\nfunction textOf(value: unknown): string | undefined {\n if (value && typeof value === 'object') {\n const o = value as Record<string, unknown>;\n return str(o['text'] ?? o['title'] ?? o['name'] ?? o['url']);\n }\n return str(value);\n}\n\n/** A link given as a string or as `{ url | src | href | uri }`. */\nfunction linkOf(value: unknown): string | undefined {\n if (value && typeof value === 'object') {\n const o = value as Record<string, unknown>;\n return str(o['url'] ?? o['src'] ?? o['href'] ?? o['uri']);\n }\n return str(value);\n}\n\nfunction firstOf(value: unknown): unknown {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction readPlace(raw: unknown): Place | null {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;\n const r = raw as Loose;\n const name = textOf(r['name'] ?? r['displayName'] ?? r['title']);\n if (!name) return null;\n const category = textOf(r['category'] ?? r['primaryTypeDisplayName'] ?? firstOf(r['categories']));\n const types = Array.isArray(r['types']) ? r['types'] : [];\n let ratingValue = num(r['rating'] ?? r['stars']);\n if (ratingValue !== undefined && ratingValue > 5 && ratingValue <= 10) ratingValue /= 2;\n if (ratingValue !== undefined && (ratingValue < 0 || ratingValue > 5)) ratingValue = undefined;\n const reviewCount = num(r['reviewCount'] ?? r['review_count'] ?? r['user_ratings_total'] ?? r['userRatingCount'] ?? r['ratingCount'] ?? r['rating_count'] ?? r['reviews']);\n const rawDistance = r['distance'] ?? r['distanceMeters'] ?? r['distance_meters'] ?? r['distance_m'];\n const distance = num(rawDistance);\n // Google's current hours first: the next seven days, holidays included, where the regular\n // week would call a closed bank holiday open. The first source with a week gives the week;\n // the first with an answer gives \"open now\" (Yelp's sits on its first `hours` entry).\n const hourSources: Loose[] = [r['hours'], r['currentOpeningHours'], r['current_opening_hours'], r['regularOpeningHours'], r['opening_hours'], r['openingHours']]\n .filter((h) => h && typeof h === 'object');\n let hours: PlaceHoursRange[] = [];\n for (const source of hourSources) {\n hours = readHours(source);\n if (hours.length) break;\n }\n const openSource = r['openNow'] ?? r['open_now'] ?? r['isOpen'] ?? r['is_open'] ?? r['is_open_now']\n ?? hourSources.map((h) => (Array.isArray(h) ? h[0] : h) as Loose | undefined)\n .map((h) => h?.['openNow'] ?? h?.['open_now'] ?? h?.['is_open_now'])\n .find((v) => typeof v === 'boolean');\n const tags = (Array.isArray(r['tags']) ? r['tags'] : Array.isArray(r['features']) ? r['features'] : Array.isArray(r['amenities']) ? r['amenities'] : [])\n .map(textOf)\n .filter((t: string | undefined): t is string => !!t && t.length <= 32)\n .slice(0, MAX_TAGS);\n const utcOffset = num(r['utcOffset'] ?? r['utc_offset_minutes'] ?? r['utcOffsetMinutes'] ?? r['utc_offset']);\n return {\n name,\n category,\n kind: readKind([category, r['primaryType'], ...types]),\n image: webUrl(linkOf(r['image'] ?? r['photo'] ?? r['imageUrl'] ?? r['image_url'] ?? r['photoUrl'] ?? r['thumbnail'] ?? r['picture'] ?? firstOf(r['photos']))),\n rating: ratingValue,\n reviewCount: reviewCount !== undefined && reviewCount >= 0 ? Math.round(reviewCount) : undefined,\n ...readPrice(r['priceLevel'] ?? r['price_level'] ?? r['price']),\n address: str(r['address'] ?? r['formatted_address'] ?? r['formattedAddress'] ?? r['shortFormattedAddress'] ?? r['vicinity'] ?? (typeof r['location'] === 'string' ? r['location'] : undefined))\n // Yelp's address is lines to stack: on one line, they are joined.\n ?? (Array.isArray(r['location']?.['display_address']) ? str(r['location']['display_address'].map(str).filter(Boolean).join(', ')) : undefined),\n distance: distance !== undefined && distance >= 0 ? distance : undefined,\n distanceText: distance === undefined && typeof rawDistance === 'string' ? str(rawDistance) : undefined,\n phone: str(r['phone'] ?? r['phoneNumber'] ?? r['phone_number'] ?? r['formatted_phone_number'] ?? r['nationalPhoneNumber'] ?? r['international_phone_number'] ?? r['internationalPhoneNumber'] ?? r['tel']),\n website: webUrl(r['website'] ?? r['websiteUri'] ?? r['websiteUrl'] ?? r['site'], true),\n url: webUrl(r['url'] ?? r['googleMapsUri'] ?? r['mapsUrl'] ?? r['maps_url'] ?? r['link']),\n coordinates: readCoordinates(r),\n placeId: str(r['placeId'] ?? r['place_id'] ?? r['googlePlaceId']),\n openNow: typeof openSource === 'boolean' ? openSource : undefined,\n hours,\n utcOffset: utcOffset !== undefined && Math.abs(utcOffset) <= 14 * 60 ? utcOffset : undefined,\n tags,\n };\n}\n\n/**\n * The card's data from what `map` returns: one place, an array of places, or a collection\n * (`{ title?, places | results | candidates }`). At most ten places; `null` when not one\n * has a name.\n */\nexport function readPlaces(raw: unknown): PlaceData | null {\n if (!raw || typeof raw !== 'object') return null;\n let title: string | undefined;\n let list: unknown[];\n if (Array.isArray(raw)) {\n list = raw;\n } else {\n const r = raw as Record<string, unknown>;\n const nested = r['places'] ?? r['results'] ?? r['candidates'];\n if (Array.isArray(nested)) {\n list = nested;\n title = str(r['title']);\n } else {\n list = [raw];\n }\n }\n const places = list.map(readPlace).filter((p): p is Place => p !== null).slice(0, MAX_PLACES);\n return places.length ? { ...(title ? { title } : {}), places } : null;\n}\n\n/**\n * Google Maps directions to the place: to its coordinates when known, else to its name and\n * address, landing on the place itself when its Google id is known. `null` without either.\n */\nexport function directionsUrl(place: Pick<Place, 'name' | 'address' | 'coordinates' | 'placeId'>): string | null {\n const destination = place.coordinates\n ? `${place.coordinates.lat},${place.coordinates.lng}`\n : place.address ? `${place.name}, ${place.address}` : null;\n if (!destination) return null;\n const id = place.placeId ? `&destination_place_id=${encodeURIComponent(place.placeId)}` : ''; // safe-attr: a URL query parameter, encodeURIComponent-ed, not markup\n return `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(destination)}${id}`; // safe-attr: a URL query parameter, encodeURIComponent-ed, not markup\n}\n\n/**\n * A `tel:` link from a written number — its digits, and the `+` before the first of them\n * (\"Tel: +33 …\" keeps it). An extension (\"ext. 12\", \"x12\", \"#3\") is not part of the number:\n * dialled as digits, it would make a different one. `null` for no number.\n */\nexport function phoneUrl(phone: string | undefined): string | null {\n if (!phone) return null;\n const number = phone.replace(/\\s*(?:\\b(?:ext(?:ension)?\\.?|x)\\s*\\d|#).*$/i, '');\n const digits = number.replace(/\\D/g, '');\n const plus = /^[^\\d]*\\+/.test(number) ? '+' : '';\n return /\\d{3,}/.test(digits) ? safeUrl(`tel:${plus}${digits}`) : null;\n}\n\n// ── Drawing ──────────────────────────────────────────────────────────────────\n\ninterface Settings {\n builtIns: boolean;\n currencySymbol: string;\n now: () => Date;\n}\n\ntype Tone = 'open' | 'soon' | 'closed';\n\n/** What the status line says, worked out once at render, so a language switch re-words it without re-reading the clock. */\ninterface StatusView {\n tone: Tone;\n state: keyof typeof P;\n next?: (config: AparteConfig) => string;\n}\n\n/**\n * A time of day as the language writes it on a shop door: \"10 PM\" where the clock has\n * twelve hours, \"22:00\" where it has twenty-four — `formatHour` would write a bare \"22\",\n * which reads as a number, not a time.\n */\nfunction clock(config: AparteConfig, date: Date): string {\n const tag = intlTag(config);\n const twelve = /h1[12]/.test(new Intl.DateTimeFormat(tag, { hour: 'numeric' }).resolvedOptions().hourCycle ?? '');\n return twelve\n ? new Intl.DateTimeFormat(tag, { hour: 'numeric', minute: date.getMinutes() ? '2-digit' : undefined }).format(date)\n : new Intl.DateTimeFormat(tag, { hour: '2-digit', minute: '2-digit' }).format(date);\n}\nconst weekday = (config: AparteConfig, date: Date) => new Intl.DateTimeFormat(intlTag(config), { weekday: 'long' }).format(date);\nconst startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\nconst daysBetween = (from: Date, to: Date) => Math.round((startOfDay(to) - startOfDay(from)) / 86_400_000);\n\nfunction statusView(place: Place, now: Date): StatusView | null {\n const local = placeTime(place, now);\n const status = place.hours.length ? placeStatus(place.hours, local) : null;\n if (!status) {\n if (place.openNow === undefined) return null;\n return { tone: place.openNow ? 'open' : 'closed', state: place.openNow ? 'cardsPlaceOpen' : 'cardsPlaceClosed' };\n }\n const at = status.changesAt;\n if (status.open) {\n if (!at) return { tone: 'open', state: 'cardsPlaceAlwaysOpen' };\n const minutes = (at.getTime() - local.getTime()) / 60_000;\n if (minutes < SOON) return { tone: 'soon', state: 'cardsPlaceClosesSoon', next: (c) => clock(c, at) };\n return {\n tone: 'open',\n state: 'cardsPlaceOpen',\n // Past midnight is still \"closes at 02:00\"; only a close more than a day away names its day.\n next: minutes <= DAY\n ? (c) => word(c, 'cardsPlaceClosesAt', P.cardsPlaceClosesAt, { t: clock(c, at) })\n : (c) => word(c, 'cardsPlaceClosesOn', P.cardsPlaceClosesOn, { day: weekday(c, at), t: clock(c, at) }),\n };\n }\n if (!at) return { tone: 'closed', state: 'cardsPlaceClosed' };\n const days = daysBetween(local, at);\n return {\n tone: 'closed',\n state: 'cardsPlaceClosed',\n next: days === 0\n ? (c) => word(c, 'cardsPlaceOpensAt', P.cardsPlaceOpensAt, { t: clock(c, at) })\n : days === 1\n ? (c) => word(c, 'cardsPlaceOpensTomorrow', P.cardsPlaceOpensTomorrow, { t: clock(c, at) })\n : (c) => word(c, 'cardsPlaceOpensOn', P.cardsPlaceOpensOn, { day: weekday(c, at), t: clock(c, at) }),\n };\n}\n\nfunction distanceText(config: AparteConfig, metres: number): string {\n if (metres < 1000) return formatUnit(config, metres < 100 ? Math.round(metres) : Math.round(metres / 10) * 10, 'meter');\n const km = metres / 1000;\n return formatUnit(config, km, 'kilometer', km < 10 ? 1 : 0);\n}\n\n/** The middle dot between two facts on a line — drawn, not read. */\nconst dot = () => el('span', { class: 'aparte-place__dot', attrs: { 'aria-hidden': 'true' }, text: '·' });\n\nfunction joined(className: string, parts: Array<Node | null>, tag: 'div' | 'p' = 'div'): HTMLElement | null {\n const present = parts.filter((p): p is Node => p !== null);\n if (!present.length) return null;\n const line = el(tag, { class: className });\n present.forEach((part, i) => {\n if (i) line.append(dot());\n line.append(part);\n });\n return line;\n}\n\nfunction nameOf(place: Place, className = 'aparte-place__name'): HTMLElement {\n const name = el('div', { class: className });\n if (place.url) {\n name.append(el('a', { class: 'aparte-place__link', attrs: { href: place.url, target: '_blank', rel: 'noopener noreferrer' }, text: place.name }));\n } else {\n name.textContent = place.name;\n }\n return name;\n}\n\n/** The category as the tool wrote it, else the kind's name in the chat's language, else nothing. */\nfunction categoryOf(ctx: CardContext, place: Place): HTMLElement | null {\n if (place.category) return el('span', { class: 'aparte-place__category', text: place.category });\n if (place.kind === 'place') return null;\n const node = el('span', { class: 'aparte-place__category' });\n ctx.word(node, `cardsPlace_${place.kind}`, KIND_WORDS[place.kind]);\n return node;\n}\n\nfunction priceOf(ctx: CardContext, place: Place, settings: Settings): HTMLElement | null {\n if (place.priceText) return el('span', { class: 'aparte-place__price', text: place.priceText });\n if (!place.price) return null;\n const { level } = place.price;\n const sign = place.price.symbol ?? settings.currencySymbol;\n // The tier in full ink, the rest of the scale faint: \"€€\" reads as two of four.\n const node = el('span', { class: 'aparte-place__price', attrs: { role: 'img' } },\n el('span', { class: 'aparte-place__price-on', attrs: { 'aria-hidden': 'true' }, text: sign.repeat(level) }),\n level < PRICE_MAX ? el('span', { class: 'aparte-place__price-off', attrs: { 'aria-hidden': 'true' }, text: sign.repeat(PRICE_MAX - level) }) : null);\n ctx.bind(node, () => word(ctx.config, 'cardsPlacePrice', P.cardsPlacePrice, {\n level: formatNumber(ctx.config, level), max: formatNumber(ctx.config, PRICE_MAX),\n }), 'aria-label');\n return node;\n}\n\nfunction scoreOf(ctx: CardContext, place: Place, settings: Settings): HTMLElement | null {\n return joined('aparte-place__score', [rating(ctx, place.rating, { count: place.reviewCount }), priceOf(ctx, place, settings)]);\n}\n\nfunction distanceOf(ctx: CardContext, place: Place): HTMLElement | null {\n if (place.distance !== undefined) {\n const node = el('span', { class: 'aparte-place__distance' });\n ctx.bind(node, () => distanceText(ctx.config, place.distance!));\n return node;\n }\n return place.distanceText ? el('span', { class: 'aparte-place__distance', text: place.distanceText }) : null;\n}\n\n/** \"● Open · Closes at 22:00\" — the state is a word, so it does not rest on its colour. */\nfunction statusOf(ctx: CardContext, place: Place, now: Date): HTMLElement | null {\n const view = statusView(place, now);\n if (!view) return null;\n const line = el('p', { class: 'aparte-place__status', attrs: { 'data-status': view.tone } });\n const state = el('span', { class: 'aparte-place__state' });\n ctx.word(state, view.state, P[view.state]);\n line.append(el('span', { class: 'aparte-place__status-dot', attrs: { 'aria-hidden': 'true' } }), state);\n if (view.next) {\n const next = el('span', { class: 'aparte-place__next' });\n ctx.bind(next, () => view.next!(ctx.config));\n line.append(dot(), next);\n }\n return line;\n}\n\nfunction addressOf(ctx: CardContext, place: Place): HTMLElement | null {\n const distance = distanceOf(ctx, place);\n const address = place.address ? el('span', { class: 'aparte-place__address-text', text: place.address }) : null;\n const line = joined('aparte-place__address', [distance, address], 'p');\n if (line) line.prepend(glyph(PIN, 'aparte-rich-card__glyph aparte-place__line-glyph'));\n return line;\n}\n\n/**\n * The photo in a fixed box, over a placeholder that stays behind it: a soft map with the\n * kind's marker for a wide box, the kind's glyph for a thumbnail. A photo that fails to load\n * is removed, and the placeholder is what shows.\n */\nfunction mediaOf(ctx: CardContext, place: Place, size: 'wide' | 'thumb'): HTMLElement {\n const box = el('div', { class: `aparte-place__media aparte-place__media--${size}` });\n const mark = glyph(kindGlyph(place.kind), 'aparte-rich-card__glyph aparte-place__marker-glyph');\n box.append(el('span', { class: 'aparte-place__placeholder', attrs: { 'aria-hidden': 'true' } },\n el('span', { class: 'aparte-place__marker' }, mark)));\n if (place.image) {\n // No referrer: the photo is on someone else's server, which need not learn the chat's address.\n const img = el('img', { class: 'aparte-place__img', attrs: { src: place.image, loading: 'lazy', decoding: 'async', referrerpolicy: 'no-referrer' } });\n ctx.bind(img, () => word(ctx.config, 'cardsPlacePhoto', P.cardsPlacePhoto, { name: place.name }), 'alt');\n img.addEventListener('error', () => {\n img.remove();\n box.setAttribute('data-empty', '');\n }, { once: true });\n box.append(img);\n } else {\n box.setAttribute('data-empty', '');\n }\n return box;\n}\n\ntype ActionKind = 'directions' | 'call' | 'website';\nconst ACTION_WORD: Record<ActionKind, 'cardsPlaceDirections' | 'cardsPlaceCall' | 'cardsPlaceWebsite'> = {\n directions: 'cardsPlaceDirections', call: 'cardsPlaceCall', website: 'cardsPlaceWebsite',\n};\nconst ACTION_GLYPH: Record<ActionKind, string> = { directions: DIRECTIONS, call: PHONE, website: GLOBE };\n\n/**\n * The buttons a place's own data can honour — none it cannot. Labelled on a card on its own;\n * round and icon-only on a tile in a row, where three words do not fit (the word is then the\n * button's name and its tooltip).\n */\nfunction actionsOf(ctx: CardContext, place: Place, settings: Settings, iconOnly: boolean): HTMLElement | null {\n if (!settings.builtIns) return null;\n const urls: Array<[ActionKind, string | null | undefined]> = [\n ['directions', directionsUrl(place)],\n ['call', phoneUrl(place.phone)],\n ['website', place.website ?? place.url],\n ];\n const buttons: HTMLButtonElement[] = [];\n for (const [kind, url] of urls) {\n if (!url) continue;\n const label = () => word(ctx.config, ACTION_WORD[kind], P[ACTION_WORD[kind]]);\n const primary = kind === 'directions' && !iconOnly;\n const button = ctx.action({ id: kind, label: label(), url, primary }, place,\n `aparte-place__action${iconOnly ? ' aparte-btn--icon aparte-btn--circle' : ''}`)!;\n // The kit writes the label as plain text; the place's buttons carry a glyph, and a\n // word that follows the language.\n button.textContent = '';\n button.setAttribute('data-action', kind);\n button.append(glyph(ACTION_GLYPH[kind], 'aparte-rich-card__glyph aparte-btn__icon'));\n if (iconOnly) {\n ctx.bind(button, label, 'aria-label');\n ctx.bind(button, label, 'title');\n } else {\n const text = el('span');\n ctx.bind(text, label);\n button.append(text);\n }\n buttons.push(button);\n }\n return buttons.length ? el('div', { class: 'aparte-place__actions' }, ...buttons) : null;\n}\n\n/** A place as a tile: photo, name, rating, open status, address, buttons. */\nfunction tileOf(ctx: CardContext, place: Place, settings: Settings, now: Date, inRow: boolean): HTMLElement {\n const media = mediaOf(ctx, place, 'wide');\n const category = categoryOf(ctx, place);\n if (category) {\n media.append(el('span', { class: 'aparte-place__badge' },\n glyph(kindGlyph(place.kind), 'aparte-rich-card__glyph aparte-place__badge-glyph'), category));\n }\n const body = el('div', { class: 'aparte-place__body' }, nameOf(place), scoreOf(ctx, place, settings), statusOf(ctx, place, now), addressOf(ctx, place));\n const actions = actionsOf(ctx, place, settings, inRow);\n if (actions) body.append(actions);\n return el('article', { class: `aparte-place${inRow ? ' aparte-place--tile' : ''}`, attrs: { 'data-kind': place.kind } }, media, body);\n}\n\n/** A place as one row: thumbnail, name and distance, rating, open status. */\nfunction rowOf(ctx: CardContext, place: Place, settings: Settings, now: Date, tag: 'div' | 'li'): HTMLElement {\n const head = el('div', { class: 'aparte-place__row-head' }, nameOf(place), distanceOf(ctx, place));\n const facts = joined('aparte-place__score', [\n rating(ctx, place.rating, { count: place.reviewCount }),\n priceOf(ctx, place, settings),\n categoryOf(ctx, place),\n ]);\n const text = el('div', { class: 'aparte-place__text' }, head, facts, statusOf(ctx, place, now));\n return el(tag, { class: 'aparte-place aparte-place__row', attrs: { 'data-kind': place.kind } }, mediaOf(ctx, place, 'thumb'), text);\n}\n\nfunction rangeText(config: AparteConfig, range: PlaceHoursRange): string {\n if (range.start === 0 && range.end >= DAY) return word(config, 'cardsPlaceAlwaysOpen', P.cardsPlaceAlwaysOpen);\n const at = (minute: number) => clock(config, new Date(2000, 0, 1, Math.floor(minute / 60) % 24, minute % 60));\n return `${at(range.start)}–${at(range.end)}`;\n}\n\n/** The week, from today, today marked: a table, so each day is read with its hours. */\nfunction hoursOf(ctx: CardContext, place: Place, now: Date): HTMLElement | null {\n if (!place.hours.length) return null;\n const local = placeTime(place, now);\n const caption = el('caption', { class: 'aparte-place__hours-title' });\n const title = el('span');\n ctx.word(title, 'cardsPlaceHours', P.cardsPlaceHours);\n caption.append(glyph(CLOCK, 'aparte-rich-card__glyph aparte-place__line-glyph'), title);\n const body = el('tbody');\n for (let i = 0; i < 7; i++) {\n const date = new Date(local.getFullYear(), local.getMonth(), local.getDate() + i, 12);\n const ranges = place.hours.filter((r) => r.day === date.getDay());\n const day = el('th', { attrs: { scope: 'row' } });\n ctx.bind(day, () => weekday(ctx.config, date));\n const hours = el('td');\n ctx.bind(hours, () => (ranges.length\n ? ranges.map((r) => rangeText(ctx.config, r)).join(', ')\n : word(ctx.config, 'cardsPlaceClosed', P.cardsPlaceClosed)));\n body.append(el('tr', { attrs: { 'aria-current': i === 0 ? 'date' : undefined, 'data-closed': !ranges.length } }, day, hours));\n }\n return el('table', { class: 'aparte-place__hours' }, caption, body);\n}\n\n/** The place's ways in, one a line: where it is, its number, its site. */\nfunction infoOf(ctx: CardContext, place: Place): HTMLElement | null {\n const items: HTMLElement[] = [];\n const address = addressOf(ctx, place);\n if (address) items.push(el('li', {}, ...address.childNodes));\n const tel = phoneUrl(place.phone);\n if (place.phone) {\n items.push(el('li', {}, glyph(PHONE, 'aparte-rich-card__glyph aparte-place__line-glyph'),\n tel ? el('a', { class: 'aparte-place__link', attrs: { href: tel }, text: place.phone }) : place.phone));\n }\n if (place.website) {\n const host = new URL(place.website).hostname.replace(/^www\\./, '');\n items.push(el('li', {}, glyph(GLOBE, 'aparte-rich-card__glyph aparte-place__line-glyph'),\n el('a', { class: 'aparte-place__link', attrs: { href: place.website, target: '_blank', rel: 'noopener noreferrer' }, text: host })));\n }\n return items.length ? el('ul', { class: 'aparte-place__info' }, ...items) : null;\n}\n\nfunction tagsOf(place: Place): HTMLElement | null {\n if (!place.tags.length) return null;\n return el('ul', { class: 'aparte-place__tags' }, ...place.tags.map((t) =>\n el('li', { class: 'aparte-tag aparte-tag--sm aparte-place__tag' }, el('span', { class: 'aparte-tag__label', text: t }))));\n}\n\nfunction renderDetail(ctx: CardContext, place: Place, settings: Settings, now: Date): Node[] {\n const media = mediaOf(ctx, place, 'wide');\n const category = categoryOf(ctx, place);\n if (category) {\n media.append(el('span', { class: 'aparte-place__badge' },\n glyph(kindGlyph(place.kind), 'aparte-rich-card__glyph aparte-place__badge-glyph'), category));\n }\n const head = el('div', { class: 'aparte-place__head' }, nameOf(place), scoreOf(ctx, place, settings), statusOf(ctx, place, now));\n const body = el('div', { class: 'aparte-place__body' }, head);\n for (const part of [actionsOf(ctx, place, settings, false), infoOf(ctx, place), hoursOf(ctx, place, now), tagsOf(place)]) {\n if (part) body.append(part);\n }\n return [el('article', { class: 'aparte-place aparte-place--detail', attrs: { 'data-kind': place.kind } }, media, body)];\n}\n\nfunction countLabel(ctx: CardContext, data: Partial<PlaceData>): string {\n return data.title ?? word(ctx.config, 'cardsPlaceCount', P.cardsPlaceCount, { n: formatNumber(ctx.config, data.places?.length ?? 0) });\n}\n\nfunction headingOf(ctx: CardContext, data: PlaceData): HTMLElement {\n const text = el('span', { class: 'aparte-place__heading-text' });\n ctx.bind(text, () => countLabel(ctx, data));\n return el('div', { class: 'aparte-place__heading' }, glyph(PIN, 'aparte-rich-card__glyph aparte-place__line-glyph'), text);\n}\n\nfunction render(data: PlaceData, ctx: CardContext<PlaceVariant>, settings: Settings): Node[] {\n const now = settings.now();\n const [first] = data.places as [Place];\n const many = data.places.length > 1;\n if (ctx.variant === 'compact') {\n if (!many) return [rowOf(ctx, first, settings, now, 'div')];\n const list = el('ul', { class: 'aparte-place__list' }, ...data.places.map((p) => rowOf(ctx, p, settings, now, 'li')));\n ctx.bind(list, () => countLabel(ctx, data), 'aria-label');\n return [headingOf(ctx, data), list];\n }\n if (many) {\n // `detail` is one place's page: several of them are tiles in a row, like `card`.\n const slides = data.places.map((p) => tileOf(ctx, p, settings, now, true));\n return [el('div', { class: 'aparte-place__collection' }, headingOf(ctx, data), carousel(ctx, slides, { label: () => countLabel(ctx, data) }))];\n }\n return ctx.variant === 'detail' ? renderDetail(ctx, first, settings, now) : [tileOf(ctx, first, settings, now, false)];\n}\n\nfunction skeleton(partial: Partial<PlaceData> | null, ctx: CardContext<PlaceVariant>): Node[] {\n const block = (cls: string, kind: 'text' | 'rect' = 'rect') =>\n el('span', { class: `aparte-skeleton aparte-skeleton--${kind} ${cls}`, attrs: { 'aria-hidden': 'true' } });\n const known = partial?.places?.[0]?.name ?? partial?.title;\n const name = known ? el('div', { class: 'aparte-place__name', text: known }) : block('aparte-place__sk-name', 'text');\n if (ctx.variant === 'compact') {\n return [el('div', { class: 'aparte-place aparte-place__row' }, block('aparte-place__media--thumb aparte-place__sk-thumb'),\n el('div', { class: 'aparte-place__text' }, name, block('aparte-place__sk-line', 'text')))];\n }\n const body = el('div', { class: 'aparte-place__body' }, name,\n block('aparte-place__sk-line', 'text'),\n block('aparte-place__sk-line aparte-place__sk-line--short', 'text'),\n el('div', { class: 'aparte-place__sk-actions' }, block('aparte-place__sk-btn'), block('aparte-place__sk-btn')));\n if (ctx.variant === 'detail') body.append(el('div', { class: 'aparte-place__sk-hours' }, ...Array.from({ length: 4 }, () => block('aparte-place__sk-line', 'text'))));\n return [el('article', { class: 'aparte-place' }, block('aparte-place__media--wide aparte-place__sk-media'), body)];\n}\n\nfunction label(data: Partial<PlaceData> | null, ctx: CardContext): string {\n const places = data?.places ?? [];\n if (places.length === 1) return places[0]!.name;\n if (places.length > 1 || data?.title) return countLabel(ctx, data!);\n return word(ctx.config, 'cardsPlaceTitle', P.cardsPlaceTitle);\n}\n\n/** One sentence a place: \"Name — 4.6/5 (1,284), 12 rue de la Paix\". */\nfunction fallback(data: PlaceData, ctx: CardContext): string {\n const lines = data.places.map((p) => {\n const score = p.rating !== undefined\n ? `${formatNumber(ctx.config, p.rating, { maximumFractionDigits: 1 })}/5${p.reviewCount !== undefined ? ` (${formatNumber(ctx.config, p.reviewCount)})` : ''}`\n : undefined;\n const rest = [score, p.address].filter(Boolean).join(', ');\n return rest ? `${p.name} — ${rest}` : p.name;\n });\n return data.title ? `${data.title}:\\n${lines.join('\\n')}` : lines.join('\\n');\n}\n\nfunction partial(input: Record<string, unknown>): Partial<PlaceData> | null {\n const name = str(input['name'] ?? input['place'] ?? input['placeName']);\n if (name) return { places: [readPlace({ name })!] };\n const query = str(input['query'] ?? input['q'] ?? input['keyword'] ?? input['search'] ?? input['textQuery']);\n return query ? { title: query } : null;\n}\n\nfunction createPlaceCard(settings: Settings) {\n return defineCard<PlaceData, PlaceVariant>({\n name: 'place',\n variants: ['card', 'compact', 'detail'],\n styles: placeStyles,\n icon: PIN,\n normalize: readPlaces,\n render: (data, ctx) => render(data, ctx, settings),\n skeleton,\n label,\n fallback,\n partial,\n });\n}\n\n/**\n * The place card with its built-in buttons and the device's clock — for `placeCard.segment(data)`.\n * Plug it in with `setupPlaceCard`, which also hears the card's own options.\n */\nexport const placeCard = createPlaceCard({ builtIns: true, currencySymbol: '$', now: () => new Date() });\n\n/**\n * Draw a tool's places as this card — returns the function that stops it. Each place keeps\n * its Directions / Call / Website buttons beside the app's own `actions` unless `builtIns`\n * is `false`.\n */\nexport function setupPlaceCard(options: PlaceCardOptions = {}): () => void {\n const { currencySymbol, now, builtIns, ...rest } = options;\n const card = createPlaceCard({\n builtIns: builtIns !== false,\n currencySymbol: str(currencySymbol) ?? '$',\n now: now ?? (() => new Date()),\n });\n return card.setup(rest);\n}\n"],"names":["h","m","out","day","start","end","label","partial"],"mappings":";;;AAYA,MAAM,MAAM,CAAC,SACT,oKAAoK,IAAI;AAErK,MAAM,MAAM,IAAI,6GAA6G;AAC7H,MAAM,QAAQ,IAAI,6HAA6H;AAC/I,MAAM,QAAQ,IAAI,mJAAmJ;AACrK,MAAM,aAAa,IAAI,sHAAsH;AAC7I,MAAM,QAAQ,IAAI,6DAA6D;AAEtF,MAAM,cAAyC;AAAA,EAC3C,YAAY,IAAI,iHAAiH;AAAA,EACjI,MAAM,IAAI,kLAAkL;AAAA,EAC5L,KAAK,IAAI,kEAAkE;AAAA,EAC3E,OAAO,IAAI,oGAAoG;AAAA,EAC/G,MAAM,IAAI,uEAAuE;AAAA,EACjF,QAAQ,IAAI,iGAAiG;AAAA,EAC7G,MAAM,IAAI,uDAAuD;AAAA,EACjE,KAAK,IAAI,gEAAgE;AAAA,EACzE,UAAU,IAAI,iFAAiF;AAAA,EAC/F,OAAO;AACX;AAGO,SAAS,UAAU,MAAyB;AAC/C,SAAO,YAAY,IAAI;AAC3B;ACrCA,MAAA,cAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plan card's glyphs: one per step status, the timeline's "current" node, a clock for
|
|
3
|
+
* the elapsed time, and the card's own for its one-line states.
|
|
4
|
+
*
|
|
5
|
+
* Drawn on a 24 × 24 grid in `currentColor`, so the sheet colours each status through
|
|
6
|
+
* `color` and a theme follows. The check and the cross inside a disc are drawn in the
|
|
7
|
+
* card's surface (`.aparte-plan__mark`), so they read in light and dark alike. Constants
|
|
8
|
+
* of this package — the only markup the card parses.
|
|
9
|
+
*/
|
|
10
|
+
/** The glyph each status wears in a list. */
|
|
11
|
+
export declare const STATUS_GLYPHS: {
|
|
12
|
+
readonly pending: string;
|
|
13
|
+
readonly 'in-progress': string;
|
|
14
|
+
readonly done: string;
|
|
15
|
+
readonly failed: string;
|
|
16
|
+
readonly skipped: string;
|
|
17
|
+
readonly blocked: string;
|
|
18
|
+
};
|
|
19
|
+
/** The timeline's node for the step under way: a ring round a dot, which the sheet makes pulse. */
|
|
20
|
+
export declare const NODE_CURRENT: string;
|
|
21
|
+
/** A clock, beside the elapsed time. */
|
|
22
|
+
export declare const CLOCK: string;
|
|
23
|
+
/** A clipboard with two ticked lines: the card's own glyph, for its one-line states. */
|
|
24
|
+
export declare const PLAN: string;
|
|
25
|
+
//# sourceMappingURL=icons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/plan/icons.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuBH,6CAA6C;AAC7C,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC;AAEX,mGAAmG;AACnG,eAAO,MAAM,YAAY,QAA0G,CAAC;AAEpI,wCAAwC;AACxC,eAAO,MAAM,KAAK,QAAyE,CAAC;AAE5F,wFAAwF;AACxF,eAAO,MAAM,IAAI,QAA0P,CAAC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aparte/plugin-cards/plan — an agent's plan, its task list, or its progress through steps.
|
|
3
|
+
*
|
|
4
|
+
* import { setupPlanCard } from '@aparte/plugin-cards/plan';
|
|
5
|
+
*
|
|
6
|
+
* setupPlanCard({ tool: 'update_plan' });
|
|
7
|
+
*
|
|
8
|
+
* // A tool whose INPUT is the list and whose result is only "ok" — Claude Code's
|
|
9
|
+
* // `TodoWrite`, say — reads its input instead:
|
|
10
|
+
* setupPlanCard({ tool: 'TodoWrite', map: (_result, input) => input });
|
|
11
|
+
*
|
|
12
|
+
* Three variants of one card: `checklist` (a header with "3 of 7 done" and a thin bar,
|
|
13
|
+
* then one row per step with its status glyph, its detail and, once it finished, its
|
|
14
|
+
* duration), `timeline` (a rail with a node per step coloured by its status, the start
|
|
15
|
+
* time and duration beside each, the current node pulsing) and `compact` (one line —
|
|
16
|
+
* "Step 3 of 7: Running the tests", a ring and the percentage — for a running plan in a
|
|
17
|
+
* small space).
|
|
18
|
+
*
|
|
19
|
+
* This is the card an agent updates while it works: the same call re-sent with new
|
|
20
|
+
* statuses, which the kit draws into the SAME root. So a step changing STATUS changes no
|
|
21
|
+
* row's height: the title holds the room of its bold form and, for a todo with an active
|
|
22
|
+
* form (Claude Code's `activeForm`), of both wordings; a timed plan keeps every row's
|
|
23
|
+
* duration slot, filled or not, as wide as the language's widest duration; and the
|
|
24
|
+
* timeline keeps every node's time line.
|
|
25
|
+
*
|
|
26
|
+
* What the card cannot hold for an update it has not seen: a detail the update brings (a
|
|
27
|
+
* line under the title appears), a title the tool rewrites, and the first time a plan
|
|
28
|
+
* carries — every row gains its time slot then, unless the plan said `timed: true` from its
|
|
29
|
+
* first draw. LangGraph's `past_steps` results are not drawn at all: every step gains one
|
|
30
|
+
* on completing, so every step would grow; a `map` that wants them gives them as `detail`.
|
|
31
|
+
*
|
|
32
|
+
* Your tool keeps its own fields: `readPlan` reads `{ title, goal, steps }`, a bare list of
|
|
33
|
+
* steps, a list of strings (each a step to do), a Markdown checklist (`- [x] Write the
|
|
34
|
+
* tests`), and the shapes agents already emit — Claude Code's and OpenAI's todo lists
|
|
35
|
+
* (`todos[]` of `content`/`activeForm`/`status`), Codex's `plan[]` of `step`/`status`,
|
|
36
|
+
* LangGraph's plan-and-execute state (`plan: string[]` and `past_steps` of
|
|
37
|
+
* `[step, result]`), and `tasks[]` of `name`/`state`/`done`. `map` covers the rest.
|
|
38
|
+
*/
|
|
39
|
+
import type { AparteConfig } from '@aparte/core';
|
|
40
|
+
import { type CardSetupOptions } from '../kit/define.js';
|
|
41
|
+
export type PlanVariant = 'checklist' | 'timeline' | 'compact';
|
|
42
|
+
/** Where a step stands. */
|
|
43
|
+
export type PlanStatus = 'pending' | 'in-progress' | 'done' | 'failed' | 'skipped' | 'blocked';
|
|
44
|
+
type When = string | number | Date;
|
|
45
|
+
/**
|
|
46
|
+
* One step as `map` returns it. Only `title` is needed; a step without `status` is
|
|
47
|
+
* `pending` (or, when it has sub-steps, where they stand).
|
|
48
|
+
*/
|
|
49
|
+
export interface PlanStepInput {
|
|
50
|
+
title: string;
|
|
51
|
+
/** The wording while it runs ("Running the tests"), Claude Code's `activeForm`: shown while the step is in progress. */
|
|
52
|
+
activeForm?: string;
|
|
53
|
+
/** `pending`, `in-progress`, `done`, `failed`, `skipped`, `blocked` — or the usual words for them (`todo`, `running`, `completed`, `error`, `cancelled`…). */
|
|
54
|
+
status?: PlanStatus | string;
|
|
55
|
+
/** One or two lines under the title: what it did, why it failed. */
|
|
56
|
+
detail?: string;
|
|
57
|
+
startedAt?: When;
|
|
58
|
+
finishedAt?: When;
|
|
59
|
+
/** In seconds; worked out from the two dates when it is absent. */
|
|
60
|
+
duration?: number;
|
|
61
|
+
/** One level of sub-steps. */
|
|
62
|
+
substeps?: Array<PlanStepInput | string>;
|
|
63
|
+
id?: string;
|
|
64
|
+
}
|
|
65
|
+
/** What `map` returns: a plan, a list of steps, or a list of strings. */
|
|
66
|
+
export type PlanInput = {
|
|
67
|
+
title?: string;
|
|
68
|
+
goal?: string;
|
|
69
|
+
steps: Array<PlanStepInput | string>;
|
|
70
|
+
updatedAt?: When;
|
|
71
|
+
/**
|
|
72
|
+
* The steps will carry times (a start, a duration) — say it before the first one does,
|
|
73
|
+
* and every row keeps its time slot from the first draw, so the update that brings the
|
|
74
|
+
* first time moves no row. Without it, the slots appear with that update.
|
|
75
|
+
*/
|
|
76
|
+
timed?: boolean;
|
|
77
|
+
} | Array<PlanStepInput | string>;
|
|
78
|
+
/** One step as the card draws it, once read. */
|
|
79
|
+
export interface PlanStep {
|
|
80
|
+
/** The wording shown now: the active form while the step runs, when it has one. */
|
|
81
|
+
title: string;
|
|
82
|
+
/**
|
|
83
|
+
* The other wording — the active form while `title` is the plain one, and the reverse.
|
|
84
|
+
* Never shown: the title holds its room too, so the update that switches wording moves no row.
|
|
85
|
+
*/
|
|
86
|
+
altTitle?: string;
|
|
87
|
+
status: PlanStatus;
|
|
88
|
+
detail?: string;
|
|
89
|
+
startedAt?: Date;
|
|
90
|
+
finishedAt?: Date;
|
|
91
|
+
/** Seconds, never negative. */
|
|
92
|
+
duration?: number;
|
|
93
|
+
/** Never nested deeper. */
|
|
94
|
+
substeps?: PlanStep[];
|
|
95
|
+
id?: string;
|
|
96
|
+
}
|
|
97
|
+
/** The data as the card draws it. */
|
|
98
|
+
export interface PlanData {
|
|
99
|
+
title?: string;
|
|
100
|
+
goal?: string;
|
|
101
|
+
/** One at least; at most fifty, sub-steps counted. */
|
|
102
|
+
steps: PlanStep[];
|
|
103
|
+
updatedAt?: Date;
|
|
104
|
+
/** The plan said its steps will carry times: their slots are kept from the first draw. */
|
|
105
|
+
timed?: boolean;
|
|
106
|
+
}
|
|
107
|
+
/** How far a plan has got, over its top-level steps. */
|
|
108
|
+
export interface PlanProgress {
|
|
109
|
+
total: number;
|
|
110
|
+
done: number;
|
|
111
|
+
skipped: number;
|
|
112
|
+
failed: number;
|
|
113
|
+
blocked: number;
|
|
114
|
+
/** `done` + `skipped`: what the bar fills with. */
|
|
115
|
+
finished: number;
|
|
116
|
+
/** `finished / total`, 0–1. */
|
|
117
|
+
ratio: number;
|
|
118
|
+
/** The step under way: the first in progress, else the first to do, else the first blocked. */
|
|
119
|
+
current?: PlanStep;
|
|
120
|
+
currentIndex?: number;
|
|
121
|
+
/** With nothing left to do, the first step that failed — where the plan stopped. */
|
|
122
|
+
stoppedIndex?: number;
|
|
123
|
+
/** Seconds from the first start to the last date the plan holds, else the sum of the durations. */
|
|
124
|
+
elapsed?: number;
|
|
125
|
+
}
|
|
126
|
+
/** Fifty, sub-steps counted: past that a plan is a backlog, not something to follow. */
|
|
127
|
+
export declare const PLAN_STEPS_SHOWN = 50;
|
|
128
|
+
/** A status from what a tool wrote — `"in_progress"`, `"Running"`, `true` — or `undefined` for a word it does not know. */
|
|
129
|
+
export declare function readStatus(value: unknown): PlanStatus | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* The card's data from the loose shape `map` returns — `{ title, goal, steps }` (also
|
|
132
|
+
* `todos`, `tasks`, `items`, `plan`…), a list of steps or of strings, a Markdown
|
|
133
|
+
* checklist, LangGraph's `{ plan, past_steps }` — or `null` when it holds no step.
|
|
134
|
+
*/
|
|
135
|
+
export declare function readPlan(raw: unknown): PlanData | null;
|
|
136
|
+
/** How far the plan has got, counted over its top-level steps. */
|
|
137
|
+
export declare function planProgress(data: PlanData): PlanProgress;
|
|
138
|
+
/** A duration, its two largest units in their narrow form: `45s`, `1m 20s`, `2h 5m`, `0.4s`. */
|
|
139
|
+
export declare function durationText(config: AparteConfig, seconds: number): string;
|
|
140
|
+
export declare const planCard: {
|
|
141
|
+
name: string;
|
|
142
|
+
variants: readonly PlanVariant[];
|
|
143
|
+
setup: (options?: CardSetupOptions<PlanData, PlanVariant>) => () => void;
|
|
144
|
+
segment: (raw: unknown, options?: {
|
|
145
|
+
id?: string;
|
|
146
|
+
variant?: PlanVariant | undefined;
|
|
147
|
+
config?: AparteConfig;
|
|
148
|
+
}) => import("../index.js").AparteCardSegment;
|
|
149
|
+
};
|
|
150
|
+
/** Draw an agent's plan or task list as this card — returns the function that stops it. */
|
|
151
|
+
export declare function setupPlanCard(options?: CardSetupOptions<PlanData, PlanVariant>): () => void;
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plan/index.ts"],"names":[],"mappings":"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"}
|