astro-component-kit 0.3.1 → 0.4.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.
Files changed (249) hide show
  1. package/README.md +133 -36
  2. package/package.json +17 -4
  3. package/src/components/index.ts +18 -202
  4. package/src/components/lib/Galaxy3D.astro +249 -137
  5. package/src/components/lib/app/AppSidebar.astro +249 -0
  6. package/src/components/lib/app/AppTopbar.astro +284 -0
  7. package/src/components/lib/app/ArrivalsBoard.astro +176 -0
  8. package/src/components/lib/app/AuthCard.astro +213 -0
  9. package/src/components/lib/app/DataTable.astro +346 -0
  10. package/src/components/lib/app/GuestProfileCard.astro +133 -0
  11. package/src/components/lib/app/HousekeepingBoard.astro +189 -0
  12. package/src/components/lib/app/PageHeader.astro +157 -0
  13. package/src/components/lib/app/PlanUsageCard.astro +112 -0
  14. package/src/components/lib/app/RoomRack.astro +207 -0
  15. package/src/components/lib/app/SettingsSection.astro +96 -0
  16. package/src/components/lib/app/SwitchRow.astro +71 -0
  17. package/src/components/lib/app/TeamMembers.astro +190 -0
  18. package/src/components/lib/app/app-icons.ts +52 -0
  19. package/src/components/lib/app/index.ts +19 -0
  20. package/src/components/lib/buttons/NeonBorderButton.astro +162 -0
  21. package/src/components/lib/buttons/RippleButton.astro +199 -0
  22. package/src/components/lib/buttons/SlideRevealButton.astro +159 -0
  23. package/src/components/lib/buttons/index.ts +4 -0
  24. package/src/components/lib/cards/GithubRepoCard.astro +176 -0
  25. package/src/components/lib/cards/PricingCompareMiniCard.astro +196 -0
  26. package/src/components/lib/cards/StatsTrendCard.astro +149 -0
  27. package/src/components/lib/cards/index.ts +3 -0
  28. package/src/components/lib/charts/ActivityRings.astro +105 -0
  29. package/src/components/lib/charts/AreaChart.astro +4 -4
  30. package/src/components/lib/charts/BarChart.astro +3 -3
  31. package/src/components/lib/charts/BoxPlotChart.astro +109 -0
  32. package/src/components/lib/charts/BubbleChart.astro +101 -0
  33. package/src/components/lib/charts/BulletChart.astro +160 -0
  34. package/src/components/lib/charts/BumpChart.astro +92 -0
  35. package/src/components/lib/charts/CandlestickChart.astro +105 -0
  36. package/src/components/lib/charts/ChartFrame.astro +373 -0
  37. package/src/components/lib/charts/DivergingBarChart.astro +98 -0
  38. package/src/components/lib/charts/DonutChart.astro +2 -2
  39. package/src/components/lib/charts/DumbbellChart.astro +92 -0
  40. package/src/components/lib/charts/ForecastLineChart.astro +125 -0
  41. package/src/components/lib/charts/FunnelChart.astro +122 -0
  42. package/src/components/lib/charts/GaugeChart.astro +111 -0
  43. package/src/components/lib/charts/GoalProgressChart.astro +97 -0
  44. package/src/components/lib/charts/GroupedBarChart.astro +125 -0
  45. package/src/components/lib/charts/HeatmapChart.astro +131 -0
  46. package/src/components/lib/charts/HistogramChart.astro +111 -0
  47. package/src/components/lib/charts/HorizontalBarChart.astro +155 -0
  48. package/src/components/lib/charts/KpiStatTile.astro +116 -0
  49. package/src/components/lib/charts/KpiTrendGrid.astro +60 -0
  50. package/src/components/lib/charts/LineChart.astro +160 -0
  51. package/src/components/lib/charts/LinearProgressGauge.astro +136 -0
  52. package/src/components/lib/charts/LollipopChart.astro +100 -0
  53. package/src/components/lib/charts/MeterGauge.astro +122 -0
  54. package/src/components/lib/charts/MetricDeltaTable.astro +125 -0
  55. package/src/components/lib/charts/PieChart.astro +135 -0
  56. package/src/components/lib/charts/PolarAreaChart.astro +85 -0
  57. package/src/components/lib/charts/PopulationPyramid.astro +122 -0
  58. package/src/components/lib/charts/PunchCardChart.astro +89 -0
  59. package/src/components/lib/charts/RadarChart.astro +94 -0
  60. package/src/components/lib/charts/RadarMetricChart.astro +168 -0
  61. package/src/components/lib/charts/RadialBarChart.astro +124 -0
  62. package/src/components/lib/charts/RangeAreaChart.astro +113 -0
  63. package/src/components/lib/charts/RetentionCohortTable.astro +126 -0
  64. package/src/components/lib/charts/SankeyChart.astro +128 -0
  65. package/src/components/lib/charts/ScatterPlot.astro +139 -0
  66. package/src/components/lib/charts/SegmentedBarChart.astro +119 -0
  67. package/src/components/lib/charts/SlopeChart.astro +105 -0
  68. package/src/components/lib/charts/SparklineChart.astro +87 -0
  69. package/src/components/lib/charts/StackedAreaChart.astro +130 -0
  70. package/src/components/lib/charts/StackedBarChart.astro +136 -0
  71. package/src/components/lib/charts/SunburstChart.astro +103 -0
  72. package/src/components/lib/charts/TreemapChart.astro +94 -0
  73. package/src/components/lib/charts/WaffleChart.astro +121 -0
  74. package/src/components/lib/charts/WaterfallChart.astro +118 -0
  75. package/src/components/lib/charts/chart-tooltip.ts +75 -0
  76. package/src/components/lib/charts/chart-utils.ts +271 -0
  77. package/src/components/lib/charts/index.ts +46 -0
  78. package/src/components/lib/data/ActivityHeatmapGrid.astro +157 -0
  79. package/src/components/lib/data/MetricComparisonRow.astro +109 -0
  80. package/src/components/lib/data/StatusTimelineFeed.astro +168 -0
  81. package/src/components/lib/data/index.ts +3 -0
  82. package/src/components/lib/ecommerce/CartDrawer.astro +483 -0
  83. package/src/components/lib/ecommerce/CartPageList.astro +290 -0
  84. package/src/components/lib/ecommerce/CartToast.astro +276 -0
  85. package/src/components/lib/ecommerce/CategoryTiles.astro +143 -0
  86. package/src/components/lib/ecommerce/CheckoutForm.astro +423 -0
  87. package/src/components/lib/ecommerce/CountdownBanner.astro +230 -0
  88. package/src/components/lib/ecommerce/FilterBar.astro +278 -0
  89. package/src/components/lib/ecommerce/FilterSidebar.astro +405 -0
  90. package/src/components/lib/ecommerce/LiveActivityToast.astro +213 -0
  91. package/src/components/lib/ecommerce/OrderSummary.astro +295 -0
  92. package/src/components/lib/ecommerce/ProductBuyBox.astro +247 -0
  93. package/src/components/lib/ecommerce/ProductCardMinimal.astro +229 -0
  94. package/src/components/lib/ecommerce/ProductGallery.astro +145 -0
  95. package/src/components/lib/ecommerce/ProductGrid.astro +118 -0
  96. package/src/components/lib/ecommerce/ProductMedia.astro +113 -0
  97. package/src/components/lib/ecommerce/ProductRating.astro +78 -0
  98. package/src/components/lib/ecommerce/ProductToolbar.astro +93 -0
  99. package/src/components/lib/ecommerce/PromoBar.astro +145 -0
  100. package/src/components/lib/ecommerce/StockIndicator.astro +127 -0
  101. package/src/components/lib/ecommerce/StoreHeader.astro +446 -0
  102. package/src/components/lib/ecommerce/StoreHero.astro +260 -0
  103. package/src/components/lib/ecommerce/StoreProductCard.astro +307 -0
  104. package/src/components/lib/ecommerce/TrustBadges.astro +101 -0
  105. package/src/components/lib/ecommerce/VariantPicker.astro +145 -0
  106. package/src/components/lib/ecommerce/cart-store.ts +151 -0
  107. package/src/components/lib/ecommerce/catalog-filter.ts +62 -0
  108. package/src/components/lib/ecommerce/index.ts +34 -0
  109. package/src/components/lib/ecommerce/product-icons.ts +28 -0
  110. package/src/components/lib/ecommerce/types.ts +70 -0
  111. package/src/components/lib/feedback/ProgressRingCounter.astro +118 -0
  112. package/src/components/lib/feedback/ToastNotificationGroup.astro +173 -0
  113. package/src/components/lib/feedback/index.ts +2 -0
  114. package/src/components/lib/forms/AnimatedInput.astro +4 -2
  115. package/src/components/lib/forms/CustomRadioGroup.astro +3 -1
  116. package/src/components/lib/forms/GlassInlineToggleGroup.astro +161 -0
  117. package/src/components/lib/forms/PasswordStrengthInput.astro +242 -0
  118. package/src/components/lib/forms/PhoneCountryInput.astro +145 -0
  119. package/src/components/lib/forms/TagsAutocompleteInput.astro +249 -0
  120. package/src/components/lib/forms/index.ts +5 -0
  121. package/src/components/lib/index.ts +2 -0
  122. package/src/components/lib/layout/BentoGrid3.astro +6 -4
  123. package/src/components/lib/layout/CenterFixedBox.astro +2 -2
  124. package/src/components/lib/layout/CenteredContainer.astro +4 -2
  125. package/src/components/lib/layout/ClusterHorizontal.astro +2 -2
  126. package/src/components/lib/layout/DiagonalSectionDivider.astro +69 -0
  127. package/src/components/lib/layout/FeatureHero.astro +4 -2
  128. package/src/components/lib/layout/FooterCenteredMinimal.astro +4 -2
  129. package/src/components/lib/layout/FullBleedSection.astro +2 -2
  130. package/src/components/lib/layout/GalleryGrid4.astro +2 -2
  131. package/src/components/lib/layout/HolyGrailGrid.astro +127 -0
  132. package/src/components/lib/layout/LandingSectionSplit.astro +5 -3
  133. package/src/components/lib/layout/MasonryGrid.astro +2 -2
  134. package/src/components/lib/layout/MinimalFooterGrid.astro +1 -1
  135. package/src/components/lib/layout/ScrollSnapSection.astro +1 -1
  136. package/src/components/lib/layout/SidebarLayoutWrapper.astro +4 -2
  137. package/src/components/lib/layout/SplitScreenLayout.astro +3 -3
  138. package/src/components/lib/layout/StepLayoutVertical.astro +1 -1
  139. package/src/components/lib/layout/StickySidebarWrapper.astro +4 -2
  140. package/src/components/lib/layout/index.ts +3 -1
  141. package/src/components/lib/navigation/QuickJumpDock.astro +125 -0
  142. package/src/components/lib/navigation/StepBreadcrumbBar.astro +151 -0
  143. package/src/components/lib/navigation/SubNavbarPills.astro +102 -0
  144. package/src/components/lib/navigation/index.ts +3 -0
  145. package/src/components/lib/overlays/CookiePreferencesDrawer.astro +226 -0
  146. package/src/components/lib/overlays/FloatingFeedbackWidget.astro +203 -0
  147. package/src/components/lib/overlays/ImageCompareSlider.astro +172 -0
  148. package/src/components/lib/overlays/index.ts +3 -0
  149. package/src/components/lib/sections/AgencyContactBrief.astro +194 -0
  150. package/src/components/lib/sections/AgencyFooterCta.astro +94 -0
  151. package/src/components/lib/sections/AgencyHeader.astro +161 -0
  152. package/src/components/lib/sections/AgencyHeroKinetic.astro +172 -0
  153. package/src/components/lib/sections/AgencyServicesList.astro +113 -0
  154. package/src/components/lib/sections/AgencyTeamGrid.astro +111 -0
  155. package/src/components/lib/sections/AgencyWorkGrid.astro +147 -0
  156. package/src/components/lib/sections/BlogGridSection.astro +133 -0
  157. package/src/components/lib/sections/ButtonsShowcase.astro +20 -18
  158. package/src/components/lib/sections/CardsShowcase.astro +28 -26
  159. package/src/components/lib/sections/CareersOpenings.astro +141 -0
  160. package/src/components/lib/sections/ChangelogSection.astro +151 -0
  161. package/src/components/lib/sections/ContactGlassForm.astro +10 -8
  162. package/src/components/lib/sections/ContactSplitMap.astro +141 -0
  163. package/src/components/lib/sections/CtaAppDownload.astro +13 -11
  164. package/src/components/lib/sections/CtaGlowBanner.astro +12 -10
  165. package/src/components/lib/sections/CtaNewsletterSection.astro +165 -0
  166. package/src/components/lib/sections/CtaSplitImage.astro +149 -0
  167. package/src/components/lib/sections/DataShowcase.astro +23 -21
  168. package/src/components/lib/sections/FaqAccordionSection.astro +8 -8
  169. package/src/components/lib/sections/FaqTwoColumn.astro +121 -0
  170. package/src/components/lib/sections/FeatureAlternatingRows.astro +192 -0
  171. package/src/components/lib/sections/FeatureBentoGrid.astro +13 -11
  172. package/src/components/lib/sections/FeatureIconGrid.astro +155 -0
  173. package/src/components/lib/sections/FeatureTabsShowcase.astro +182 -0
  174. package/src/components/lib/sections/FeatureTimelineFlow.astro +8 -6
  175. package/src/components/lib/sections/FeedbackShowcase.astro +15 -13
  176. package/src/components/lib/sections/FooterMegaSection.astro +157 -0
  177. package/src/components/lib/sections/FormsShowcase.astro +22 -20
  178. package/src/components/lib/sections/HeroDashboardPreview.astro +182 -0
  179. package/src/components/lib/sections/HeroGlass.astro +22 -20
  180. package/src/components/lib/sections/HeroGradient.astro +15 -13
  181. package/src/components/lib/sections/HeroMinimalCentered.astro +175 -0
  182. package/src/components/lib/sections/HeroShowcaseSplit.astro +306 -0
  183. package/src/components/lib/sections/HeroSplit.astro +13 -11
  184. package/src/components/lib/sections/HeroTerminal.astro +253 -0
  185. package/src/components/lib/sections/HeroWaitlist.astro +231 -0
  186. package/src/components/lib/sections/HowItWorksSteps.astro +180 -0
  187. package/src/components/lib/sections/IntegrationsGrid.astro +167 -0
  188. package/src/components/lib/sections/LayoutShowcase.astro +21 -19
  189. package/src/components/lib/sections/LogoCloudSection.astro +96 -0
  190. package/src/components/lib/sections/LogoWallGrid.astro +93 -0
  191. package/src/components/lib/sections/NavigationShowcase.astro +15 -13
  192. package/src/components/lib/sections/OverlaysShowcase.astro +21 -19
  193. package/src/components/lib/sections/PricingComparisonMatrix.astro +15 -13
  194. package/src/components/lib/sections/PricingSinglePlan.astro +159 -0
  195. package/src/components/lib/sections/PricingTierCards.astro +11 -9
  196. package/src/components/lib/sections/PricingToggleCards.astro +171 -0
  197. package/src/components/lib/sections/ShopCategoryHero.astro +103 -0
  198. package/src/components/lib/sections/ShopCollectionMosaic.astro +131 -0
  199. package/src/components/lib/sections/ShopFooterWordmark.astro +100 -0
  200. package/src/components/lib/sections/ShopHeaderEditorial.astro +396 -0
  201. package/src/components/lib/sections/ShopHeroEditorial.astro +151 -0
  202. package/src/components/lib/sections/ShopLookbook.astro +250 -0
  203. package/src/components/lib/sections/ShopNewsletterEditorial.astro +128 -0
  204. package/src/components/lib/sections/ShopProductRail.astro +150 -0
  205. package/src/components/lib/sections/ShopReviewsEditorial.astro +133 -0
  206. package/src/components/lib/sections/ShopValuesMarquee.astro +91 -0
  207. package/src/components/lib/sections/StatsCounterBand.astro +124 -0
  208. package/src/components/lib/sections/StatsDashboardSection.astro +85 -0
  209. package/src/components/lib/sections/StatsMetricShowcase.astro +9 -7
  210. package/src/components/lib/sections/TeamGridSection.astro +12 -10
  211. package/src/components/lib/sections/TestimonialCarousel.astro +167 -0
  212. package/src/components/lib/sections/TestimonialFeatured.astro +122 -0
  213. package/src/components/lib/sections/TestimonialGridSection.astro +188 -0
  214. package/src/components/lib/sections/TestimonialWallGlass.astro +11 -9
  215. package/src/components/lib/sections/TypographyShowcase.astro +10 -8
  216. package/src/components/lib/sections/index.ts +39 -0
  217. package/src/components/lib/templates/ecommerce/StoreCategoryPage.astro +160 -0
  218. package/src/components/lib/templates/ecommerce/StoreCheckoutPage.astro +98 -0
  219. package/src/components/lib/templates/ecommerce/StoreHomePage.astro +191 -0
  220. package/src/components/lib/templates/ecommerce/StoreLayout.astro +169 -0
  221. package/src/components/lib/templates/ecommerce/StoreProductPage.astro +165 -0
  222. package/src/components/lib/templates/ecommerce/data.ts +187 -0
  223. package/src/components/lib/templates/ecommerce/index.ts +14 -0
  224. package/src/components/lib/templates/ecommerce-editorial/EditorialBagPage.astro +52 -0
  225. package/src/components/lib/templates/ecommerce-editorial/EditorialCheckoutPage.astro +123 -0
  226. package/src/components/lib/templates/ecommerce-editorial/EditorialHomePage.astro +102 -0
  227. package/src/components/lib/templates/ecommerce-editorial/EditorialLayout.astro +216 -0
  228. package/src/components/lib/templates/ecommerce-editorial/EditorialProductPage.astro +205 -0
  229. package/src/components/lib/templates/ecommerce-editorial/EditorialShopPage.astro +112 -0
  230. package/src/components/lib/templates/ecommerce-editorial/data.ts +125 -0
  231. package/src/components/lib/templates/ecommerce-editorial/index.ts +16 -0
  232. package/src/components/lib/templates/saas-hotel/AppLayout.astro +83 -0
  233. package/src/components/lib/templates/saas-hotel/DashboardPage.astro +66 -0
  234. package/src/components/lib/templates/saas-hotel/GuestsPage.astro +65 -0
  235. package/src/components/lib/templates/saas-hotel/LandingPage.astro +213 -0
  236. package/src/components/lib/templates/saas-hotel/ReportsPage.astro +63 -0
  237. package/src/components/lib/templates/saas-hotel/ReservationsPage.astro +49 -0
  238. package/src/components/lib/templates/saas-hotel/RoomsPage.astro +48 -0
  239. package/src/components/lib/templates/saas-hotel/SettingsPage.astro +115 -0
  240. package/src/components/lib/templates/saas-hotel/SignInPage.astro +50 -0
  241. package/src/components/lib/templates/saas-hotel/data.ts +229 -0
  242. package/src/components/lib/templates/saas-hotel/index.ts +19 -0
  243. package/src/components/lib/templates/saas-hotel/lobby-theme.css +90 -0
  244. package/src/components/lib/typography/AnimatedCounterText.astro +102 -0
  245. package/src/components/lib/typography/CurvedPathHeading.astro +86 -0
  246. package/src/components/lib/typography/GradientTextMarquee.astro +105 -0
  247. package/src/components/lib/typography/HackerDecodeText.astro +85 -0
  248. package/src/components/lib/typography/index.ts +4 -0
  249. package/src/styles/global.css +113 -1
