{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "leaflet-neighborhood-walkscore-card",
  "title": "Leaflet Neighborhood Walkscore Card",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/leaflet-neighborhood-walkscore-card/leaflet-neighborhood-walkscore-card.component.ts",
      "content": "// Real estate neighborhood intelligence widget on free OpenStreetMap/Esri tiles — no API\n// key. Walk Score, Transit Score, Bike Score, categorized points of interest (transit, dining,\n// schools, parks), a 15-minute walk radius, and commute time estimator.\n// Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, DestroyRef, Input, computed, inject, signal } from '@angular/core'\nimport {\n  ArrowUpRight,\n  Bike,\n  Bookmark,\n  Bus,\n  Car,\n  Check,\n  Clock,\n  Coffee,\n  Footprints,\n  GraduationCap,\n  LucideAngularModule,\n  MapPin,\n  Navigation,\n  School,\n  Search,\n  Share2,\n  ShieldCheck,\n  Train,\n  TreePine,\n  UtensilsCrossed,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport {\n  UiLeafletCircleComponent,\n  UiLeafletMapComponent,\n  UiLeafletMarkerComponent,\n} from '@/ui/leaflet-map/leaflet-map.component'\n\nexport type PoiCategoryType = 'all' | 'transit' | 'dining' | 'schools' | 'parks'\nexport type CommuteMode = 'all' | 'transit' | 'drive'\n\nexport interface MobilityScore {\n  score: number\n  maxScore?: number\n  label: string\n  verdict: string\n  description: string\n  verdictClass: string\n  gaugeColor: string\n  subtext: string\n  highlights: string[]\n}\n\nexport interface PoiItem {\n  id: string\n  name: string\n  category: 'transit' | 'dining' | 'schools' | 'parks'\n  categoryLabel: string\n  distance: string\n  timeWalk?: string\n  timeDrive?: string\n  rating?: string\n  badge?: string\n  description: string\n  address: string\n  coords?: [number, number]\n}\n\nexport interface CommuteDestination {\n  id: string\n  name: string\n  region: string\n  distance: string\n  transitTime: number\n  transitLabel: string\n  transitRoute: string\n  driveTime: number\n  driveLabel: string\n  driveRoute: string\n  peakRushTime?: string\n}\n\nexport const DEFAULT_WALK_SCORE: MobilityScore = {\n  score: 94,\n  maxScore: 100,\n  label: 'Walk Score®',\n  verdict: \"Walker's Paradise\",\n  description: 'Daily errands do not require a car',\n  verdictClass: 'text-success',\n  gaugeColor: '#10b981',\n  subtext: '94 out of 100 on walkable street accessibility',\n  highlights: ['48 amenities within 10-min walk', '98% continuous sidewalks', 'Pedestrian safety grade: A+'],\n}\n\nexport const DEFAULT_TRANSIT_SCORE: MobilityScore = {\n  score: 82,\n  maxScore: 100,\n  label: 'Transit Score®',\n  verdict: 'Excellent Transit',\n  description: '6 nearby bus & light rail routes',\n  verdictClass: 'text-info',\n  gaugeColor: '#0ea5e9',\n  subtext: '82 out of 100 on public transportation connectivity',\n  highlights: ['Metro A Line station in 4 min', '5 frequent municipal bus routes', '18 min direct train to DTLA'],\n}\n\nexport const DEFAULT_BIKE_SCORE: MobilityScore = {\n  score: 88,\n  maxScore: 100,\n  label: 'Bike Score®',\n  verdict: 'Very Bikeable',\n  description: 'Dedicated bike lanes and flat terrain',\n  verdictClass: 'text-chart-1',\n  gaugeColor: 'var(--chart-1)',\n  subtext: '88 out of 100 on cycling infrastructure & slope',\n  highlights: ['14 miles of protected bike lanes', '<2% average street gradient', '3 bikeshare docks nearby'],\n}\n\nexport const DEFAULT_POIS: PoiItem[] = [\n  {\n    id: 'poi-1',\n    name: 'Metro A Line Station',\n    category: 'transit',\n    categoryLabel: 'Public Transit',\n    distance: '0.2 mi',\n    timeWalk: '4 min walk',\n    badge: 'Light Rail',\n    description: 'High-frequency light rail connecting Pasadena directly to Downtown LA and Long Beach.',\n    address: 'Del Mar Ave & S Raymond Ave',\n  },\n  {\n    id: 'poi-2',\n    name: 'Pasadena Transit Bus Stop',\n    category: 'transit',\n    categoryLabel: 'Public Transit',\n    distance: '0.1 mi',\n    timeWalk: '2 min walk',\n    badge: 'Local Transit',\n    description: 'Direct routes 10 & 20 connecting South Lake District to Old Town & City Hall.',\n    address: 'S Lake Ave & E Green St',\n  },\n  {\n    id: 'poi-3',\n    name: 'Memorial Park Station',\n    category: 'transit',\n    categoryLabel: 'Public Transit',\n    distance: '0.5 mi',\n    timeWalk: '10 min walk',\n    badge: 'Light Rail',\n    description: 'Alternative metro access with regional bus connection bays and bike lockups.',\n    address: '125 E Holly St',\n  },\n  {\n    id: 'poi-4',\n    name: 'Blue Bottle Coffee',\n    category: 'dining',\n    categoryLabel: 'Dining & Coffee',\n    distance: '0.1 mi',\n    timeWalk: '2 min walk',\n    rating: '4.8 ★',\n    badge: 'Artisanal Cafe',\n    description: 'Specialty pour-over coffee, single-origin espresso drinks, and fresh bakery pastries.',\n    address: '60 S Lake Ave',\n  },\n  {\n    id: 'poi-5',\n    name: 'Whole Foods Market',\n    category: 'dining',\n    categoryLabel: 'Dining & Coffee',\n    distance: '0.3 mi',\n    timeWalk: '6 min walk',\n    rating: '4.7 ★',\n    badge: 'Organic Grocery',\n    description: 'Full-service natural grocer with organic produce, prepared hot bar, and wellness center.',\n    address: '3751 E Foothill Blvd / Arroyo Pkwy',\n  },\n  {\n    id: 'poi-6',\n    name: \"Trader Joe's\",\n    category: 'dining',\n    categoryLabel: 'Dining & Coffee',\n    distance: '0.4 mi',\n    timeWalk: '8 min walk',\n    rating: '4.9 ★',\n    badge: 'Grocery',\n    description: 'Neighborhood market renowned for unique provisions, fresh bakery, and wine selection.',\n    address: '610 S Lake Ave',\n  },\n  {\n    id: 'poi-7',\n    name: 'Urth Caffe Pasadena',\n    category: 'dining',\n    categoryLabel: 'Dining & Coffee',\n    distance: '0.2 mi',\n    timeWalk: '5 min walk',\n    rating: '4.6 ★',\n    badge: 'Organic Eatery',\n    description: 'Vibrant indoor/outdoor patio serving farm-to-table organic breakfast, lunch, and matcha.',\n    address: '594 E Colorado Blvd',\n  },\n  {\n    id: 'poi-8',\n    name: 'Pasadena High School',\n    category: 'schools',\n    categoryLabel: 'Schools & Education',\n    distance: '0.6 mi',\n    timeWalk: '12 min walk',\n    rating: '9/10',\n    badge: 'Public 9-12',\n    description: 'Top-rated public high school with Law and Creative Arts academies and AP honors programs.',\n    address: '2925 E Sierra Madre Blvd',\n  },\n  {\n    id: 'poi-9',\n    name: 'Caltech Campus',\n    category: 'schools',\n    categoryLabel: 'Schools & Education',\n    distance: '0.8 mi',\n    timeWalk: '15 min walk',\n    rating: 'Top Tier',\n    badge: 'Higher Education',\n    description: 'World-renowned private science & engineering research university campus and open grounds.',\n    address: '1200 E California Blvd',\n  },\n  {\n    id: 'poi-10',\n    name: 'McKinley Elementary School',\n    category: 'schools',\n    categoryLabel: 'Schools & Education',\n    distance: '0.4 mi',\n    timeWalk: '8 min walk',\n    rating: '8/10',\n    badge: 'Public K-8',\n    description: 'STEAM-focused neighborhood magnet school with dual-language immersion track.',\n    address: '325 S Oak Knoll Ave',\n  },\n  {\n    id: 'poi-11',\n    name: 'Central Park',\n    category: 'parks',\n    categoryLabel: 'Parks & Recreation',\n    distance: '0.3 mi',\n    timeWalk: '6 min walk',\n    rating: '4.8 ★',\n    badge: 'Public Park',\n    description: 'Historic shaded park with rolling green lawns, dedicated dog park, and lawn bowling greens.',\n    address: '275 S Raymond Ave',\n  },\n  {\n    id: 'poi-12',\n    name: 'Rose Bowl Aquatics Center',\n    category: 'parks',\n    categoryLabel: 'Parks & Recreation',\n    distance: '1.4 mi',\n    timeDrive: '5 min drive',\n    rating: '4.9 ★',\n    badge: 'Sports Complex',\n    description: 'Twin Olympic 50-meter pools, fitness facilities, and adjacent Arroyo Seco running trails.',\n    address: '360 N Arroyo Blvd',\n  },\n]\n\nexport const DEFAULT_COMMUTES: CommuteDestination[] = [\n  {\n    id: 'commute-dtla',\n    name: 'Downtown Los Angeles',\n    region: 'Financial District & Union Station',\n    distance: '10.4 mi',\n    transitTime: 18,\n    transitLabel: '18m by train',\n    transitRoute: 'Metro A Line (Direct Express)',\n    driveTime: 24,\n    driveLabel: '24m by car',\n    driveRoute: 'via CA-110 S Freeway',\n    peakRushTime: '28-34m at 8:30 AM',\n  },\n  {\n    id: 'commute-sm',\n    name: 'Santa Monica',\n    region: 'Silicon Beach & Pier',\n    distance: '26.2 mi',\n    transitTime: 62,\n    transitLabel: '62m by train',\n    transitRoute: 'Metro A Line → Metro E Line',\n    driveTime: 45,\n    driveLabel: '45m by car',\n    driveRoute: 'via I-10 W / CA-110 S',\n    peakRushTime: '55-68m at 8:30 AM',\n  },\n  {\n    id: 'commute-burbank',\n    name: 'Burbank Media District',\n    region: 'Warner Bros & Disney Studios',\n    distance: '12.1 mi',\n    transitTime: 38,\n    transitLabel: '38m by transit',\n    transitRoute: 'Metro Bus 501 Rapid',\n    driveTime: 22,\n    driveLabel: '22m by car',\n    driveRoute: 'via CA-134 W Express',\n    peakRushTime: '26-32m at 8:30 AM',\n  },\n  {\n    id: 'commute-century',\n    name: 'Century City / Westwood',\n    region: 'Fox Studios & UCLA Area',\n    distance: '21.5 mi',\n    transitTime: 54,\n    transitLabel: '54m by transit',\n    transitRoute: 'Commuter Express 423',\n    driveTime: 38,\n    driveLabel: '38m by car',\n    driveRoute: 'via CA-134 W to I-405 S',\n    peakRushTime: '48-58m at 8:30 AM',\n  },\n]\n\n// Subject property (742 Evergreen Terrace, Pasadena) — map center, home marker,\n// and the 15-minute walkshed circle all anchor here.\nexport const HOME_CENTER: [number, number] = [-118.1445, 34.1478]\n// ~15-minute pedestrian catchment (~1.2 km at typical walking speed).\nexport const WALK_RADIUS_METERS = 1200\n\nconst DEFAULT_POI_COORDS: Record<string, [number, number]> = {\n  'poi-1': [-118.148, 34.141],\n  'poi-2': [-118.132, 34.152],\n  'poi-3': [-118.149, 34.148],\n  'poi-4': [-118.133, 34.144],\n  'poi-5': [-118.149, 34.135],\n  'poi-6': [-118.132, 34.136],\n  'poi-7': [-118.136, 34.146],\n  'poi-8': [-118.125, 34.155],\n  'poi-9': [-118.138, 34.138],\n  'poi-10': [-118.148, 34.143],\n  'poi-11': [-118.142, 34.133],\n}\n\n// Circular gauge calculation helper (radius 38, perimeter ~238.76)\nexport const GAUGE_CIRCUMFERENCE = 2 * Math.PI * 38\n\nexport function getGaugeDashOffset(score: number): number {\n  const clamped = Math.min(100, Math.max(0, score))\n  return GAUGE_CIRCUMFERENCE - (clamped / 100) * GAUGE_CIRCUMFERENCE\n}\n\ninterface PoiCategory {\n  id: PoiCategoryType\n  label: string\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-leaflet-neighborhood-walkscore-card, [ui-leaflet-neighborhood-walkscore-card]',\n  standalone: true,\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiInputComponent,\n    UiProgressComponent,\n    UiSeparatorComponent,\n    UiLeafletCircleComponent,\n    UiLeafletMapComponent,\n    UiLeafletMarkerComponent,\n  ],\n  host: {\n    'data-slot': 'leaflet-neighborhood-walkscore-card',\n    '[class]': 'hostClass',\n  },\n  template: `\n    <!-- Header Banner Card -->\n    <ui-card class=\"border-border/80 bg-card text-card-foreground shadow-xs\">\n      <ui-card-header class=\"p-4 sm:p-6\">\n        <div class=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n          <div class=\"space-y-2\">\n            <!-- Badges Bar -->\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <span ui-badge wrap variant=\"outline\" class=\"gap-1.5 font-medium\">\n                <lucide-icon [img]=\"MapPin\" class=\"text-primary size-3.5\" />\n                <span>{{ city }} · {{ zipCode }}</span>\n              </span>\n              <span ui-badge wrap variant=\"success\" class=\"gap-1 font-medium\">\n                <lucide-icon [img]=\"Footprints\" class=\"size-3.5\" />\n                <span>Walker's Paradise</span>\n              </span>\n              <span ui-badge wrap variant=\"secondary\" class=\"font-medium\"> Urban Transit Hub </span>\n            </div>\n\n            <!-- Title & Address -->\n            <div>\n              <h1 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n                {{ title }}\n              </h1>\n              <p class=\"text-foreground mt-1 text-sm font-semibold sm:text-base\">\n                {{ address }}\n              </p>\n              <p class=\"text-muted-foreground mt-0.5 text-xs sm:text-sm\">\n                Neighborhood: <span class=\"text-foreground font-medium\">{{ neighborhood }}</span>\n              </p>\n            </div>\n          </div>\n\n          <!-- Top Actions -->\n          <div class=\"flex flex-wrap items-center gap-2 self-start lg:self-auto\">\n            <button\n              ui-button\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-8 gap-1.5 text-xs font-medium shadow-xs\"\n              (click)=\"handleCopyAddress()\"\n            >\n              @if (isCopied()) {\n                <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n              } @else {\n                <lucide-icon [img]=\"Share2\" class=\"size-3.5\" />\n              }\n              <span>{{ isCopied() ? 'Address Copied' : 'Share Location' }}</span>\n            </button>\n\n            <button\n              ui-button\n              [variant]=\"isSaved() ? 'default' : 'outline'\"\n              size=\"sm\"\n              class=\"h-8 gap-1.5 text-xs font-medium shadow-xs\"\n              (click)=\"handleToggleSave()\"\n            >\n              <lucide-icon [img]=\"Bookmark\" [class]=\"isSaved() ? 'size-3.5 fill-current' : 'size-3.5'\" />\n              <span>{{ isSaved() ? 'Saved Neighborhood' : 'Save Area' }}</span>\n            </button>\n          </div>\n        </div>\n      </ui-card-header>\n    </ui-card>\n\n    <!-- Section 1: 3 Primary Mobility Score Cards -->\n    <div class=\"grid grid-cols-1 gap-4 md:grid-cols-3\">\n      <!-- Card 1: Walk Score -->\n      <ui-card\n        class=\"border-border/80 bg-card text-card-foreground hover:border-success/40 shadow-xs transition-colors\"\n      >\n        <ui-card-header class=\"p-4 pb-2 sm:p-5 sm:pb-2\">\n          <div class=\"flex items-center justify-between\">\n            <div class=\"flex items-center gap-2\">\n              <div\n                class=\"border-success/30 bg-success/10 text-success flex size-8 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"Footprints\" class=\"size-4\" />\n              </div>\n              <div>\n                <ui-card-title class=\"text-sm font-semibold\">{{ walkScore.label }}</ui-card-title>\n                <ui-card-description class=\"text-xs\">Pedestrian Index</ui-card-description>\n              </div>\n            </div>\n            <span ui-badge wrap variant=\"success\" class=\"text-xs font-semibold\"> {{ walkScore.score }}/100 </span>\n          </div>\n        </ui-card-header>\n\n        <ui-card-content class=\"space-y-4 p-4 pt-2 sm:p-5 sm:pt-2\">\n          <!-- Circular Gauge & Score Verdict -->\n          <div class=\"flex items-center gap-4 pt-1\">\n            <div class=\"relative flex size-20 shrink-0 items-center justify-center\">\n              <svg class=\"size-20 -rotate-90\" viewBox=\"0 0 96 96\">\n                <circle\n                  cx=\"48\"\n                  cy=\"48\"\n                  r=\"38\"\n                  fill=\"none\"\n                  stroke=\"currentColor\"\n                  stroke-width=\"7\"\n                  class=\"text-muted/40\"\n                />\n                <circle\n                  cx=\"48\"\n                  cy=\"48\"\n                  r=\"38\"\n                  fill=\"none\"\n                  [attr.stroke]=\"walkScore.gaugeColor\"\n                  stroke-width=\"7\"\n                  stroke-linecap=\"round\"\n                  [attr.stroke-dasharray]=\"gaugeCircumference\"\n                  [attr.stroke-dashoffset]=\"gaugeOffset(walkScore.score)\"\n                  class=\"transition-colors duration-700 ease-out\"\n                />\n              </svg>\n              <div class=\"absolute inset-0 flex flex-col items-center justify-center text-center\">\n                <span class=\"text-foreground font-mono text-xl font-bold tracking-tight tabular-nums\">\n                  {{ walkScore.score }}\n                </span>\n                <span class=\"text-muted-foreground text-xs font-medium\">/ 100</span>\n              </div>\n            </div>\n\n            <div class=\"space-y-1\">\n              <div class=\"text-foreground text-sm font-bold tracking-tight\">\n                {{ walkScore.verdict }}\n              </div>\n              <p class=\"text-success text-xs leading-relaxed font-semibold\">\n                {{ walkScore.description }}\n              </p>\n            </div>\n          </div>\n\n          <ui-separator class=\"bg-border/60\" />\n\n          <!-- Key Highlights -->\n          <div class=\"space-y-1.5\">\n            <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Mobility Highlights</p>\n            <ul class=\"space-y-1 text-xs\">\n              @for (item of walkScore.highlights; track $index) {\n                <li class=\"text-foreground flex items-center gap-2\">\n                  <lucide-icon [img]=\"Check\" class=\"text-success size-3.5 shrink-0\" />\n                  <span>{{ item }}</span>\n                </li>\n              }\n            </ul>\n          </div>\n        </ui-card-content>\n      </ui-card>\n\n      <!-- Card 2: Transit Score -->\n      <ui-card class=\"border-border/80 bg-card text-card-foreground hover:border-info/40 shadow-xs transition-colors\">\n        <ui-card-header class=\"p-4 pb-2 sm:p-5 sm:pb-2\">\n          <div class=\"flex items-center justify-between\">\n            <div class=\"flex items-center gap-2\">\n              <div\n                class=\"border-info/30 bg-info/10 text-info flex size-8 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"Bus\" class=\"size-4\" />\n              </div>\n              <div>\n                <ui-card-title class=\"text-sm font-semibold\">{{ transitScore.label }}</ui-card-title>\n                <ui-card-description class=\"text-xs\">Transit Connectivity</ui-card-description>\n              </div>\n            </div>\n            <span ui-badge wrap variant=\"info\" class=\"text-xs font-semibold\"> {{ transitScore.score }}/100 </span>\n          </div>\n        </ui-card-header>\n\n        <ui-card-content class=\"space-y-4 p-4 pt-2 sm:p-5 sm:pt-2\">\n          <!-- Circular Gauge & Score Verdict -->\n          <div class=\"flex items-center gap-4 pt-1\">\n            <div class=\"relative flex size-20 shrink-0 items-center justify-center\">\n              <svg class=\"size-20 -rotate-90\" viewBox=\"0 0 96 96\">\n                <circle\n                  cx=\"48\"\n                  cy=\"48\"\n                  r=\"38\"\n                  fill=\"none\"\n                  stroke=\"currentColor\"\n                  stroke-width=\"7\"\n                  class=\"text-muted/40\"\n                />\n                <circle\n                  cx=\"48\"\n                  cy=\"48\"\n                  r=\"38\"\n                  fill=\"none\"\n                  [attr.stroke]=\"transitScore.gaugeColor\"\n                  stroke-width=\"7\"\n                  stroke-linecap=\"round\"\n                  [attr.stroke-dasharray]=\"gaugeCircumference\"\n                  [attr.stroke-dashoffset]=\"gaugeOffset(transitScore.score)\"\n                  class=\"transition-colors duration-700 ease-out\"\n                />\n              </svg>\n              <div class=\"absolute inset-0 flex flex-col items-center justify-center text-center\">\n                <span class=\"text-foreground font-mono text-xl font-bold tracking-tight tabular-nums\">\n                  {{ transitScore.score }}\n                </span>\n                <span class=\"text-muted-foreground text-xs font-medium\">/ 100</span>\n              </div>\n            </div>\n\n            <div class=\"space-y-1\">\n              <div class=\"text-foreground text-sm font-bold tracking-tight\">\n                {{ transitScore.verdict }}\n              </div>\n              <p class=\"text-info text-xs leading-relaxed font-semibold\">\n                {{ transitScore.description }}\n              </p>\n            </div>\n          </div>\n\n          <ui-separator class=\"bg-border/60\" />\n\n          <!-- Key Highlights -->\n          <div class=\"space-y-1.5\">\n            <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Transit Highlights</p>\n            <ul class=\"space-y-1 text-xs\">\n              @for (item of transitScore.highlights; track $index) {\n                <li class=\"text-foreground flex items-center gap-2\">\n                  <lucide-icon [img]=\"Check\" class=\"text-info size-3.5 shrink-0\" />\n                  <span>{{ item }}</span>\n                </li>\n              }\n            </ul>\n          </div>\n        </ui-card-content>\n      </ui-card>\n\n      <!-- Card 3: Bike Score -->\n      <ui-card\n        class=\"border-border/80 bg-card text-card-foreground hover:border-chart-1/40 shadow-xs transition-colors\"\n      >\n        <ui-card-header class=\"p-4 pb-2 sm:p-5 sm:pb-2\">\n          <div class=\"flex items-center justify-between\">\n            <div class=\"flex items-center gap-2\">\n              <div\n                class=\"border-chart-1/30 bg-chart-1/10 text-chart-1 flex size-8 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"Bike\" class=\"size-4\" />\n              </div>\n              <div>\n                <ui-card-title class=\"text-sm font-semibold\">{{ bikeScore.label }}</ui-card-title>\n                <ui-card-description class=\"text-xs\">Cycling Grid</ui-card-description>\n              </div>\n            </div>\n            <span ui-badge wrap variant=\"outline\" class=\"text-xs font-semibold\"> {{ bikeScore.score }}/100 </span>\n          </div>\n        </ui-card-header>\n\n        <ui-card-content class=\"space-y-4 p-4 pt-2 sm:p-5 sm:pt-2\">\n          <!-- Circular Gauge & Score Verdict -->\n          <div class=\"flex items-center gap-4 pt-1\">\n            <div class=\"relative flex size-20 shrink-0 items-center justify-center\">\n              <svg class=\"size-20 -rotate-90\" viewBox=\"0 0 96 96\">\n                <circle\n                  cx=\"48\"\n                  cy=\"48\"\n                  r=\"38\"\n                  fill=\"none\"\n                  stroke=\"currentColor\"\n                  stroke-width=\"7\"\n                  class=\"text-muted/40\"\n                />\n                <circle\n                  cx=\"48\"\n                  cy=\"48\"\n                  r=\"38\"\n                  fill=\"none\"\n                  [attr.stroke]=\"bikeScore.gaugeColor\"\n                  stroke-width=\"7\"\n                  stroke-linecap=\"round\"\n                  [attr.stroke-dasharray]=\"gaugeCircumference\"\n                  [attr.stroke-dashoffset]=\"gaugeOffset(bikeScore.score)\"\n                  class=\"transition-colors duration-700 ease-out\"\n                />\n              </svg>\n              <div class=\"absolute inset-0 flex flex-col items-center justify-center text-center\">\n                <span class=\"text-foreground font-mono text-xl font-bold tracking-tight tabular-nums\">\n                  {{ bikeScore.score }}\n                </span>\n                <span class=\"text-muted-foreground text-xs font-medium\">/ 100</span>\n              </div>\n            </div>\n\n            <div class=\"space-y-1\">\n              <div class=\"text-foreground text-sm font-bold tracking-tight\">\n                {{ bikeScore.verdict }}\n              </div>\n              <p class=\"text-chart-1 text-xs leading-relaxed font-semibold\">\n                {{ bikeScore.description }}\n              </p>\n            </div>\n          </div>\n\n          <ui-separator class=\"bg-border/60\" />\n\n          <!-- Key Highlights -->\n          <div class=\"space-y-1.5\">\n            <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Cycling Highlights</p>\n            <ul class=\"space-y-1 text-xs\">\n              @for (item of bikeScore.highlights; track $index) {\n                <li class=\"text-foreground flex items-center gap-2\">\n                  <lucide-icon [img]=\"Check\" class=\"text-chart-1 size-3.5 shrink-0\" />\n                  <span>{{ item }}</span>\n                </li>\n              }\n            </ul>\n          </div>\n        </ui-card-content>\n      </ui-card>\n    </div>\n\n    <!-- Section 2: Commute Time Estimator -->\n    <div class=\"space-y-3\">\n      <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n        <div>\n          <h2 class=\"text-foreground text-sm font-semibold tracking-tight\">Commute Time Estimator</h2>\n          <p class=\"text-muted-foreground text-xs\">\n            Estimated travel duration from 742 Evergreen Terrace to key employment & lifestyle hubs.\n          </p>\n        </div>\n\n        <!-- Mode selector filters -->\n        <div class=\"border-border/80 bg-muted/40 flex items-center rounded-lg border p-1 text-xs\">\n          <button type=\"button\" [class]=\"commuteModeClass('all')\" (click)=\"selectedCommuteMode.set('all')\">\n            All Modes\n          </button>\n          <button\n            type=\"button\"\n            [class]=\"commuteModeClass('transit', true)\"\n            (click)=\"selectedCommuteMode.set('transit')\"\n          >\n            <lucide-icon [img]=\"Train\" class=\"size-3\" />\n            <span>Transit</span>\n          </button>\n          <button type=\"button\" [class]=\"commuteModeClass('drive', true)\" (click)=\"selectedCommuteMode.set('drive')\">\n            <lucide-icon [img]=\"Car\" class=\"size-3\" />\n            <span>Driving</span>\n          </button>\n        </div>\n      </div>\n\n      <ui-card class=\"border-border/80 bg-card text-card-foreground overflow-hidden shadow-xs\">\n        <div class=\"divide-border/60 divide-y\">\n          @for (commute of commutes; track commute.id) {\n            <div class=\"hover:bg-muted/15 p-4 transition-colors sm:p-5\">\n              <div class=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n                <!-- Destination Info -->\n                <div class=\"space-y-1\">\n                  <div class=\"flex items-center gap-2\">\n                    <h3 class=\"text-foreground text-sm font-semibold\">{{ commute.name }}</h3>\n                    <span class=\"text-muted-foreground font-mono text-xs tabular-nums\">· {{ commute.distance }}</span>\n                  </div>\n                  <p class=\"text-muted-foreground text-xs\">{{ commute.region }}</p>\n                </div>\n\n                <!-- Time Badges & Routes -->\n                <div class=\"flex flex-wrap items-center gap-3\">\n                  <!-- Transit Mode Pill -->\n                  @if (showTransit()) {\n                    <div\n                      class=\"border-info/20 bg-info/10 flex items-center gap-2 rounded-lg border px-3 py-1.5 text-xs\"\n                    >\n                      <lucide-icon [img]=\"Train\" class=\"text-info size-3.5\" />\n                      <div>\n                        <span class=\"text-foreground font-mono font-semibold tabular-nums\">\n                          {{ commute.transitLabel }}\n                        </span>\n                        <span class=\"text-muted-foreground hidden sm:inline\"> — {{ commute.transitRoute }}</span>\n                      </div>\n                    </div>\n                  }\n\n                  <!-- Drive Mode Pill -->\n                  @if (showDrive()) {\n                    <div\n                      class=\"border-success/20 bg-success/10 flex items-center gap-2 rounded-lg border px-3 py-1.5 text-xs\"\n                    >\n                      <lucide-icon [img]=\"Car\" class=\"text-success size-3.5\" />\n                      <div>\n                        <span class=\"text-foreground font-mono font-semibold tabular-nums\">\n                          {{ commute.driveLabel }}\n                        </span>\n                        <span class=\"text-muted-foreground hidden sm:inline\"> — {{ commute.driveRoute }}</span>\n                      </div>\n                    </div>\n                  }\n\n                  <!-- Peak Rush Info -->\n                  @if (commute.peakRushTime) {\n                    <div class=\"text-muted-foreground flex items-center gap-1 font-mono text-xs tabular-nums\">\n                      <lucide-icon [img]=\"Clock\" class=\"text-muted-foreground size-3\" />\n                      <span>Rush: {{ commute.peakRushTime }}</span>\n                    </div>\n                  }\n                </div>\n              </div>\n\n              <!-- Visual Progress Bar for Comparative Duration -->\n              <div class=\"mt-3 grid grid-cols-1 gap-2 pt-1 sm:grid-cols-2\">\n                @if (showTransit()) {\n                  <div class=\"space-y-1\">\n                    <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                      <span>Transit Duration</span>\n                      <span class=\"font-mono tabular-nums\">{{ commute.transitTime }} min</span>\n                    </div>\n                    <ui-progress [value]=\"transitProgress(commute)\" class=\"bg-muted h-1.5\" />\n                  </div>\n                }\n\n                @if (showDrive()) {\n                  <div class=\"space-y-1\">\n                    <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                      <span>Driving Duration</span>\n                      <span class=\"font-mono tabular-nums\">{{ commute.driveTime }} min</span>\n                    </div>\n                    <ui-progress [value]=\"driveProgress(commute)\" class=\"bg-muted h-1.5\" />\n                  </div>\n                }\n              </div>\n            </div>\n          }\n        </div>\n      </ui-card>\n    </div>\n\n    <!-- Section 3: Nearby Points of Interest Categorized List -->\n    <div class=\"space-y-3\">\n      <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n        <div>\n          <h2 class=\"text-foreground text-sm font-semibold tracking-tight\">Nearby Points of Interest</h2>\n          <p class=\"text-muted-foreground text-xs\">\n            Key transit hubs, dining, specialty cafes, schools, and parks located within walking distance.\n          </p>\n        </div>\n\n        <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n          <lucide-icon [img]=\"Navigation\" class=\"text-primary size-3.5\" />\n          <span class=\"font-mono tabular-nums\">{{ pois.length }} verified local venues</span>\n        </div>\n      </div>\n\n      <!-- Controls: Category Filter Tabs & Search Bar -->\n      <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n        <!-- Category Filter Tabs -->\n        <div class=\"flex flex-wrap items-center gap-1.5\">\n          @for (cat of categoriesList(); track cat.id) {\n            <button type=\"button\" [class]=\"categoryTabClass(cat.id)\" (click)=\"selectedCategory.set(cat.id)\">\n              {{ cat.label }}\n              <span\n                [class]=\"\n                  selectedCategory() === cat.id\n                    ? 'ml-1 font-mono tabular-nums opacity-80'\n                    : 'text-muted-foreground ml-1 font-mono tabular-nums'\n                \"\n              >\n                ({{ categoryCount(cat.id) }})\n              </span>\n            </button>\n          }\n        </div>\n\n        <!-- Search Input -->\n        <div class=\"relative w-full sm:w-64\">\n          <lucide-icon\n            [img]=\"Search\"\n            class=\"text-muted-foreground pointer-events-none absolute top-2.5 left-2.5 z-10 size-3.5\"\n          />\n          <ui-input\n            [value]=\"searchQuery()\"\n            (valueChange)=\"searchQuery.set($event)\"\n            placeholder=\"Search venue or street...\"\n            class=\"h-8 w-full pl-8 text-xs\"\n          />\n        </div>\n      </div>\n\n      <!-- Interactive 15-Minute Walkshed & POI Map -->\n      <ui-card class=\"overflow-hidden\">\n        <ui-card-header class=\"border-border/70 border-b p-4 pb-3 sm:p-5 sm:pb-3\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div>\n              <ui-card-title class=\"flex items-center gap-2 text-base font-semibold\">\n                <lucide-icon [img]=\"Navigation\" class=\"text-success size-4\" />\n                <span>15-Minute Walkshed & Amenity Locator</span>\n              </ui-card-title>\n              <ui-card-description>\n                Free OpenStreetMap/Esri basemap — no API key — with a 15-minute walk radius and categorized local\n                destinations.\n              </ui-card-description>\n            </div>\n            <span ui-badge variant=\"outline\" class=\"w-fit gap-1 font-mono text-xs\">\n              <lucide-icon [img]=\"Footprints\" class=\"text-success size-3\" />\n              <span>98 Walk Score Paradise</span>\n            </span>\n          </div>\n        </ui-card-header>\n        <div class=\"relative h-72 w-full sm:h-96\">\n          <ui-leaflet-map variant=\"light\" [center]=\"homeCenter\" [zoom]=\"14\" class=\"size-full\">\n            <!-- 15-min Walk Radius Circle -->\n            <ui-leaflet-circle\n              [center]=\"homeCenter\"\n              [radius]=\"walkRadiusMeters\"\n              color=\"#10b981\"\n              [weight]=\"1.5\"\n              [opacity]=\"0.6\"\n              dashArray=\"4 4\"\n              [fill]=\"true\"\n              fillColor=\"#10b981\"\n              [fillOpacity]=\"0.12\"\n            />\n\n            <!-- Home Property Marker -->\n            <ui-leaflet-marker [lngLat]=\"homeCenter\" anchor=\"center\" [zIndexOffset]=\"30\">\n              <div class=\"relative flex size-9 items-center justify-center\">\n                <span class=\"bg-warning absolute inline-flex size-full animate-ping rounded-full opacity-60\"></span>\n                <div\n                  class=\"bg-warning relative flex size-7 items-center justify-center rounded-full border-2 border-white text-white shadow-lg\"\n                >\n                  <lucide-icon [img]=\"MapPin\" class=\"size-4\" />\n                </div>\n              </div>\n            </ui-leaflet-marker>\n\n            <!-- Filtered POI Markers -->\n            @for (poi of filteredPois(); track poi.id) {\n              <ui-leaflet-marker [lngLat]=\"poiCoords(poi)\" anchor=\"center\">\n                <div\n                  class=\"border-background bg-background flex size-7 cursor-pointer items-center justify-center rounded-full border-2 shadow-md select-none\"\n                  [attr.title]=\"poi.name\"\n                >\n                  @if (poi.category === 'dining') {\n                    <lucide-icon [img]=\"Coffee\" class=\"text-warning size-3.5\" />\n                  } @else if (poi.category === 'transit') {\n                    <lucide-icon [img]=\"Train\" class=\"text-info size-3.5\" />\n                  } @else if (poi.category === 'schools') {\n                    <lucide-icon [img]=\"School\" class=\"text-chart-2 size-3.5\" />\n                  } @else {\n                    <lucide-icon [img]=\"TreePine\" class=\"text-success size-3.5\" />\n                  }\n                </div>\n              </ui-leaflet-marker>\n            }\n          </ui-leaflet-map>\n        </div>\n      </ui-card>\n\n      <!-- POIs Grid -->\n      @if (filteredPois().length > 0) {\n        <div class=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n          @for (poi of filteredPois(); track poi.id) {\n            <ui-card\n              class=\"border-border/80 bg-card text-card-foreground hover:border-border transition-colors hover:shadow-xs\"\n            >\n              <ui-card-content class=\"p-4 sm:p-4\">\n                <div class=\"flex items-start gap-3\">\n                  <!-- Icon Box based on category -->\n                  <div [class]=\"poiIconBoxClass(poi)\">\n                    @if (poi.category === 'transit' && poi.badge === 'Light Rail') {\n                      <lucide-icon [img]=\"Train\" class=\"size-4\" />\n                    } @else if (poi.category === 'transit') {\n                      <lucide-icon [img]=\"Bus\" class=\"size-4\" />\n                    } @else if (poi.category === 'dining' && poi.name.includes('Coffee')) {\n                      <lucide-icon [img]=\"Coffee\" class=\"size-4\" />\n                    } @else if (poi.category === 'dining') {\n                      <lucide-icon [img]=\"UtensilsCrossed\" class=\"size-4\" />\n                    } @else if (poi.category === 'schools' && poi.name.includes('Caltech')) {\n                      <lucide-icon [img]=\"GraduationCap\" class=\"size-4\" />\n                    } @else if (poi.category === 'schools') {\n                      <lucide-icon [img]=\"School\" class=\"size-4\" />\n                    } @else {\n                      <lucide-icon [img]=\"TreePine\" class=\"size-4\" />\n                    }\n                  </div>\n\n                  <!-- Main POI Details -->\n                  <div class=\"min-w-0 flex-1 space-y-1\">\n                    <div class=\"flex items-start justify-between gap-2\">\n                      <h3 class=\"text-foreground truncate text-sm font-semibold\">\n                        {{ poi.name }}\n                      </h3>\n\n                      <!-- Distance / Walk Time Pill -->\n                      <div\n                        class=\"bg-muted/70 text-foreground border-border/60 shrink-0 rounded-md border px-2 py-0.5 font-mono text-xs font-medium tabular-nums\"\n                      >\n                        <span>{{ poi.distance }}</span>\n                        @if (poi.timeWalk) {\n                          <span class=\"text-muted-foreground\"> · {{ poi.timeWalk }}</span>\n                        } @else if (poi.timeDrive) {\n                          <span class=\"text-muted-foreground\"> · {{ poi.timeDrive }}</span>\n                        }\n                      </div>\n                    </div>\n\n                    <p class=\"text-muted-foreground line-clamp-2 text-xs leading-relaxed\">\n                      {{ poi.description }}\n                    </p>\n\n                    <div class=\"flex flex-wrap items-center justify-between gap-2 pt-1.5 text-xs\">\n                      <span class=\"text-muted-foreground truncate\">{{ poi.address }}</span>\n                      <div class=\"flex items-center gap-1.5\">\n                        @if (poi.rating) {\n                          <span ui-badge wrap variant=\"secondary\" class=\"font-mono text-xs font-semibold tabular-nums\">\n                            {{ poi.rating }}\n                          </span>\n                        }\n                        @if (poi.badge) {\n                          <span ui-badge wrap variant=\"outline\" class=\"text-xs\">\n                            {{ poi.badge }}\n                          </span>\n                        }\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              </ui-card-content>\n            </ui-card>\n          }\n        </div>\n      } @else {\n        <!-- Empty State when filter yields nothing -->\n        <ui-card class=\"border-border/80 bg-card text-card-foreground p-8 text-center shadow-xs\">\n          <div class=\"mx-auto flex max-w-sm flex-col items-center justify-center space-y-2\">\n            <lucide-icon [img]=\"Search\" class=\"text-muted-foreground size-8\" />\n            <p class=\"text-foreground text-sm font-semibold\">No points of interest match \"{{ searchQuery() }}\"</p>\n            <p class=\"text-muted-foreground text-xs\">\n              Try searching for other amenities like \"coffee\", \"market\", \"school\", or clear the filter.\n            </p>\n            <button ui-button variant=\"outline\" size=\"sm\" class=\"mt-2 text-xs\" (click)=\"resetFilters()\">\n              Clear Filters\n            </button>\n          </div>\n        </ui-card>\n      }\n    </div>\n\n    <!-- Section 4: Quick Neighborhood Summary Footnote -->\n    <ui-card class=\"border-border/80 bg-muted/25 text-card-foreground p-4 shadow-xs sm:p-5\">\n      <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"space-y-1\">\n          <div class=\"flex items-center gap-2\">\n            <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-4\" />\n            <p class=\"text-foreground text-xs font-semibold\">Official Location Score Intelligence Verification</p>\n          </div>\n          <p class=\"text-muted-foreground text-xs\">\n            Calculated based on standard 15-minute pedestrian catchment models, municipal route timetables, and GIS road\n            grades.\n          </p>\n        </div>\n\n        <div class=\"flex items-center gap-3\">\n          <button\n            ui-button\n            variant=\"outline\"\n            size=\"sm\"\n            class=\"h-8 gap-1.5 text-xs font-medium shadow-xs\"\n            (click)=\"handleCopyAddress()\"\n          >\n            <lucide-icon [img]=\"ArrowUpRight\" class=\"size-3.5\" />\n            <span>Open in Maps</span>\n          </button>\n        </div>\n      </div>\n    </ui-card>\n  `,\n})\nexport class UiLeafletNeighborhoodWalkscoreCardComponent {\n  protected readonly ArrowUpRight = ArrowUpRight\n  protected readonly Bike = Bike\n  protected readonly Bookmark = Bookmark\n  protected readonly Bus = Bus\n  protected readonly Car = Car\n  protected readonly Check = Check\n  protected readonly Clock = Clock\n  protected readonly Coffee = Coffee\n  protected readonly Footprints = Footprints\n  protected readonly GraduationCap = GraduationCap\n  protected readonly MapPin = MapPin\n  protected readonly Navigation = Navigation\n  protected readonly School = School\n  protected readonly Search = Search\n  protected readonly Share2 = Share2\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Train = Train\n  protected readonly TreePine = TreePine\n  protected readonly UtensilsCrossed = UtensilsCrossed\n\n  @Input() title = 'Neighborhood & Location Intelligence'\n  @Input() address = '742 Evergreen Terrace, Pasadena, CA 91101'\n  @Input() neighborhood = 'South Lake Commercial & Arts District'\n  @Input() city = 'Pasadena'\n  @Input() zipCode = '91101'\n  @Input() walkScore: MobilityScore = DEFAULT_WALK_SCORE\n  @Input() transitScore: MobilityScore = DEFAULT_TRANSIT_SCORE\n  @Input() bikeScore: MobilityScore = DEFAULT_BIKE_SCORE\n  @Input() pois: PoiItem[] = DEFAULT_POIS\n  @Input() commutes: CommuteDestination[] = DEFAULT_COMMUTES\n  @Input('class') className?: string\n\n  protected readonly homeCenter = HOME_CENTER\n  protected readonly walkRadiusMeters = WALK_RADIUS_METERS\n  protected readonly gaugeCircumference = GAUGE_CIRCUMFERENCE\n\n  readonly selectedCategory = signal<PoiCategoryType>('all')\n  readonly searchQuery = signal('')\n  readonly selectedCommuteMode = signal<CommuteMode>('all')\n  readonly isSaved = signal(false)\n  readonly isCopied = signal(false)\n  private copyTimer: ReturnType<typeof setTimeout> | undefined\n\n  constructor() {\n    inject(DestroyRef).onDestroy(() => clearTimeout(this.copyTimer))\n  }\n\n  get hostClass(): string {\n    return cn('w-full space-y-6', this.className)\n  }\n\n  readonly categoriesList = computed<PoiCategory[]>(() => [\n    { id: 'all', label: 'All Places' },\n    { id: 'transit', label: 'Public Transit' },\n    { id: 'dining', label: 'Dining & Coffee' },\n    { id: 'schools', label: 'Schools & Education' },\n    { id: 'parks', label: 'Parks & Rec' },\n  ])\n\n  categoryCount(id: PoiCategoryType): number {\n    if (id === 'all') return this.pois.length\n    return this.pois.filter((p) => p.category === id).length\n  }\n\n  readonly filteredPois = computed(() => {\n    const cat = this.selectedCategory()\n    const q = this.searchQuery().trim().toLowerCase()\n    return this.pois.filter((poi) => {\n      const matchesCat = cat === 'all' || poi.category === cat\n      const matchesSearch =\n        q === '' ||\n        poi.name.toLowerCase().includes(q) ||\n        poi.description.toLowerCase().includes(q) ||\n        poi.address.toLowerCase().includes(q) ||\n        (poi.badge?.toLowerCase().includes(q) ?? false)\n      return matchesCat && matchesSearch\n    })\n  })\n\n  showTransit(): boolean {\n    return this.selectedCommuteMode() === 'all' || this.selectedCommuteMode() === 'transit'\n  }\n\n  showDrive(): boolean {\n    return this.selectedCommuteMode() === 'all' || this.selectedCommuteMode() === 'drive'\n  }\n\n  gaugeOffset(score: number): number {\n    return getGaugeDashOffset(score)\n  }\n\n  transitProgress(c: CommuteDestination): number {\n    return Math.min(100, (c.transitTime / 70) * 100)\n  }\n\n  driveProgress(c: CommuteDestination): number {\n    return Math.min(100, (c.driveTime / 70) * 100)\n  }\n\n  poiCoords(poi: PoiItem): [number, number] {\n    if (poi.coords) return poi.coords\n    return (\n      DEFAULT_POI_COORDS[poi.id] ?? [\n        HOME_CENTER[0] + Math.sin(poi.name.length) * 0.008,\n        HOME_CENTER[1] + Math.cos(poi.name.length) * 0.008,\n      ]\n    )\n  }\n\n  categoryTabClass(id: PoiCategoryType): string {\n    return cn(\n      'focus-visible:ring-ring rounded-md border px-3 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n      this.selectedCategory() === id\n        ? 'border-primary bg-primary text-primary-foreground shadow-xs'\n        : 'border-border/80 bg-card text-muted-foreground hover:bg-muted hover:text-foreground',\n    )\n  }\n\n  commuteModeClass(mode: CommuteMode, withIcon = false): string {\n    return cn(\n      'focus-visible:ring-ring rounded-md px-2.5 py-1 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n      withIcon && 'flex items-center gap-1',\n      this.selectedCommuteMode() === mode\n        ? 'bg-background text-foreground shadow-xs'\n        : 'text-muted-foreground hover:text-foreground',\n    )\n  }\n\n  poiIconBoxClass(poi: PoiItem): string {\n    return cn(\n      'flex size-9 shrink-0 items-center justify-center rounded-lg border',\n      poi.category === 'transit' && 'border-info/30 bg-info/10 text-info',\n      poi.category === 'dining' && 'border-warning/30 bg-warning/10 text-warning',\n      poi.category === 'schools' && 'border-chart-2/30 bg-chart-2/10 text-chart-2',\n      poi.category === 'parks' && 'border-success/30 bg-success/10 text-success',\n    )\n  }\n\n  resetFilters(): void {\n    this.searchQuery.set('')\n    this.selectedCategory.set('all')\n  }\n\n  handleCopyAddress(): void {\n    try {\n      void navigator.clipboard?.writeText(`${this.address}, ${this.neighborhood}`)\n      this.isCopied.set(true)\n      clearTimeout(this.copyTimer)\n      this.copyTimer = setTimeout(() => this.isCopied.set(false), 2000)\n    } catch {\n      // Clipboard unavailable (non-secure context) — leave the button state alone.\n    }\n  }\n\n  handleToggleSave(): void {\n    this.isSaved.set(!this.isSaved())\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/leaflet-neighborhood-walkscore-card/leaflet-neighborhood-walkscore-card.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/leaflet-neighborhood-walkscore-card/index.ts",
      "content": "export {\n  UiLeafletNeighborhoodWalkscoreCardComponent,\n  HOME_CENTER,\n  WALK_RADIUS_METERS,\n  DEFAULT_WALK_SCORE,\n  DEFAULT_TRANSIT_SCORE,\n  DEFAULT_BIKE_SCORE,\n  DEFAULT_POIS,\n  DEFAULT_COMMUTES,\n  GAUGE_CIRCUMFERENCE,\n  getGaugeDashOffset,\n  type MobilityScore,\n  type PoiItem,\n  type PoiCategoryType,\n  type CommuteDestination,\n  type CommuteMode,\n} from './leaflet-neighborhood-walkscore-card.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/leaflet-neighborhood-walkscore-card/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/progress.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/leaflet-map.json"
  ],
  "description": "Real estate neighborhood intelligence widget on free OpenStreetMap/Esri tiles — no API key. Walk Score, Transit Score, Bike Score, categorized points of interest (transit, dining, schools, parks), a 15-minute walk radius, and commute time estimator.",
  "categories": [
    "real-estate",
    "app",
    "dashboard",
    "marketing"
  ]
}