@@ -8,6 +8,7 @@ interface Props {
8
8
  const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astro.props;
9
9
  ---
10
10
 
11
+ <div class="cq-overlays-showcase-cq">
11
12
  <section class="overlays-showcase">
12
13
  <div class="container">
13
14
  <div class="showcase-header">
@@ -77,8 +78,9 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
77
78
  </div>
78
79
  </div>
79
80
  </section>
80
-
81
+ </div>
81
82
  <style>
83
+ .cq-overlays-showcase-cq { container-type: inline-size; }
82
84
  .overlays-showcase {
83
85
  padding: var(--sp-16) 0;
84
86
  position: relative;
@@ -95,8 +97,8 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
95
97
  text-transform: uppercase;
96
98
  letter-spacing: 0.1em;
97
99
  color: var(--c-primary-light);
98
- background: rgba(184,134,11,0.1);
99
- border: 1px solid rgba(184,134,11,0.25);
100
+ background: color-mix(in srgb, var(--c-primary, #b8860b) 10%, transparent);
101
+ border: 1px solid color-mix(in srgb, var(--c-primary, #b8860b) 25%, transparent);
100
102
  border-radius: var(--r-full);
101
103
  margin-bottom: var(--sp-4);
102
104
  }
@@ -118,7 +120,7 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
118
120
  padding: var(--sp-12);
119
121
  background: rgba(10, 10, 10, 0.6);
120
122
  backdrop-filter: blur(20px);
121
- border: 1px solid rgba(255,255,255,0.08);
123
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
122
124
  border-radius: var(--r-xl);
123
125
  margin-bottom: var(--sp-6);
124
126
  box-shadow: 0 20px 60px rgba(0,0,0,0.4);
@@ -160,9 +162,9 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
160
162
  padding: var(--sp-6);
161
163
  background: rgba(30, 30, 30, 0.9);
162
164
  backdrop-filter: blur(16px);
163
- border: 1px solid rgba(255,255,255,0.1);
165
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
164
166
  border-radius: var(--r-lg);
165
- box-shadow: 0 24px 80px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.05);
167
+ box-shadow: 0 24px 80px rgba(0,0,0,0.5), 0 0 0 1px rgb(var(--ink-rgb, 255 255 255) / 0.05);
166
168
  transform: scale(1) translateY(0);
167
169
  }
168
170
  .overlay-card__header {
@@ -191,7 +193,7 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
191
193
  transition: all 0.2s ease;
192
194
  }
193
195
  .overlay-close:hover {
194
- background: rgba(255,255,255,0.1);
196
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.1);
195
197
  color: var(--c-text-1);
196
198
  }
197
199
  .overlay-card__body {
@@ -226,7 +228,7 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
226
228
  width: 200px;
227
229
  background: rgba(25, 25, 25, 0.95);
228
230
  backdrop-filter: blur(18px);
229
- border: 1px solid rgba(255,255,255,0.08);
231
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
230
232
  border-radius: var(--r-lg);
231
233
  box-shadow: -12px 0 40px rgba(0,0,0,0.4);
232
234
  transform: translateX(0);
@@ -278,15 +280,15 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
278
280
  font-size: 0.8rem;
279
281
  font-weight: 600;
280
282
  color: var(--c-text-2);
281
- background: rgba(255,255,255,0.04);
282
- border: 1px solid rgba(255,255,255,0.1);
283
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.04);
284
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
283
285
  border-radius: var(--r-md);
284
286
  cursor: pointer;
285
287
  transition: all 0.2s ease;
286
288
  }
287
289
  .popover-target:hover {
288
290
  color: var(--c-text-1);
289
- border-color: rgba(184,134,11,0.3);
291
+ border-color: color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent);
290
292
  }
291
293
  .popover-content {
292
294
  position: absolute;
@@ -297,7 +299,7 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
297
299
  padding: var(--sp-3) var(--sp-4);
298
300
  background: rgba(40, 40, 40, 0.95);
299
301
  backdrop-filter: blur(14px);
300
- border: 1px solid rgba(255,255,255,0.1);
302
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
301
303
  border-radius: var(--r-md);
302
304
  box-shadow: 0 12px 32px rgba(0,0,0,0.4);
303
305
  }
@@ -309,8 +311,8 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
309
311
  width: 10px;
310
312
  height: 10px;
311
313
  background: rgba(40, 40, 40, 0.95);
312
- border-right: 1px solid rgba(255,255,255,0.1);
313
- border-bottom: 1px solid rgba(255,255,255,0.1);
314
+ border-right: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
315
+ border-bottom: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
314
316
  transform: translateX(-50%) rotate(45deg);
315
317
  }
316
318
  .popover-text {
@@ -334,12 +336,12 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
334
336
  }
335
337
  .btn--primary {
336
338
  background: linear-gradient(135deg, var(--c-primary-light), var(--c-primary));
337
- color: #0a0a0a;
338
- box-shadow: 0 4px 20px rgba(184,134,11,0.3);
339
+ color: var(--c-on-primary, #0a0a0a);
340
+ box-shadow: 0 4px 20px color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent);
339
341
  }
340
342
  .btn--primary:hover {
341
343
  transform: translateY(-2px);
342
- box-shadow: 0 8px 30px rgba(184,134,11,0.4);
344
+ box-shadow: 0 8px 30px color-mix(in srgb, var(--c-primary, #b8860b) 40%, transparent);
343
345
  }
344
346
  .btn--ghost {
345
347
  background: transparent;
@@ -354,7 +356,7 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
354
356
  .usage-code {
355
357
  text-align: center;
356
358
  padding: var(--sp-4);
357
- background: rgba(255,255,255,0.02);
359
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
358
360
  border-radius: var(--r-md);
359
361
  }
360
362
  .usage-code code {
@@ -363,7 +365,7 @@ const { title = "Overlays", subtitle = "Modals, drawers, and popovers." } = Astr
363
365
  color: var(--c-primary-light);
364
366
  }
365
367
 
366
- @media (max-width: 640px) {
368
+ @container (max-width: 640px) {
367
369
  .preview-stage { padding: var(--sp-8) var(--sp-4); }
368
370
  .overlay-card { width: 240px; padding: var(--sp-4); }
369
371
  .drawer-panel { width: 160px; right: var(--sp-2); }
@@ -21,6 +21,7 @@ const {
21
21
  } = Astro.props;
22
22
  ---
23
23
 
24
+ <div class="cq-pricing-comparison-matrix-cq">
24
25
  <section class={`pricing-section ${className}`} aria-labelledby="pricing-title">
25
26
  <div class="pricing-bg" aria-hidden="true">
26
27
  <div class="pricing-glow"></div>
@@ -129,7 +130,7 @@ const {
129
130
  </div>
130
131
  </div>
131
132
  </section>
132
-
133
+ </div>
133
134
  <script>
134
135
  const toggleBtn = document.getElementById('billingToggleBtn');
135
136
  const priceVals = document.querySelectorAll('.price-val');
@@ -149,6 +150,7 @@ const {
149
150
  </script>
150
151
 
151
152
  <style>
153
+ .cq-pricing-comparison-matrix-cq { container-type: inline-size; }
152
154
  .pricing-section {
153
155
  position: relative;
154
156
  padding: var(--sp-20, 5rem) var(--sp-6, 1.5rem);
@@ -170,7 +172,7 @@ const {
170
172
  transform: translateX(-50%);
171
173
  width: 600px;
172
174
  height: 500px;
173
- background: radial-gradient(circle, rgba(184, 134, 11, 0.12), transparent 70%);
175
+ background: radial-gradient(circle, color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent), transparent 70%);
174
176
  filter: blur(100px);
175
177
  }
176
178
 
@@ -195,7 +197,7 @@ const {
195
197
  font-weight: 700;
196
198
  letter-spacing: 0.06em;
197
199
  text-transform: uppercase;
198
- background: rgba(184, 134, 11, 0.12);
200
+ background: color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent);
199
201
  color: #eab308;
200
202
  border: 1px solid rgba(234, 179, 8, 0.25);
201
203
  margin-bottom: var(--sp-4, 1rem);
@@ -224,7 +226,7 @@ const {
224
226
  gap: 0.75rem;
225
227
  padding: 0.4rem 0.8rem;
226
228
  background: rgba(15, 23, 42, 0.8);
227
- border: 1px solid rgba(255, 255, 255, 0.1);
229
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
228
230
  border-radius: 9999px;
229
231
  }
230
232
 
@@ -248,7 +250,7 @@ const {
248
250
  width: 44px;
249
251
  height: 24px;
250
252
  border-radius: 9999px;
251
- background: rgba(255, 255, 255, 0.15);
253
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.15);
252
254
  border: none;
253
255
  position: relative;
254
256
  cursor: pointer;
@@ -286,7 +288,7 @@ const {
286
288
  background: rgba(15, 23, 42, 0.6);
287
289
  backdrop-filter: blur(20px);
288
290
  -webkit-backdrop-filter: blur(20px);
289
- border: 1px solid rgba(255, 255, 255, 0.08);
291
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
290
292
  border-radius: var(--r-xl, 20px);
291
293
  padding: 2.25rem 2rem;
292
294
  display: flex;
@@ -297,7 +299,7 @@ const {
297
299
 
298
300
  .plan-card:hover {
299
301
  transform: translateY(-4px);
300
- border-color: rgba(255, 255, 255, 0.18);
302
+ border-color: rgb(var(--ink-rgb, 255 255 255) / 0.18);
301
303
  }
302
304
 
303
305
  .plan-card--popular {
@@ -393,19 +395,19 @@ const {
393
395
  }
394
396
 
395
397
  .plan-btn--ghost {
396
- background: rgba(255, 255, 255, 0.05);
398
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.05);
397
399
  color: #fff;
398
- border: 1px solid rgba(255, 255, 255, 0.12);
400
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.12);
399
401
  }
400
402
 
401
403
  .plan-btn--ghost:hover {
402
- background: rgba(255, 255, 255, 0.1);
403
- border-color: rgba(255, 255, 255, 0.25);
404
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.1);
405
+ border-color: rgb(var(--ink-rgb, 255 255 255) / 0.25);
404
406
  }
405
407
 
406
408
  .plan-divider {
407
409
  height: 1px;
408
- background: rgba(255, 255, 255, 0.08);
410
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.08);
409
411
  margin: 1.5rem 0;
410
412
  }
411
413
 
@@ -454,7 +456,7 @@ const {
454
456
  color: #10b981;
455
457
  }
456
458
 
457
- @media (max-width: 960px) {
459
+ @container (max-width: 960px) {
458
460
  .pricing-cards {
459
461
  grid-template-columns: 1fr;
460
462
  }
@@ -0,0 +1,159 @@
1
+ ---
2
+ /**
3
+ * PricingSinglePlan — One-plan pricing section: price card on one side,
4
+ * full feature checklist on the other, with a money-back guarantee note.
5
+ *
6
+ * @param {string} title - Section heading.
7
+ * @param {string} subtitle - Section description.
8
+ * @param {string} planName - Plan name.
9
+ * @param {string} price - Formatted price.
10
+ * @param {string} period - Billing period label.
11
+ * @param {string} originalPrice - Optional struck-through price.
12
+ * @param {string[]} features - Included features.
13
+ * @param {{label: string, href: string}} cta - CTA button.
14
+ * @param {string} guarantee - Reassurance note under the CTA.
15
+ * @param {string} variant - Card style (glow|glass|minimal).
16
+ * @param {string} size - Vertical rhythm (sm|md|lg).
17
+ * @param {string} className - Extra CSS class.
18
+ */
19
+ interface Props {
20
+ title?: string;
21
+ subtitle?: string;
22
+ planName?: string;
23
+ price?: string;
24
+ period?: string;
25
+ originalPrice?: string;
26
+ features?: string[];
27
+ cta?: { label: string; href: string };
28
+ guarantee?: string;
29
+ variant?: 'glow' | 'glass' | 'minimal';
30
+ size?: 'sm' | 'md' | 'lg';
31
+ className?: string;
32
+ }
33
+
34
+ const {
35
+ title = 'One price. Everything included.',
36
+ subtitle = 'Lifetime access to every component, section and future update.',
37
+ planName = 'Lifetime license',
38
+ price = '$149',
39
+ period = 'one-time payment',
40
+ originalPrice = '$249',
41
+ features = [
42
+ '250+ components & sections',
43
+ '45 dependency-free SVG charts',
44
+ 'Lifetime updates',
45
+ 'Unlimited projects',
46
+ 'Commercial license',
47
+ 'Figma design kit',
48
+ 'Private community',
49
+ 'Priority email support',
50
+ ],
51
+ cta = { label: 'Get lifetime access', href: '#' },
52
+ guarantee = '30-day money-back guarantee. No questions asked.',
53
+ variant = 'glow',
54
+ size = 'md',
55
+ className = '',
56
+ } = Astro.props;
57
+
58
+ const id = `psp-${Math.random().toString(36).slice(2, 8)}`;
59
+ ---
60
+
61
+ <div class="cq-pricing-single-plan-cq">
62
+ <section class={`psp psp--${variant} psp--${size} ${className}`} aria-labelledby={id}>
63
+ <div class="psp__inner">
64
+ <header class="psp__head">
65
+ <h2 id={id} class="psp__title">{title}</h2>
66
+ <p class="psp__subtitle">{subtitle}</p>
67
+ </header>
68
+ <div class="psp__card">
69
+ <div class="psp__price-col">
70
+ <p class="psp__plan">{planName}</p>
71
+ <p class="psp__price">
72
+ {originalPrice && <s class="psp__orig"><span class="psp__sr">Was </span>{originalPrice}</s>}
73
+ <span class="psp__amount"><span class="psp__sr">Now </span>{price}</span>
74
+ </p>
75
+ <p class="psp__period">{period}</p>
76
+ <a class="psp__cta" href={cta.href}>{cta.label}</a>
77
+ <p class="psp__guarantee">
78
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" /><path d="m9 12 2 2 4-4" /></svg>
79
+ {guarantee}
80
+ </p>
81
+ </div>
82
+ <div class="psp__features-col">
83
+ <h3 class="psp__features-title">What’s included</h3>
84
+ <ul class="psp__features">
85
+ {features.map((f) => (
86
+ <li><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>{f}</li>
87
+ ))}
88
+ </ul>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </section>
93
+ </div>
94
+ <style>
95
+ .cq-pricing-single-plan-cq { container-type: inline-size; }
96
+ .psp {
97
+ --psp-py: 5.5rem;
98
+ padding: var(--psp-py) var(--sp-6, 1.5rem);
99
+ background: var(--c-bg, #050505);
100
+ }
101
+ .psp--sm { --psp-py: 3.5rem; }
102
+ .psp--lg { --psp-py: 7.5rem; }
103
+ .psp__inner { max-width: 960px; margin: 0 auto; }
104
+ .psp__head { text-align: center; margin-bottom: 3rem; }
105
+ .psp__title { margin: 0 0 0.75rem; font-size: clamp(1.9rem, 4vw, 2.75rem); font-weight: 800; letter-spacing: -0.03em; color: var(--c-text-1, #fff); }
106
+ .psp__subtitle { margin: 0; font-size: 1.0625rem; color: var(--c-text-2, #a3a3a3); }
107
+ .psp__card {
108
+ position: relative;
109
+ display: grid;
110
+ grid-template-columns: 1fr 1.3fr;
111
+ border-radius: var(--r-xl, 28px);
112
+ overflow: hidden;
113
+ border: 1px solid var(--c-border, rgb(var(--ink-rgb, 255 255 255) / 0.08));
114
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
115
+ }
116
+ .psp--glow .psp__card { border-color: color-mix(in srgb, var(--c-primary-light, #d4a017) 35%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--c-primary-light, #d4a017) 8%, transparent), 0 40px 100px -40px color-mix(in srgb, var(--c-primary-light, #d4a017) 40%, transparent); }
117
+ .psp--glass .psp__card { backdrop-filter: blur(16px); background: linear-gradient(160deg, rgb(var(--ink-rgb, 255 255 255) / 0.06), rgb(var(--ink-rgb, 255 255 255) / 0.015)); }
118
+ .psp--minimal .psp__card { background: transparent; }
119
+ .psp__price-col {
120
+ display: flex;
121
+ flex-direction: column;
122
+ justify-content: center;
123
+ padding: clamp(2rem, 5vw, 3rem);
124
+ background: radial-gradient(circle at 30% 0%, var(--c-primary-glow, color-mix(in srgb, var(--c-primary, #b8860b) 18%, transparent)), transparent 70%), rgb(var(--ink-rgb, 255 255 255) / 0.02);
125
+ border-right: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06);
126
+ }
127
+ .psp__plan { margin: 0 0 1rem; font-size: 0.875rem; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase; color: var(--c-primary-light, #d4a017); }
128
+ .psp__price { display: flex; align-items: baseline; gap: 0.75rem; margin: 0; }
129
+ .psp__orig { font-size: 1.25rem; color: var(--c-text-3, #8a8a8a); }
130
+ .psp__amount { font-size: clamp(3rem, 7vw, 4rem); font-weight: 800; letter-spacing: -0.04em; color: var(--c-text-1, #fff); line-height: 1; }
131
+ .psp__period { margin: 0.5rem 0 2rem; font-size: 0.9rem; color: var(--c-text-2, #a3a3a3); }
132
+ .psp__cta {
133
+ display: inline-flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ min-height: 52px;
137
+ border-radius: var(--r-md, 12px);
138
+ background: var(--c-primary-light, #d4a017);
139
+ color: var(--c-on-primary, #0a0a0a);
140
+ font-weight: 700;
141
+ text-decoration: none;
142
+ transition: background 0.2s ease, transform 0.2s ease;
143
+ }
144
+ .psp__cta:hover { background: var(--c-accent, #fef3c7); color: var(--c-on-primary, #0a0a0a); transform: translateY(-1px); }
145
+ .psp__cta:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 3px; }
146
+ .psp__guarantee { display: flex; align-items: flex-start; gap: 0.5rem; margin: 1.25rem 0 0; font-size: 0.8125rem; line-height: 1.5; color: var(--c-text-2, #a3a3a3); }
147
+ .psp__guarantee svg { color: var(--chart-pos, #34c38f); flex-shrink: 0; margin-top: 1px; }
148
+ .psp__features-col { padding: clamp(2rem, 5vw, 3rem); }
149
+ .psp__features-title { margin: 0 0 1.5rem; font-size: 1rem; font-weight: 650; color: var(--c-text-1, #fff); }
150
+ .psp__features { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.5rem; }
151
+ .psp__features li { display: flex; align-items: flex-start; gap: 0.6rem; font-size: 0.9375rem; line-height: 1.4; color: var(--c-text-1, #fff); }
152
+ .psp__features svg { color: var(--c-primary-light, #d4a017); flex-shrink: 0; }
153
+ .psp__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
154
+ @container (max-width: 760px) {
155
+ .psp__card { grid-template-columns: 1fr; }
156
+ .psp__price-col { border-right: 0; border-bottom: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06); }
157
+ .psp__features { grid-template-columns: 1fr; }
158
+ }
159
+ </style>
@@ -21,6 +21,7 @@ const {
21
21
  } = Astro.props;
22
22
  ---
23
23
 
24
+ <div class="cq-pricing-tier-cards-cq">
24
25
  <section class={`tier-pricing-section ${className}`} aria-labelledby="tier-pricing-title">
25
26
  <div class="container">
26
27
  <div class="section-header">
@@ -79,8 +80,9 @@ const {
79
80
  </div>
80
81
  </div>
81
82
  </section>
82
-
83
+ </div>
83
84
  <style>
85
+ .cq-pricing-tier-cards-cq { container-type: inline-size; }
84
86
  .tier-pricing-section {
85
87
  padding: var(--sp-20, 5rem) var(--sp-6, 1.5rem);
86
88
  background: var(--c-bg-primary, #030712);
@@ -105,7 +107,7 @@ const {
105
107
  font-weight: 700;
106
108
  letter-spacing: 0.06em;
107
109
  text-transform: uppercase;
108
- background: rgba(184, 134, 11, 0.12);
110
+ background: color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent);
109
111
  color: #eab308;
110
112
  border: 1px solid rgba(234, 179, 8, 0.25);
111
113
  margin-bottom: var(--sp-4, 1rem);
@@ -136,7 +138,7 @@ const {
136
138
 
137
139
  .tier-card {
138
140
  background: rgba(15, 23, 42, 0.55);
139
- border: 1px solid rgba(255, 255, 255, 0.08);
141
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
140
142
  border-radius: 20px;
141
143
  padding: 2.5rem 2rem;
142
144
  display: flex;
@@ -146,7 +148,7 @@ const {
146
148
 
147
149
  .tier-card:hover {
148
150
  transform: translateY(-4px);
149
- border-color: rgba(255, 255, 255, 0.2);
151
+ border-color: rgb(var(--ink-rgb, 255 255 255) / 0.2);
150
152
  }
151
153
 
152
154
  .tier-card--highlight {
@@ -163,7 +165,7 @@ const {
163
165
  font-size: 0.72rem;
164
166
  font-weight: 700;
165
167
  text-transform: uppercase;
166
- background: rgba(255, 255, 255, 0.08);
168
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.08);
167
169
  color: #cbd5e1;
168
170
  margin-bottom: 1rem;
169
171
  }
@@ -225,13 +227,13 @@ const {
225
227
  }
226
228
 
227
229
  .tier-btn--ghost {
228
- background: rgba(255, 255, 255, 0.05);
229
- border: 1px solid rgba(255, 255, 255, 0.12);
230
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.05);
231
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.12);
230
232
  color: #fff;
231
233
  }
232
234
 
233
235
  .tier-btn--ghost:hover {
234
- background: rgba(255, 255, 255, 0.12);
236
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.12);
235
237
  }
236
238
 
237
239
  .tier-list {
@@ -248,7 +250,7 @@ const {
248
250
  color: #cbd5e1;
249
251
  }
250
252
 
251
- @media (max-width: 960px) {
253
+ @container (max-width: 960px) {
252
254
  .tier-grid {
253
255
  grid-template-columns: 1fr;
254
256
  }
@@ -0,0 +1,171 @@
1
+ ---
2
+ /**
3
+ * PricingToggleCards — Three pricing tiers with an accessible monthly/yearly
4
+ * switch (role="switch"), savings badge and a highlighted recommended plan.
5
+ *
6
+ * @param {string} title - Section heading.
7
+ * @param {string} subtitle - Section description.
8
+ * @param {Array<{name: string, monthly: number, yearly: number, description: string, features: string[], cta: string, href: string, featured?: boolean}>} plans - Tiers.
9
+ * @param {string} currency - Currency symbol.
10
+ * @param {string} savingsLabel - Badge next to the yearly option.
11
+ * @param {string} variant - Card style (glass|solid|outline).
12
+ * @param {string} size - Vertical rhythm (sm|md|lg).
13
+ * @param {string} className - Extra CSS class.
14
+ */
15
+ interface Plan { name: string; monthly: number; yearly: number; description: string; features: string[]; cta: string; href: string; featured?: boolean }
16
+ interface Props {
17
+ title?: string;
18
+ subtitle?: string;
19
+ plans?: Plan[];
20
+ currency?: string;
21
+ savingsLabel?: string;
22
+ variant?: 'glass' | 'solid' | 'outline';
23
+ size?: 'sm' | 'md' | 'lg';
24
+ className?: string;
25
+ }
26
+
27
+ const {
28
+ title = 'Simple pricing that scales with you',
29
+ subtitle = 'Start free. Upgrade when your team grows. Cancel anytime.',
30
+ plans = [
31
+ { name: 'Starter', monthly: 0, yearly: 0, description: 'For side projects and prototypes.', features: ['All components', 'Community support', '1 project'], cta: 'Get started', href: '#' },
32
+ { name: 'Pro', monthly: 24, yearly: 19, description: 'For professionals shipping client work.', features: ['Everything in Starter', 'Premium sections', 'Unlimited projects', 'Priority support'], cta: 'Start 14-day trial', href: '#', featured: true },
33
+ { name: 'Team', monthly: 79, yearly: 63, description: 'For agencies and product teams.', features: ['Everything in Pro', '10 seats included', 'Figma kit', 'Private Discord'], cta: 'Contact sales', href: '#' },
34
+ ],
35
+ currency = '$',
36
+ savingsLabel = 'Save 20%',
37
+ variant = 'glass',
38
+ size = 'md',
39
+ className = '',
40
+ } = Astro.props;
41
+
42
+ const id = `ptc-${Math.random().toString(36).slice(2, 8)}`;
43
+ ---
44
+
45
+ <section class={`ptc ptc--${variant} ptc--${size} ${className}`} aria-labelledby={id} data-ptc data-period="monthly">
46
+ <div class="ptc__inner">
47
+ <header class="ptc__head">
48
+ <h2 id={id} class="ptc__title">{title}</h2>
49
+ <p class="ptc__subtitle">{subtitle}</p>
50
+ <div class="ptc__toggle">
51
+ <span class="ptc__period" id={`${id}-m`}>Monthly</span>
52
+ <button type="button" class="ptc__switch" role="switch" aria-checked="false" aria-labelledby={`${id}-y`}>
53
+ <span class="ptc__knob" aria-hidden="true"></span>
54
+ </button>
55
+ <span class="ptc__period" id={`${id}-y`}>Yearly <span class="ptc__save">{savingsLabel}</span></span>
56
+ </div>
57
+ </header>
58
+
59
+ <ul class="ptc__grid">
60
+ {plans.map((p) => (
61
+ <li class={`ptc__card ${p.featured ? 'ptc__card--featured' : ''}`}>
62
+ {p.featured && <span class="ptc__ribbon">Most popular</span>}
63
+ <h3 class="ptc__name">{p.name}</h3>
64
+ <p class="ptc__desc">{p.description}</p>
65
+ <p class="ptc__price">
66
+ <span class="ptc__amount" data-monthly={`${currency}${p.monthly}`} data-yearly={`${currency}${p.yearly}`}>{currency}{p.monthly}</span>
67
+ <span class="ptc__per">/ month<span class="ptc__billed" data-yearly-only>, billed yearly</span></span>
68
+ </p>
69
+ <a class="ptc__cta" href={p.href}>{p.cta}</a>
70
+ <ul class="ptc__features">
71
+ {p.features.map((f) => (
72
+ <li><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>{f}</li>
73
+ ))}
74
+ </ul>
75
+ </li>
76
+ ))}
77
+ </ul>
78
+ <p class="ptc__live" role="status" aria-live="polite"></p>
79
+ </div>
80
+ </section>
81
+
82
+ <script>
83
+ document.querySelectorAll<HTMLElement>('[data-ptc]').forEach((root) => {
84
+ const sw = root.querySelector<HTMLButtonElement>('.ptc__switch');
85
+ const live = root.querySelector('.ptc__live');
86
+ sw?.addEventListener('click', () => {
87
+ const yearly = sw.getAttribute('aria-checked') !== 'true';
88
+ sw.setAttribute('aria-checked', String(yearly));
89
+ root.dataset.period = yearly ? 'yearly' : 'monthly';
90
+ root.querySelectorAll<HTMLElement>('.ptc__amount').forEach((el) => {
91
+ el.textContent = (yearly ? el.dataset.yearly : el.dataset.monthly) || '';
92
+ });
93
+ if (live) live.textContent = yearly ? 'Showing yearly prices' : 'Showing monthly prices';
94
+ });
95
+ });
96
+ </script>
97
+
98
+ <style>
99
+ .ptc {
100
+ --ptc-py: 5.5rem;
101
+ padding: var(--ptc-py) var(--sp-6, 1.5rem);
102
+ background: radial-gradient(ellipse 60% 40% at 50% 0%, var(--c-primary-glow, color-mix(in srgb, var(--c-primary, #b8860b) 10%, transparent)), transparent 70%), var(--c-bg, #050505);
103
+ }
104
+ .ptc--sm { --ptc-py: 3.5rem; }
105
+ .ptc--lg { --ptc-py: 7.5rem; }
106
+ .ptc__inner { max-width: 1120px; margin: 0 auto; }
107
+ .ptc__head { text-align: center; margin-bottom: 3rem; }
108
+ .ptc__title { margin: 0 0 0.75rem; font-size: clamp(1.9rem, 4vw, 2.75rem); font-weight: 800; letter-spacing: -0.03em; color: var(--c-text-1, #fff); }
109
+ .ptc__subtitle { margin: 0 0 2rem; font-size: 1.0625rem; color: var(--c-text-2, #a3a3a3); }
110
+ .ptc__toggle { display: inline-flex; align-items: center; gap: 0.85rem; font-size: 0.9375rem; color: var(--c-text-2, #a3a3a3); }
111
+ .ptc__switch {
112
+ position: relative;
113
+ width: 52px;
114
+ height: 30px;
115
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.15);
116
+ border-radius: 999px;
117
+ background: rgb(var(--ink-rgb, 255 255 255) / 0.08);
118
+ cursor: pointer;
119
+ transition: background 0.25s ease;
120
+ }
121
+ .ptc__switch::after { content: ''; position: absolute; inset: -8px; }
122
+ .ptc__switch[aria-checked='true'] { background: var(--c-primary, #b8860b); border-color: transparent; }
123
+ .ptc__switch:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 3px; }
124
+ .ptc__knob { position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #fff; transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1); }
125
+ .ptc__switch[aria-checked='true'] .ptc__knob { transform: translateX(22px); }
126
+ [data-period='monthly'] .ptc__period:first-child,
127
+ [data-period='yearly'] .ptc__period:last-child { color: var(--c-text-1, #fff); }
128
+ .ptc__save { margin-left: 0.35rem; padding: 0.15rem 0.5rem; border-radius: 999px; background: rgba(52, 195, 143, 0.15); color: #7ee2b8; font-size: 0.75rem; font-weight: 650; }
129
+
130
+ .ptc__grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.25rem; align-items: stretch; }
131
+ .ptc__card {
132
+ position: relative;
133
+ display: flex;
134
+ flex-direction: column;
135
+ padding: 2rem;
136
+ border-radius: var(--r-xl, 24px);
137
+ }
138
+ .ptc--glass .ptc__card { background: linear-gradient(160deg, rgb(var(--ink-rgb, 255 255 255) / 0.05), rgb(var(--ink-rgb, 255 255 255) / 0.015)); border: 1px solid var(--c-border, rgb(var(--ink-rgb, 255 255 255) / 0.07)); backdrop-filter: blur(12px); }
139
+ .ptc--solid .ptc__card { background: var(--c-bg-2, #111); border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06); }
140
+ .ptc--outline .ptc__card { border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.12); }
141
+ .ptc__card--featured { border-color: color-mix(in srgb, var(--c-primary-light, #d4a017) 55%, transparent) !important; box-shadow: 0 30px 80px -30px color-mix(in srgb, var(--c-primary-light, #d4a017) 35%, transparent); }
142
+ .ptc__ribbon { position: absolute; top: -12px; left: 2rem; padding: 0.25rem 0.75rem; border-radius: 999px; background: var(--c-primary-light, #d4a017); color: var(--c-on-primary, #0a0a0a); font-size: 0.75rem; font-weight: 700; }
143
+ .ptc__name { margin: 0 0 0.35rem; font-size: 1.125rem; font-weight: 650; color: var(--c-text-1, #fff); }
144
+ .ptc__desc { margin: 0 0 1.5rem; font-size: 0.9rem; color: var(--c-text-2, #a3a3a3); }
145
+ .ptc__price { display: flex; align-items: baseline; gap: 0.4rem; margin: 0 0 1.5rem; }
146
+ .ptc__amount { font-size: 3rem; font-weight: 800; letter-spacing: -0.04em; color: var(--c-text-1, #fff); font-variant-numeric: tabular-nums; line-height: 1; }
147
+ .ptc__per { font-size: 0.875rem; color: var(--c-text-3, #8a8a8a); }
148
+ .ptc__billed { display: none; }
149
+ [data-period='yearly'] .ptc__billed { display: inline; }
150
+ .ptc__cta {
151
+ display: inline-flex;
152
+ align-items: center;
153
+ justify-content: center;
154
+ min-height: 48px;
155
+ border-radius: var(--r-md, 12px);
156
+ border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.14);
157
+ color: var(--c-text-1, #fff);
158
+ font-weight: 650;
159
+ text-decoration: none;
160
+ transition: background 0.2s ease, border-color 0.2s ease;
161
+ }
162
+ .ptc__cta:hover { border-color: rgb(var(--ink-rgb, 255 255 255) / 0.3); color: var(--c-text-1, #fff); }
163
+ .ptc__card--featured .ptc__cta { background: var(--c-primary-light, #d4a017); color: var(--c-on-primary, #0a0a0a); border-color: transparent; }
164
+ .ptc__card--featured .ptc__cta:hover { background: var(--c-accent, #fef3c7); color: var(--c-on-primary, #0a0a0a); }
165
+ .ptc__cta:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 3px; }
166
+ .ptc__features { list-style: none; margin: 1.75rem 0 0; padding: 1.5rem 0 0; border-top: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.07); display: grid; gap: 0.7rem; }
167
+ .ptc__features li { display: flex; align-items: center; gap: 0.6rem; font-size: 0.9rem; color: var(--c-text-1, #fff); }
168
+ .ptc__features svg { color: var(--c-primary-light, #d4a017); flex-shrink: 0; }
169
+ .ptc__live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
170
+ @media (prefers-reduced-motion: reduce) { .ptc__knob, .ptc__switch { transition: none; } }
171
+ </style>