designmd-forge 1.2.0

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 (907) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/__tests__/designStore.test.js +41 -0
  4. package/dist/__tests__/linter.test.js +23 -0
  5. package/dist/__tests__/sectionParser.test.js +60 -0
  6. package/dist/__tests__/server.test.js +129 -0
  7. package/dist/constants.js +12 -0
  8. package/dist/data/authoring-guide.md +113 -0
  9. package/dist/data/designs/airbnb.md +545 -0
  10. package/dist/data/designs/airtable.md +554 -0
  11. package/dist/data/designs/apple.md +562 -0
  12. package/dist/data/designs/binance.md +634 -0
  13. package/dist/data/designs/bmw-m.md +503 -0
  14. package/dist/data/designs/bmw.md +544 -0
  15. package/dist/data/designs/bugatti.md +454 -0
  16. package/dist/data/designs/cal.md +542 -0
  17. package/dist/data/designs/card-heavy.md +250 -0
  18. package/dist/data/designs/claude.md +589 -0
  19. package/dist/data/designs/clay.md +541 -0
  20. package/dist/data/designs/clickhouse.md +544 -0
  21. package/dist/data/designs/cohere.md +451 -0
  22. package/dist/data/designs/coinbase.md +570 -0
  23. package/dist/data/designs/composio.md +506 -0
  24. package/dist/data/designs/content-first.md +236 -0
  25. package/dist/data/designs/cursor.md +537 -0
  26. package/dist/data/designs/data-dashboard.md +300 -0
  27. package/dist/data/designs/dell-1996.md +632 -0
  28. package/dist/data/designs/elevenlabs.md +504 -0
  29. package/dist/data/designs/enterprise-neutral.md +252 -0
  30. package/dist/data/designs/expo.md +526 -0
  31. package/dist/data/designs/ferrari.md +531 -0
  32. package/dist/data/designs/figma.md +578 -0
  33. package/dist/data/designs/framer.md +544 -0
  34. package/dist/data/designs/hashicorp.md +575 -0
  35. package/dist/data/designs/hp.md +670 -0
  36. package/dist/data/designs/ibm.md +550 -0
  37. package/dist/data/designs/intercom.md +546 -0
  38. package/dist/data/designs/ios-acorns-android.md +430 -0
  39. package/dist/data/designs/ios-acorns-expo.md +381 -0
  40. package/dist/data/designs/ios-acorns-swiftui.md +378 -0
  41. package/dist/data/designs/ios-acorns.md +384 -0
  42. package/dist/data/designs/ios-airbnb-android.md +658 -0
  43. package/dist/data/designs/ios-airbnb-expo.md +457 -0
  44. package/dist/data/designs/ios-airbnb-swiftui.md +464 -0
  45. package/dist/data/designs/ios-airbnb.md +410 -0
  46. package/dist/data/designs/ios-alltrails-android.md +451 -0
  47. package/dist/data/designs/ios-alltrails-expo.md +400 -0
  48. package/dist/data/designs/ios-alltrails-swiftui.md +343 -0
  49. package/dist/data/designs/ios-alltrails.md +344 -0
  50. package/dist/data/designs/ios-amazon-android.md +686 -0
  51. package/dist/data/designs/ios-amazon-expo.md +433 -0
  52. package/dist/data/designs/ios-amazon-music-android.md +416 -0
  53. package/dist/data/designs/ios-amazon-music-expo.md +368 -0
  54. package/dist/data/designs/ios-amazon-music-swiftui.md +436 -0
  55. package/dist/data/designs/ios-amazon-music.md +389 -0
  56. package/dist/data/designs/ios-amazon-swiftui.md +460 -0
  57. package/dist/data/designs/ios-amazon.md +440 -0
  58. package/dist/data/designs/ios-apple-fitness-android.md +462 -0
  59. package/dist/data/designs/ios-apple-fitness-expo.md +373 -0
  60. package/dist/data/designs/ios-apple-fitness-swiftui.md +373 -0
  61. package/dist/data/designs/ios-apple-fitness.md +399 -0
  62. package/dist/data/designs/ios-apple-maps-android.md +646 -0
  63. package/dist/data/designs/ios-apple-maps-expo.md +557 -0
  64. package/dist/data/designs/ios-apple-maps-swiftui.md +588 -0
  65. package/dist/data/designs/ios-apple-maps.md +447 -0
  66. package/dist/data/designs/ios-apple-music-android.md +737 -0
  67. package/dist/data/designs/ios-apple-music-expo.md +596 -0
  68. package/dist/data/designs/ios-apple-music-swiftui.md +578 -0
  69. package/dist/data/designs/ios-apple-music.md +494 -0
  70. package/dist/data/designs/ios-apple-notes-android.md +675 -0
  71. package/dist/data/designs/ios-apple-notes-expo.md +468 -0
  72. package/dist/data/designs/ios-apple-notes-swiftui.md +489 -0
  73. package/dist/data/designs/ios-apple-notes.md +413 -0
  74. package/dist/data/designs/ios-apple-tv-android.md +405 -0
  75. package/dist/data/designs/ios-apple-tv-expo.md +341 -0
  76. package/dist/data/designs/ios-apple-tv-swiftui.md +348 -0
  77. package/dist/data/designs/ios-apple-tv.md +390 -0
  78. package/dist/data/designs/ios-apple-wallet-android.md +617 -0
  79. package/dist/data/designs/ios-apple-wallet-expo.md +487 -0
  80. package/dist/data/designs/ios-apple-wallet-swiftui.md +425 -0
  81. package/dist/data/designs/ios-apple-wallet.md +360 -0
  82. package/dist/data/designs/ios-asana-android.md +435 -0
  83. package/dist/data/designs/ios-asana-expo.md +411 -0
  84. package/dist/data/designs/ios-asana-swiftui.md +416 -0
  85. package/dist/data/designs/ios-asana.md +433 -0
  86. package/dist/data/designs/ios-audible-android.md +450 -0
  87. package/dist/data/designs/ios-audible-expo.md +328 -0
  88. package/dist/data/designs/ios-audible-swiftui.md +418 -0
  89. package/dist/data/designs/ios-audible.md +364 -0
  90. package/dist/data/designs/ios-bandcamp-android.md +471 -0
  91. package/dist/data/designs/ios-bandcamp-expo.md +378 -0
  92. package/dist/data/designs/ios-bandcamp-swiftui.md +374 -0
  93. package/dist/data/designs/ios-bandcamp.md +372 -0
  94. package/dist/data/designs/ios-bear-android.md +496 -0
  95. package/dist/data/designs/ios-bear-expo.md +449 -0
  96. package/dist/data/designs/ios-bear-swiftui.md +479 -0
  97. package/dist/data/designs/ios-bear.md +412 -0
  98. package/dist/data/designs/ios-bereal-android.md +392 -0
  99. package/dist/data/designs/ios-bereal-expo.md +299 -0
  100. package/dist/data/designs/ios-bereal-swiftui.md +319 -0
  101. package/dist/data/designs/ios-bereal.md +336 -0
  102. package/dist/data/designs/ios-binance-android.md +481 -0
  103. package/dist/data/designs/ios-binance-expo.md +404 -0
  104. package/dist/data/designs/ios-binance-swiftui.md +418 -0
  105. package/dist/data/designs/ios-binance.md +410 -0
  106. package/dist/data/designs/ios-bluesky-android.md +442 -0
  107. package/dist/data/designs/ios-bluesky-expo.md +362 -0
  108. package/dist/data/designs/ios-bluesky-swiftui.md +328 -0
  109. package/dist/data/designs/ios-bluesky.md +338 -0
  110. package/dist/data/designs/ios-booking-android.md +471 -0
  111. package/dist/data/designs/ios-booking-expo.md +364 -0
  112. package/dist/data/designs/ios-booking-swiftui.md +377 -0
  113. package/dist/data/designs/ios-booking.md +346 -0
  114. package/dist/data/designs/ios-bumble-android.md +756 -0
  115. package/dist/data/designs/ios-bumble-expo.md +629 -0
  116. package/dist/data/designs/ios-bumble-swiftui.md +546 -0
  117. package/dist/data/designs/ios-bumble.md +424 -0
  118. package/dist/data/designs/ios-cal-ai-android.md +664 -0
  119. package/dist/data/designs/ios-cal-ai-expo.md +415 -0
  120. package/dist/data/designs/ios-cal-ai-swiftui.md +486 -0
  121. package/dist/data/designs/ios-cal-ai.md +387 -0
  122. package/dist/data/designs/ios-calm-android.md +431 -0
  123. package/dist/data/designs/ios-calm-expo.md +384 -0
  124. package/dist/data/designs/ios-calm-swiftui.md +327 -0
  125. package/dist/data/designs/ios-calm.md +356 -0
  126. package/dist/data/designs/ios-canva-android.md +469 -0
  127. package/dist/data/designs/ios-canva-expo.md +374 -0
  128. package/dist/data/designs/ios-canva-swiftui.md +422 -0
  129. package/dist/data/designs/ios-canva.md +395 -0
  130. package/dist/data/designs/ios-cash-app-android.md +601 -0
  131. package/dist/data/designs/ios-cash-app-expo.md +453 -0
  132. package/dist/data/designs/ios-cash-app-swiftui.md +463 -0
  133. package/dist/data/designs/ios-cash-app.md +365 -0
  134. package/dist/data/designs/ios-character-ai-android.md +489 -0
  135. package/dist/data/designs/ios-character-ai-expo.md +420 -0
  136. package/dist/data/designs/ios-character-ai-swiftui.md +417 -0
  137. package/dist/data/designs/ios-character-ai.md +392 -0
  138. package/dist/data/designs/ios-charles-schwab-android.md +454 -0
  139. package/dist/data/designs/ios-charles-schwab-expo.md +388 -0
  140. package/dist/data/designs/ios-charles-schwab-swiftui.md +394 -0
  141. package/dist/data/designs/ios-charles-schwab.md +380 -0
  142. package/dist/data/designs/ios-chatgpt-android.md +753 -0
  143. package/dist/data/designs/ios-chatgpt-expo.md +644 -0
  144. package/dist/data/designs/ios-chatgpt-swiftui.md +653 -0
  145. package/dist/data/designs/ios-chatgpt.md +466 -0
  146. package/dist/data/designs/ios-chime-android.md +438 -0
  147. package/dist/data/designs/ios-chime-expo.md +419 -0
  148. package/dist/data/designs/ios-chime-swiftui.md +383 -0
  149. package/dist/data/designs/ios-chime.md +389 -0
  150. package/dist/data/designs/ios-chipotle-android.md +397 -0
  151. package/dist/data/designs/ios-chipotle-expo.md +301 -0
  152. package/dist/data/designs/ios-chipotle-swiftui.md +345 -0
  153. package/dist/data/designs/ios-chipotle.md +340 -0
  154. package/dist/data/designs/ios-citymapper-android.md +466 -0
  155. package/dist/data/designs/ios-citymapper-expo.md +420 -0
  156. package/dist/data/designs/ios-citymapper-swiftui.md +424 -0
  157. package/dist/data/designs/ios-citymapper.md +394 -0
  158. package/dist/data/designs/ios-claude-android.md +625 -0
  159. package/dist/data/designs/ios-claude-expo.md +671 -0
  160. package/dist/data/designs/ios-claude-swiftui.md +649 -0
  161. package/dist/data/designs/ios-claude.md +447 -0
  162. package/dist/data/designs/ios-clickup-android.md +484 -0
  163. package/dist/data/designs/ios-clickup-expo.md +423 -0
  164. package/dist/data/designs/ios-clickup-swiftui.md +416 -0
  165. package/dist/data/designs/ios-clickup.md +431 -0
  166. package/dist/data/designs/ios-clubhouse-android.md +524 -0
  167. package/dist/data/designs/ios-clubhouse-expo.md +425 -0
  168. package/dist/data/designs/ios-clubhouse-swiftui.md +447 -0
  169. package/dist/data/designs/ios-clubhouse.md +406 -0
  170. package/dist/data/designs/ios-coffee-meets-bagel-android.md +461 -0
  171. package/dist/data/designs/ios-coffee-meets-bagel-expo.md +372 -0
  172. package/dist/data/designs/ios-coffee-meets-bagel-swiftui.md +368 -0
  173. package/dist/data/designs/ios-coffee-meets-bagel.md +376 -0
  174. package/dist/data/designs/ios-coinbase-android.md +611 -0
  175. package/dist/data/designs/ios-coinbase-expo.md +500 -0
  176. package/dist/data/designs/ios-coinbase-swiftui.md +490 -0
  177. package/dist/data/designs/ios-coinbase.md +409 -0
  178. package/dist/data/designs/ios-copilot-android.md +625 -0
  179. package/dist/data/designs/ios-copilot-expo.md +423 -0
  180. package/dist/data/designs/ios-copilot-swiftui.md +471 -0
  181. package/dist/data/designs/ios-copilot.md +367 -0
  182. package/dist/data/designs/ios-craft-android.md +459 -0
  183. package/dist/data/designs/ios-craft-expo.md +417 -0
  184. package/dist/data/designs/ios-craft-swiftui.md +449 -0
  185. package/dist/data/designs/ios-craft.md +449 -0
  186. package/dist/data/designs/ios-crunchyroll-android.md +432 -0
  187. package/dist/data/designs/ios-crunchyroll-expo.md +388 -0
  188. package/dist/data/designs/ios-crunchyroll-swiftui.md +417 -0
  189. package/dist/data/designs/ios-crunchyroll.md +388 -0
  190. package/dist/data/designs/ios-crypto-com-android.md +461 -0
  191. package/dist/data/designs/ios-crypto-com-expo.md +404 -0
  192. package/dist/data/designs/ios-crypto-com-swiftui.md +419 -0
  193. package/dist/data/designs/ios-crypto-com.md +410 -0
  194. package/dist/data/designs/ios-deepseek-android.md +471 -0
  195. package/dist/data/designs/ios-deepseek-expo.md +391 -0
  196. package/dist/data/designs/ios-deepseek-swiftui.md +354 -0
  197. package/dist/data/designs/ios-deepseek.md +393 -0
  198. package/dist/data/designs/ios-deezer-android.md +475 -0
  199. package/dist/data/designs/ios-deezer-expo.md +400 -0
  200. package/dist/data/designs/ios-deezer-swiftui.md +430 -0
  201. package/dist/data/designs/ios-deezer.md +388 -0
  202. package/dist/data/designs/ios-deliveroo-android.md +493 -0
  203. package/dist/data/designs/ios-deliveroo-expo.md +424 -0
  204. package/dist/data/designs/ios-deliveroo-swiftui.md +398 -0
  205. package/dist/data/designs/ios-deliveroo.md +420 -0
  206. package/dist/data/designs/ios-delta-android.md +439 -0
  207. package/dist/data/designs/ios-delta-expo.md +381 -0
  208. package/dist/data/designs/ios-delta-swiftui.md +400 -0
  209. package/dist/data/designs/ios-delta.md +397 -0
  210. package/dist/data/designs/ios-discord-android.md +611 -0
  211. package/dist/data/designs/ios-discord-expo.md +618 -0
  212. package/dist/data/designs/ios-discord-swiftui.md +630 -0
  213. package/dist/data/designs/ios-discord.md +451 -0
  214. package/dist/data/designs/ios-disney-plus-android.md +464 -0
  215. package/dist/data/designs/ios-disney-plus-expo.md +358 -0
  216. package/dist/data/designs/ios-disney-plus-swiftui.md +412 -0
  217. package/dist/data/designs/ios-disney-plus.md +355 -0
  218. package/dist/data/designs/ios-dominos-android.md +417 -0
  219. package/dist/data/designs/ios-dominos-expo.md +316 -0
  220. package/dist/data/designs/ios-dominos-swiftui.md +340 -0
  221. package/dist/data/designs/ios-dominos.md +347 -0
  222. package/dist/data/designs/ios-doordash-android.md +527 -0
  223. package/dist/data/designs/ios-doordash-expo.md +323 -0
  224. package/dist/data/designs/ios-doordash-swiftui.md +301 -0
  225. package/dist/data/designs/ios-doordash.md +393 -0
  226. package/dist/data/designs/ios-dropbox-android.md +522 -0
  227. package/dist/data/designs/ios-dropbox-expo.md +393 -0
  228. package/dist/data/designs/ios-dropbox-swiftui.md +400 -0
  229. package/dist/data/designs/ios-dropbox.md +374 -0
  230. package/dist/data/designs/ios-duolingo-android.md +641 -0
  231. package/dist/data/designs/ios-duolingo-expo.md +597 -0
  232. package/dist/data/designs/ios-duolingo-swiftui.md +539 -0
  233. package/dist/data/designs/ios-duolingo.md +409 -0
  234. package/dist/data/designs/ios-ebay-android.md +436 -0
  235. package/dist/data/designs/ios-ebay-expo.md +344 -0
  236. package/dist/data/designs/ios-ebay-swiftui.md +308 -0
  237. package/dist/data/designs/ios-ebay.md +355 -0
  238. package/dist/data/designs/ios-espn-android.md +468 -0
  239. package/dist/data/designs/ios-espn-expo.md +387 -0
  240. package/dist/data/designs/ios-espn-swiftui.md +410 -0
  241. package/dist/data/designs/ios-espn.md +384 -0
  242. package/dist/data/designs/ios-etsy-android.md +439 -0
  243. package/dist/data/designs/ios-etsy-expo.md +351 -0
  244. package/dist/data/designs/ios-etsy-swiftui.md +296 -0
  245. package/dist/data/designs/ios-etsy.md +355 -0
  246. package/dist/data/designs/ios-evernote-android.md +419 -0
  247. package/dist/data/designs/ios-evernote-expo.md +379 -0
  248. package/dist/data/designs/ios-evernote-swiftui.md +380 -0
  249. package/dist/data/designs/ios-evernote.md +416 -0
  250. package/dist/data/designs/ios-expedia-android.md +451 -0
  251. package/dist/data/designs/ios-expedia-expo.md +433 -0
  252. package/dist/data/designs/ios-expedia-swiftui.md +399 -0
  253. package/dist/data/designs/ios-expedia.md +431 -0
  254. package/dist/data/designs/ios-facebook-android.md +628 -0
  255. package/dist/data/designs/ios-facebook-expo.md +471 -0
  256. package/dist/data/designs/ios-facebook-swiftui.md +459 -0
  257. package/dist/data/designs/ios-facebook.md +452 -0
  258. package/dist/data/designs/ios-feeld-android.md +431 -0
  259. package/dist/data/designs/ios-feeld-expo.md +379 -0
  260. package/dist/data/designs/ios-feeld-swiftui.md +401 -0
  261. package/dist/data/designs/ios-feeld.md +378 -0
  262. package/dist/data/designs/ios-fidelity-android.md +426 -0
  263. package/dist/data/designs/ios-fidelity-expo.md +396 -0
  264. package/dist/data/designs/ios-fidelity-swiftui.md +398 -0
  265. package/dist/data/designs/ios-fidelity.md +387 -0
  266. package/dist/data/designs/ios-figma-android.md +578 -0
  267. package/dist/data/designs/ios-figma-expo.md +504 -0
  268. package/dist/data/designs/ios-figma-swiftui.md +542 -0
  269. package/dist/data/designs/ios-figma.md +404 -0
  270. package/dist/data/designs/ios-fitbit-android.md +439 -0
  271. package/dist/data/designs/ios-fitbit-expo.md +389 -0
  272. package/dist/data/designs/ios-fitbit-swiftui.md +380 -0
  273. package/dist/data/designs/ios-fitbit.md +396 -0
  274. package/dist/data/designs/ios-flickr-android.md +506 -0
  275. package/dist/data/designs/ios-flickr-expo.md +434 -0
  276. package/dist/data/designs/ios-flickr-swiftui.md +421 -0
  277. package/dist/data/designs/ios-flickr.md +394 -0
  278. package/dist/data/designs/ios-flighty-android.md +418 -0
  279. package/dist/data/designs/ios-flighty-expo.md +353 -0
  280. package/dist/data/designs/ios-flighty-swiftui.md +337 -0
  281. package/dist/data/designs/ios-flighty.md +357 -0
  282. package/dist/data/designs/ios-flo-android.md +447 -0
  283. package/dist/data/designs/ios-flo-expo.md +363 -0
  284. package/dist/data/designs/ios-flo-swiftui.md +355 -0
  285. package/dist/data/designs/ios-flo.md +351 -0
  286. package/dist/data/designs/ios-garmin-connect-android.md +531 -0
  287. package/dist/data/designs/ios-garmin-connect-expo.md +429 -0
  288. package/dist/data/designs/ios-garmin-connect-swiftui.md +459 -0
  289. package/dist/data/designs/ios-garmin-connect.md +419 -0
  290. package/dist/data/designs/ios-gas-android.md +438 -0
  291. package/dist/data/designs/ios-gas-expo.md +350 -0
  292. package/dist/data/designs/ios-gas-swiftui.md +329 -0
  293. package/dist/data/designs/ios-gas.md +387 -0
  294. package/dist/data/designs/ios-gemini-android.md +568 -0
  295. package/dist/data/designs/ios-gemini-expo.md +416 -0
  296. package/dist/data/designs/ios-gemini-swiftui.md +424 -0
  297. package/dist/data/designs/ios-gemini.md +351 -0
  298. package/dist/data/designs/ios-github-android.md +507 -0
  299. package/dist/data/designs/ios-github-expo.md +486 -0
  300. package/dist/data/designs/ios-github-swiftui.md +459 -0
  301. package/dist/data/designs/ios-github.md +394 -0
  302. package/dist/data/designs/ios-gmail-android.md +548 -0
  303. package/dist/data/designs/ios-gmail-expo.md +457 -0
  304. package/dist/data/designs/ios-gmail-swiftui.md +470 -0
  305. package/dist/data/designs/ios-gmail.md +441 -0
  306. package/dist/data/designs/ios-goodreads-android.md +436 -0
  307. package/dist/data/designs/ios-goodreads-expo.md +407 -0
  308. package/dist/data/designs/ios-goodreads-swiftui.md +378 -0
  309. package/dist/data/designs/ios-goodreads.md +385 -0
  310. package/dist/data/designs/ios-google-calendar-android.md +565 -0
  311. package/dist/data/designs/ios-google-calendar-expo.md +616 -0
  312. package/dist/data/designs/ios-google-calendar-swiftui.md +585 -0
  313. package/dist/data/designs/ios-google-calendar.md +431 -0
  314. package/dist/data/designs/ios-google-maps-android.md +614 -0
  315. package/dist/data/designs/ios-google-maps-expo.md +515 -0
  316. package/dist/data/designs/ios-google-maps-swiftui.md +484 -0
  317. package/dist/data/designs/ios-google-maps.md +451 -0
  318. package/dist/data/designs/ios-grammarly-android.md +449 -0
  319. package/dist/data/designs/ios-grammarly-expo.md +383 -0
  320. package/dist/data/designs/ios-grammarly-swiftui.md +381 -0
  321. package/dist/data/designs/ios-grammarly.md +392 -0
  322. package/dist/data/designs/ios-grindr-android.md +494 -0
  323. package/dist/data/designs/ios-grindr-expo.md +358 -0
  324. package/dist/data/designs/ios-grindr-swiftui.md +357 -0
  325. package/dist/data/designs/ios-grindr.md +356 -0
  326. package/dist/data/designs/ios-grok-android.md +471 -0
  327. package/dist/data/designs/ios-grok-expo.md +388 -0
  328. package/dist/data/designs/ios-grok-swiftui.md +397 -0
  329. package/dist/data/designs/ios-grok.md +357 -0
  330. package/dist/data/designs/ios-groupme-android.md +551 -0
  331. package/dist/data/designs/ios-groupme-expo.md +442 -0
  332. package/dist/data/designs/ios-groupme-swiftui.md +439 -0
  333. package/dist/data/designs/ios-groupme.md +424 -0
  334. package/dist/data/designs/ios-grubhub-android.md +506 -0
  335. package/dist/data/designs/ios-grubhub-expo.md +428 -0
  336. package/dist/data/designs/ios-grubhub-swiftui.md +408 -0
  337. package/dist/data/designs/ios-grubhub.md +427 -0
  338. package/dist/data/designs/ios-happn-android.md +464 -0
  339. package/dist/data/designs/ios-happn-expo.md +411 -0
  340. package/dist/data/designs/ios-happn-swiftui.md +401 -0
  341. package/dist/data/designs/ios-happn.md +400 -0
  342. package/dist/data/designs/ios-headspace-android.md +688 -0
  343. package/dist/data/designs/ios-headspace-expo.md +574 -0
  344. package/dist/data/designs/ios-headspace-swiftui.md +498 -0
  345. package/dist/data/designs/ios-headspace.md +430 -0
  346. package/dist/data/designs/ios-hevy-android.md +473 -0
  347. package/dist/data/designs/ios-hevy-expo.md +405 -0
  348. package/dist/data/designs/ios-hevy-swiftui.md +367 -0
  349. package/dist/data/designs/ios-hevy.md +410 -0
  350. package/dist/data/designs/ios-hinge-android.md +743 -0
  351. package/dist/data/designs/ios-hinge-expo.md +580 -0
  352. package/dist/data/designs/ios-hinge-swiftui.md +512 -0
  353. package/dist/data/designs/ios-hinge.md +405 -0
  354. package/dist/data/designs/ios-hopper-android.md +440 -0
  355. package/dist/data/designs/ios-hopper-expo.md +353 -0
  356. package/dist/data/designs/ios-hopper-swiftui.md +340 -0
  357. package/dist/data/designs/ios-hopper.md +354 -0
  358. package/dist/data/designs/ios-hulu-android.md +435 -0
  359. package/dist/data/designs/ios-hulu-expo.md +331 -0
  360. package/dist/data/designs/ios-hulu-swiftui.md +374 -0
  361. package/dist/data/designs/ios-hulu.md +353 -0
  362. package/dist/data/designs/ios-iheartradio-android.md +481 -0
  363. package/dist/data/designs/ios-iheartradio-expo.md +417 -0
  364. package/dist/data/designs/ios-iheartradio-swiftui.md +423 -0
  365. package/dist/data/designs/ios-iheartradio.md +381 -0
  366. package/dist/data/designs/ios-imessage-android.md +426 -0
  367. package/dist/data/designs/ios-imessage-expo.md +384 -0
  368. package/dist/data/designs/ios-imessage-swiftui.md +378 -0
  369. package/dist/data/designs/ios-imessage.md +394 -0
  370. package/dist/data/designs/ios-instacart-android.md +471 -0
  371. package/dist/data/designs/ios-instacart-expo.md +349 -0
  372. package/dist/data/designs/ios-instacart-swiftui.md +378 -0
  373. package/dist/data/designs/ios-instacart.md +360 -0
  374. package/dist/data/designs/ios-instagram-android.md +646 -0
  375. package/dist/data/designs/ios-instagram-expo.md +310 -0
  376. package/dist/data/designs/ios-instagram-swiftui.md +333 -0
  377. package/dist/data/designs/ios-instagram.md +376 -0
  378. package/dist/data/designs/ios-jira-android.md +432 -0
  379. package/dist/data/designs/ios-jira-expo.md +375 -0
  380. package/dist/data/designs/ios-jira-swiftui.md +433 -0
  381. package/dist/data/designs/ios-jira.md +424 -0
  382. package/dist/data/designs/ios-kakaotalk-android.md +491 -0
  383. package/dist/data/designs/ios-kakaotalk-expo.md +418 -0
  384. package/dist/data/designs/ios-kakaotalk-swiftui.md +406 -0
  385. package/dist/data/designs/ios-kakaotalk.md +414 -0
  386. package/dist/data/designs/ios-kayak-android.md +466 -0
  387. package/dist/data/designs/ios-kayak-expo.md +407 -0
  388. package/dist/data/designs/ios-kayak-swiftui.md +426 -0
  389. package/dist/data/designs/ios-kayak.md +392 -0
  390. package/dist/data/designs/ios-kick-android.md +487 -0
  391. package/dist/data/designs/ios-kick-expo.md +434 -0
  392. package/dist/data/designs/ios-kick-swiftui.md +429 -0
  393. package/dist/data/designs/ios-kick.md +389 -0
  394. package/dist/data/designs/ios-kik-android.md +433 -0
  395. package/dist/data/designs/ios-kik-expo.md +363 -0
  396. package/dist/data/designs/ios-kik-swiftui.md +363 -0
  397. package/dist/data/designs/ios-kik.md +392 -0
  398. package/dist/data/designs/ios-kindle-android.md +439 -0
  399. package/dist/data/designs/ios-kindle-expo.md +356 -0
  400. package/dist/data/designs/ios-kindle-swiftui.md +372 -0
  401. package/dist/data/designs/ios-kindle.md +369 -0
  402. package/dist/data/designs/ios-klarna-android.md +420 -0
  403. package/dist/data/designs/ios-klarna-expo.md +349 -0
  404. package/dist/data/designs/ios-klarna-swiftui.md +360 -0
  405. package/dist/data/designs/ios-klarna.md +356 -0
  406. package/dist/data/designs/ios-lemon8-android.md +492 -0
  407. package/dist/data/designs/ios-lemon8-expo.md +413 -0
  408. package/dist/data/designs/ios-lemon8-swiftui.md +428 -0
  409. package/dist/data/designs/ios-lemon8.md +378 -0
  410. package/dist/data/designs/ios-life360-android.md +474 -0
  411. package/dist/data/designs/ios-life360-expo.md +375 -0
  412. package/dist/data/designs/ios-life360-swiftui.md +390 -0
  413. package/dist/data/designs/ios-life360.md +402 -0
  414. package/dist/data/designs/ios-line-android.md +517 -0
  415. package/dist/data/designs/ios-line-expo.md +402 -0
  416. package/dist/data/designs/ios-line-swiftui.md +361 -0
  417. package/dist/data/designs/ios-line.md +362 -0
  418. package/dist/data/designs/ios-linear-android.md +457 -0
  419. package/dist/data/designs/ios-linear-expo.md +367 -0
  420. package/dist/data/designs/ios-linear-swiftui.md +401 -0
  421. package/dist/data/designs/ios-linear.md +368 -0
  422. package/dist/data/designs/ios-linkedin-android.md +620 -0
  423. package/dist/data/designs/ios-linkedin-expo.md +469 -0
  424. package/dist/data/designs/ios-linkedin-swiftui.md +472 -0
  425. package/dist/data/designs/ios-linkedin.md +444 -0
  426. package/dist/data/designs/ios-locket-android.md +500 -0
  427. package/dist/data/designs/ios-locket-expo.md +375 -0
  428. package/dist/data/designs/ios-locket-swiftui.md +375 -0
  429. package/dist/data/designs/ios-locket.md +381 -0
  430. package/dist/data/designs/ios-lyft-android.md +406 -0
  431. package/dist/data/designs/ios-lyft-expo.md +333 -0
  432. package/dist/data/designs/ios-lyft-swiftui.md +315 -0
  433. package/dist/data/designs/ios-lyft.md +337 -0
  434. package/dist/data/designs/ios-marriott-bonvoy-android.md +488 -0
  435. package/dist/data/designs/ios-marriott-bonvoy-expo.md +412 -0
  436. package/dist/data/designs/ios-marriott-bonvoy-swiftui.md +461 -0
  437. package/dist/data/designs/ios-marriott-bonvoy.md +379 -0
  438. package/dist/data/designs/ios-mastodon-android.md +476 -0
  439. package/dist/data/designs/ios-mastodon-expo.md +379 -0
  440. package/dist/data/designs/ios-mastodon-swiftui.md +349 -0
  441. package/dist/data/designs/ios-mastodon.md +337 -0
  442. package/dist/data/designs/ios-match-android.md +496 -0
  443. package/dist/data/designs/ios-match-expo.md +393 -0
  444. package/dist/data/designs/ios-match-swiftui.md +450 -0
  445. package/dist/data/designs/ios-match.md +382 -0
  446. package/dist/data/designs/ios-max-android.md +454 -0
  447. package/dist/data/designs/ios-max-expo.md +342 -0
  448. package/dist/data/designs/ios-max-swiftui.md +332 -0
  449. package/dist/data/designs/ios-max.md +352 -0
  450. package/dist/data/designs/ios-mcdonalds-android.md +497 -0
  451. package/dist/data/designs/ios-mcdonalds-expo.md +382 -0
  452. package/dist/data/designs/ios-mcdonalds-swiftui.md +394 -0
  453. package/dist/data/designs/ios-mcdonalds.md +410 -0
  454. package/dist/data/designs/ios-messenger-android.md +523 -0
  455. package/dist/data/designs/ios-messenger-expo.md +379 -0
  456. package/dist/data/designs/ios-messenger-swiftui.md +369 -0
  457. package/dist/data/designs/ios-messenger.md +361 -0
  458. package/dist/data/designs/ios-microsoft-teams-android.md +446 -0
  459. package/dist/data/designs/ios-microsoft-teams-expo.md +362 -0
  460. package/dist/data/designs/ios-microsoft-teams-swiftui.md +384 -0
  461. package/dist/data/designs/ios-microsoft-teams.md +359 -0
  462. package/dist/data/designs/ios-midjourney-android.md +503 -0
  463. package/dist/data/designs/ios-midjourney-expo.md +406 -0
  464. package/dist/data/designs/ios-midjourney-swiftui.md +376 -0
  465. package/dist/data/designs/ios-midjourney.md +407 -0
  466. package/dist/data/designs/ios-miro-android.md +475 -0
  467. package/dist/data/designs/ios-miro-expo.md +421 -0
  468. package/dist/data/designs/ios-miro-swiftui.md +407 -0
  469. package/dist/data/designs/ios-miro.md +424 -0
  470. package/dist/data/designs/ios-monday-android.md +426 -0
  471. package/dist/data/designs/ios-monday-expo.md +382 -0
  472. package/dist/data/designs/ios-monday-swiftui.md +386 -0
  473. package/dist/data/designs/ios-monday.md +415 -0
  474. package/dist/data/designs/ios-monzo-android.md +423 -0
  475. package/dist/data/designs/ios-monzo-expo.md +391 -0
  476. package/dist/data/designs/ios-monzo-swiftui.md +371 -0
  477. package/dist/data/designs/ios-monzo.md +382 -0
  478. package/dist/data/designs/ios-myfitnesspal-android.md +631 -0
  479. package/dist/data/designs/ios-myfitnesspal-expo.md +489 -0
  480. package/dist/data/designs/ios-myfitnesspal-swiftui.md +500 -0
  481. package/dist/data/designs/ios-myfitnesspal.md +408 -0
  482. package/dist/data/designs/ios-netflix-android.md +570 -0
  483. package/dist/data/designs/ios-netflix-expo.md +528 -0
  484. package/dist/data/designs/ios-netflix-swiftui.md +543 -0
  485. package/dist/data/designs/ios-netflix.md +476 -0
  486. package/dist/data/designs/ios-nextdoor-android.md +399 -0
  487. package/dist/data/designs/ios-nextdoor-expo.md +317 -0
  488. package/dist/data/designs/ios-nextdoor-swiftui.md +343 -0
  489. package/dist/data/designs/ios-nextdoor.md +332 -0
  490. package/dist/data/designs/ios-nike-run-club-android.md +598 -0
  491. package/dist/data/designs/ios-nike-run-club-expo.md +459 -0
  492. package/dist/data/designs/ios-nike-run-club-swiftui.md +474 -0
  493. package/dist/data/designs/ios-nike-run-club.md +400 -0
  494. package/dist/data/designs/ios-noom-android.md +455 -0
  495. package/dist/data/designs/ios-noom-expo.md +362 -0
  496. package/dist/data/designs/ios-noom-swiftui.md +369 -0
  497. package/dist/data/designs/ios-noom.md +404 -0
  498. package/dist/data/designs/ios-notion-android.md +575 -0
  499. package/dist/data/designs/ios-notion-expo.md +543 -0
  500. package/dist/data/designs/ios-notion-swiftui.md +562 -0
  501. package/dist/data/designs/ios-notion.md +506 -0
  502. package/dist/data/designs/ios-nubank-android.md +447 -0
  503. package/dist/data/designs/ios-nubank-expo.md +391 -0
  504. package/dist/data/designs/ios-nubank-swiftui.md +391 -0
  505. package/dist/data/designs/ios-nubank.md +388 -0
  506. package/dist/data/designs/ios-obsidian-android.md +456 -0
  507. package/dist/data/designs/ios-obsidian-expo.md +401 -0
  508. package/dist/data/designs/ios-obsidian-swiftui.md +412 -0
  509. package/dist/data/designs/ios-obsidian.md +363 -0
  510. package/dist/data/designs/ios-okcupid-android.md +496 -0
  511. package/dist/data/designs/ios-okcupid-expo.md +378 -0
  512. package/dist/data/designs/ios-okcupid-swiftui.md +343 -0
  513. package/dist/data/designs/ios-okcupid.md +364 -0
  514. package/dist/data/designs/ios-opentable-android.md +426 -0
  515. package/dist/data/designs/ios-opentable-expo.md +350 -0
  516. package/dist/data/designs/ios-opentable-swiftui.md +328 -0
  517. package/dist/data/designs/ios-opentable.md +411 -0
  518. package/dist/data/designs/ios-oura-android.md +426 -0
  519. package/dist/data/designs/ios-oura-expo.md +353 -0
  520. package/dist/data/designs/ios-oura-swiftui.md +327 -0
  521. package/dist/data/designs/ios-oura.md +356 -0
  522. package/dist/data/designs/ios-overcast-android.md +508 -0
  523. package/dist/data/designs/ios-overcast-expo.md +420 -0
  524. package/dist/data/designs/ios-overcast-swiftui.md +427 -0
  525. package/dist/data/designs/ios-overcast.md +414 -0
  526. package/dist/data/designs/ios-pandora-android.md +477 -0
  527. package/dist/data/designs/ios-pandora-expo.md +406 -0
  528. package/dist/data/designs/ios-pandora-swiftui.md +413 -0
  529. package/dist/data/designs/ios-pandora.md +366 -0
  530. package/dist/data/designs/ios-panera-android.md +414 -0
  531. package/dist/data/designs/ios-panera-expo.md +352 -0
  532. package/dist/data/designs/ios-panera-swiftui.md +369 -0
  533. package/dist/data/designs/ios-panera.md +412 -0
  534. package/dist/data/designs/ios-paramount-plus-android.md +415 -0
  535. package/dist/data/designs/ios-paramount-plus-expo.md +363 -0
  536. package/dist/data/designs/ios-paramount-plus-swiftui.md +372 -0
  537. package/dist/data/designs/ios-paramount-plus.md +400 -0
  538. package/dist/data/designs/ios-paypal-android.md +535 -0
  539. package/dist/data/designs/ios-paypal-expo.md +429 -0
  540. package/dist/data/designs/ios-paypal-swiftui.md +466 -0
  541. package/dist/data/designs/ios-paypal.md +393 -0
  542. package/dist/data/designs/ios-peacock-android.md +453 -0
  543. package/dist/data/designs/ios-peacock-expo.md +393 -0
  544. package/dist/data/designs/ios-peacock-swiftui.md +420 -0
  545. package/dist/data/designs/ios-peacock.md +411 -0
  546. package/dist/data/designs/ios-peloton-android.md +470 -0
  547. package/dist/data/designs/ios-peloton-expo.md +401 -0
  548. package/dist/data/designs/ios-peloton-swiftui.md +409 -0
  549. package/dist/data/designs/ios-peloton.md +415 -0
  550. package/dist/data/designs/ios-perplexity-android.md +553 -0
  551. package/dist/data/designs/ios-perplexity-expo.md +703 -0
  552. package/dist/data/designs/ios-perplexity-swiftui.md +602 -0
  553. package/dist/data/designs/ios-perplexity.md +453 -0
  554. package/dist/data/designs/ios-pinterest-android.md +551 -0
  555. package/dist/data/designs/ios-pinterest-expo.md +466 -0
  556. package/dist/data/designs/ios-pinterest-swiftui.md +464 -0
  557. package/dist/data/designs/ios-pinterest.md +427 -0
  558. package/dist/data/designs/ios-plenty-of-fish-android.md +462 -0
  559. package/dist/data/designs/ios-plenty-of-fish-expo.md +380 -0
  560. package/dist/data/designs/ios-plenty-of-fish-swiftui.md +429 -0
  561. package/dist/data/designs/ios-plenty-of-fish.md +387 -0
  562. package/dist/data/designs/ios-plex-android.md +403 -0
  563. package/dist/data/designs/ios-plex-expo.md +333 -0
  564. package/dist/data/designs/ios-plex-swiftui.md +349 -0
  565. package/dist/data/designs/ios-plex.md +379 -0
  566. package/dist/data/designs/ios-pluto-tv-android.md +413 -0
  567. package/dist/data/designs/ios-pluto-tv-expo.md +379 -0
  568. package/dist/data/designs/ios-pluto-tv-swiftui.md +411 -0
  569. package/dist/data/designs/ios-pluto-tv.md +362 -0
  570. package/dist/data/designs/ios-pocket-casts-android.md +492 -0
  571. package/dist/data/designs/ios-pocket-casts-expo.md +430 -0
  572. package/dist/data/designs/ios-pocket-casts-swiftui.md +479 -0
  573. package/dist/data/designs/ios-pocket-casts.md +427 -0
  574. package/dist/data/designs/ios-postman-android.md +472 -0
  575. package/dist/data/designs/ios-postman-expo.md +372 -0
  576. package/dist/data/designs/ios-postman-swiftui.md +377 -0
  577. package/dist/data/designs/ios-postman.md +405 -0
  578. package/dist/data/designs/ios-prime-video-android.md +447 -0
  579. package/dist/data/designs/ios-prime-video-expo.md +365 -0
  580. package/dist/data/designs/ios-prime-video-swiftui.md +333 -0
  581. package/dist/data/designs/ios-prime-video.md +351 -0
  582. package/dist/data/designs/ios-quora-android.md +513 -0
  583. package/dist/data/designs/ios-quora-expo.md +362 -0
  584. package/dist/data/designs/ios-quora-swiftui.md +375 -0
  585. package/dist/data/designs/ios-quora.md +359 -0
  586. package/dist/data/designs/ios-raya-android.md +401 -0
  587. package/dist/data/designs/ios-raya-expo.md +366 -0
  588. package/dist/data/designs/ios-raya-swiftui.md +393 -0
  589. package/dist/data/designs/ios-raya.md +366 -0
  590. package/dist/data/designs/ios-reddit-android.md +605 -0
  591. package/dist/data/designs/ios-reddit-expo.md +553 -0
  592. package/dist/data/designs/ios-reddit-swiftui.md +514 -0
  593. package/dist/data/designs/ios-reddit.md +460 -0
  594. package/dist/data/designs/ios-resy-android.md +430 -0
  595. package/dist/data/designs/ios-resy-expo.md +344 -0
  596. package/dist/data/designs/ios-resy-swiftui.md +330 -0
  597. package/dist/data/designs/ios-resy.md +412 -0
  598. package/dist/data/designs/ios-revolut-android.md +433 -0
  599. package/dist/data/designs/ios-revolut-expo.md +379 -0
  600. package/dist/data/designs/ios-revolut-swiftui.md +372 -0
  601. package/dist/data/designs/ios-revolut.md +353 -0
  602. package/dist/data/designs/ios-robinhood-android.md +587 -0
  603. package/dist/data/designs/ios-robinhood-expo.md +416 -0
  604. package/dist/data/designs/ios-robinhood-swiftui.md +431 -0
  605. package/dist/data/designs/ios-robinhood.md +380 -0
  606. package/dist/data/designs/ios-runna-android.md +485 -0
  607. package/dist/data/designs/ios-runna-expo.md +388 -0
  608. package/dist/data/designs/ios-runna-swiftui.md +413 -0
  609. package/dist/data/designs/ios-runna.md +390 -0
  610. package/dist/data/designs/ios-shazam-android.md +436 -0
  611. package/dist/data/designs/ios-shazam-expo.md +348 -0
  612. package/dist/data/designs/ios-shazam-swiftui.md +394 -0
  613. package/dist/data/designs/ios-shazam.md +338 -0
  614. package/dist/data/designs/ios-signal-android.md +462 -0
  615. package/dist/data/designs/ios-signal-expo.md +361 -0
  616. package/dist/data/designs/ios-signal-swiftui.md +350 -0
  617. package/dist/data/designs/ios-signal.md +357 -0
  618. package/dist/data/designs/ios-skype-android.md +398 -0
  619. package/dist/data/designs/ios-skype-expo.md +368 -0
  620. package/dist/data/designs/ios-skype-swiftui.md +369 -0
  621. package/dist/data/designs/ios-skype.md +406 -0
  622. package/dist/data/designs/ios-skyscanner-android.md +451 -0
  623. package/dist/data/designs/ios-skyscanner-expo.md +423 -0
  624. package/dist/data/designs/ios-skyscanner-swiftui.md +419 -0
  625. package/dist/data/designs/ios-skyscanner.md +421 -0
  626. package/dist/data/designs/ios-slack-android.md +695 -0
  627. package/dist/data/designs/ios-slack-expo.md +601 -0
  628. package/dist/data/designs/ios-slack-swiftui.md +594 -0
  629. package/dist/data/designs/ios-slack.md +474 -0
  630. package/dist/data/designs/ios-sleep-cycle-android.md +436 -0
  631. package/dist/data/designs/ios-sleep-cycle-expo.md +380 -0
  632. package/dist/data/designs/ios-sleep-cycle-swiftui.md +409 -0
  633. package/dist/data/designs/ios-sleep-cycle.md +386 -0
  634. package/dist/data/designs/ios-snapchat-android.md +671 -0
  635. package/dist/data/designs/ios-snapchat-expo.md +528 -0
  636. package/dist/data/designs/ios-snapchat-swiftui.md +557 -0
  637. package/dist/data/designs/ios-snapchat.md +478 -0
  638. package/dist/data/designs/ios-sofi-android.md +446 -0
  639. package/dist/data/designs/ios-sofi-expo.md +387 -0
  640. package/dist/data/designs/ios-sofi-swiftui.md +379 -0
  641. package/dist/data/designs/ios-sofi.md +385 -0
  642. package/dist/data/designs/ios-soundcloud-android.md +488 -0
  643. package/dist/data/designs/ios-soundcloud-expo.md +364 -0
  644. package/dist/data/designs/ios-soundcloud-swiftui.md +399 -0
  645. package/dist/data/designs/ios-soundcloud.md +359 -0
  646. package/dist/data/designs/ios-southwest-android.md +446 -0
  647. package/dist/data/designs/ios-southwest-expo.md +389 -0
  648. package/dist/data/designs/ios-southwest-swiftui.md +405 -0
  649. package/dist/data/designs/ios-southwest.md +405 -0
  650. package/dist/data/designs/ios-spotify-android.md +427 -0
  651. package/dist/data/designs/ios-spotify-expo.md +321 -0
  652. package/dist/data/designs/ios-spotify-swiftui.md +312 -0
  653. package/dist/data/designs/ios-spotify.md +366 -0
  654. package/dist/data/designs/ios-starbucks-android.md +622 -0
  655. package/dist/data/designs/ios-starbucks-expo.md +497 -0
  656. package/dist/data/designs/ios-starbucks-swiftui.md +500 -0
  657. package/dist/data/designs/ios-starbucks.md +440 -0
  658. package/dist/data/designs/ios-strava-android.md +656 -0
  659. package/dist/data/designs/ios-strava-expo.md +501 -0
  660. package/dist/data/designs/ios-strava-swiftui.md +465 -0
  661. package/dist/data/designs/ios-strava.md +433 -0
  662. package/dist/data/designs/ios-strong-android.md +479 -0
  663. package/dist/data/designs/ios-strong-expo.md +396 -0
  664. package/dist/data/designs/ios-strong-swiftui.md +363 -0
  665. package/dist/data/designs/ios-strong.md +415 -0
  666. package/dist/data/designs/ios-substack-android.md +440 -0
  667. package/dist/data/designs/ios-substack-expo.md +395 -0
  668. package/dist/data/designs/ios-substack-swiftui.md +371 -0
  669. package/dist/data/designs/ios-substack.md +372 -0
  670. package/dist/data/designs/ios-swiggy-android.md +549 -0
  671. package/dist/data/designs/ios-swiggy-expo.md +443 -0
  672. package/dist/data/designs/ios-swiggy-swiftui.md +471 -0
  673. package/dist/data/designs/ios-swiggy.md +432 -0
  674. package/dist/data/designs/ios-taco-bell-android.md +529 -0
  675. package/dist/data/designs/ios-taco-bell-expo.md +407 -0
  676. package/dist/data/designs/ios-taco-bell-swiftui.md +419 -0
  677. package/dist/data/designs/ios-taco-bell.md +430 -0
  678. package/dist/data/designs/ios-telegram-android.md +676 -0
  679. package/dist/data/designs/ios-telegram-expo.md +594 -0
  680. package/dist/data/designs/ios-telegram-swiftui.md +518 -0
  681. package/dist/data/designs/ios-telegram.md +458 -0
  682. package/dist/data/designs/ios-the-league-android.md +454 -0
  683. package/dist/data/designs/ios-the-league-expo.md +391 -0
  684. package/dist/data/designs/ios-the-league-swiftui.md +409 -0
  685. package/dist/data/designs/ios-the-league.md +368 -0
  686. package/dist/data/designs/ios-things-3-android.md +421 -0
  687. package/dist/data/designs/ios-things-3-expo.md +351 -0
  688. package/dist/data/designs/ios-things-3-swiftui.md +359 -0
  689. package/dist/data/designs/ios-things-3.md +339 -0
  690. package/dist/data/designs/ios-threads-android.md +588 -0
  691. package/dist/data/designs/ios-threads-expo.md +468 -0
  692. package/dist/data/designs/ios-threads-swiftui.md +452 -0
  693. package/dist/data/designs/ios-threads.md +424 -0
  694. package/dist/data/designs/ios-threema-android.md +496 -0
  695. package/dist/data/designs/ios-threema-expo.md +415 -0
  696. package/dist/data/designs/ios-threema-swiftui.md +446 -0
  697. package/dist/data/designs/ios-threema.md +397 -0
  698. package/dist/data/designs/ios-tidal-android.md +398 -0
  699. package/dist/data/designs/ios-tidal-expo.md +323 -0
  700. package/dist/data/designs/ios-tidal-swiftui.md +340 -0
  701. package/dist/data/designs/ios-tidal.md +351 -0
  702. package/dist/data/designs/ios-tiktok-android.md +654 -0
  703. package/dist/data/designs/ios-tiktok-expo.md +578 -0
  704. package/dist/data/designs/ios-tiktok-swiftui.md +595 -0
  705. package/dist/data/designs/ios-tiktok.md +387 -0
  706. package/dist/data/designs/ios-tinder-android.md +681 -0
  707. package/dist/data/designs/ios-tinder-expo.md +512 -0
  708. package/dist/data/designs/ios-tinder-swiftui.md +497 -0
  709. package/dist/data/designs/ios-tinder.md +415 -0
  710. package/dist/data/designs/ios-todoist-android.md +711 -0
  711. package/dist/data/designs/ios-todoist-expo.md +607 -0
  712. package/dist/data/designs/ios-todoist-swiftui.md +573 -0
  713. package/dist/data/designs/ios-todoist.md +418 -0
  714. package/dist/data/designs/ios-trello-android.md +412 -0
  715. package/dist/data/designs/ios-trello-expo.md +332 -0
  716. package/dist/data/designs/ios-trello-swiftui.md +359 -0
  717. package/dist/data/designs/ios-trello.md +344 -0
  718. package/dist/data/designs/ios-tripadvisor-android.md +450 -0
  719. package/dist/data/designs/ios-tripadvisor-expo.md +322 -0
  720. package/dist/data/designs/ios-tripadvisor-swiftui.md +326 -0
  721. package/dist/data/designs/ios-tripadvisor.md +356 -0
  722. package/dist/data/designs/ios-tubi-android.md +453 -0
  723. package/dist/data/designs/ios-tubi-expo.md +419 -0
  724. package/dist/data/designs/ios-tubi-swiftui.md +463 -0
  725. package/dist/data/designs/ios-tubi.md +383 -0
  726. package/dist/data/designs/ios-tumblr-android.md +462 -0
  727. package/dist/data/designs/ios-tumblr-expo.md +374 -0
  728. package/dist/data/designs/ios-tumblr-swiftui.md +380 -0
  729. package/dist/data/designs/ios-tumblr.md +337 -0
  730. package/dist/data/designs/ios-turo-android.md +500 -0
  731. package/dist/data/designs/ios-turo-expo.md +454 -0
  732. package/dist/data/designs/ios-turo-swiftui.md +447 -0
  733. package/dist/data/designs/ios-turo.md +392 -0
  734. package/dist/data/designs/ios-twitch-android.md +412 -0
  735. package/dist/data/designs/ios-twitch-expo.md +342 -0
  736. package/dist/data/designs/ios-twitch-swiftui.md +328 -0
  737. package/dist/data/designs/ios-twitch.md +354 -0
  738. package/dist/data/designs/ios-uber-android.md +637 -0
  739. package/dist/data/designs/ios-uber-eats-android.md +502 -0
  740. package/dist/data/designs/ios-uber-eats-expo.md +407 -0
  741. package/dist/data/designs/ios-uber-eats-swiftui.md +393 -0
  742. package/dist/data/designs/ios-uber-eats.md +353 -0
  743. package/dist/data/designs/ios-uber-expo.md +512 -0
  744. package/dist/data/designs/ios-uber-swiftui.md +483 -0
  745. package/dist/data/designs/ios-uber.md +395 -0
  746. package/dist/data/designs/ios-united-airlines-android.md +494 -0
  747. package/dist/data/designs/ios-united-airlines-expo.md +408 -0
  748. package/dist/data/designs/ios-united-airlines-swiftui.md +453 -0
  749. package/dist/data/designs/ios-united-airlines.md +388 -0
  750. package/dist/data/designs/ios-venmo-android.md +654 -0
  751. package/dist/data/designs/ios-venmo-expo.md +458 -0
  752. package/dist/data/designs/ios-venmo-swiftui.md +469 -0
  753. package/dist/data/designs/ios-venmo.md +436 -0
  754. package/dist/data/designs/ios-vercel-android.md +454 -0
  755. package/dist/data/designs/ios-vercel-expo.md +387 -0
  756. package/dist/data/designs/ios-vercel-swiftui.md +374 -0
  757. package/dist/data/designs/ios-vercel.md +399 -0
  758. package/dist/data/designs/ios-vero-android.md +498 -0
  759. package/dist/data/designs/ios-vero-expo.md +376 -0
  760. package/dist/data/designs/ios-vero-swiftui.md +374 -0
  761. package/dist/data/designs/ios-vero.md +394 -0
  762. package/dist/data/designs/ios-viber-android.md +377 -0
  763. package/dist/data/designs/ios-viber-expo.md +375 -0
  764. package/dist/data/designs/ios-viber-swiftui.md +378 -0
  765. package/dist/data/designs/ios-viber.md +403 -0
  766. package/dist/data/designs/ios-vimeo-android.md +465 -0
  767. package/dist/data/designs/ios-vimeo-expo.md +347 -0
  768. package/dist/data/designs/ios-vimeo-swiftui.md +383 -0
  769. package/dist/data/designs/ios-vimeo.md +403 -0
  770. package/dist/data/designs/ios-vrbo-android.md +488 -0
  771. package/dist/data/designs/ios-vrbo-expo.md +395 -0
  772. package/dist/data/designs/ios-vrbo-swiftui.md +421 -0
  773. package/dist/data/designs/ios-vrbo.md +383 -0
  774. package/dist/data/designs/ios-vsco-android.md +490 -0
  775. package/dist/data/designs/ios-vsco-expo.md +413 -0
  776. package/dist/data/designs/ios-vsco-swiftui.md +449 -0
  777. package/dist/data/designs/ios-vsco.md +412 -0
  778. package/dist/data/designs/ios-walmart-android.md +479 -0
  779. package/dist/data/designs/ios-walmart-expo.md +370 -0
  780. package/dist/data/designs/ios-walmart-swiftui.md +387 -0
  781. package/dist/data/designs/ios-walmart.md +366 -0
  782. package/dist/data/designs/ios-waze-android.md +695 -0
  783. package/dist/data/designs/ios-waze-expo.md +587 -0
  784. package/dist/data/designs/ios-waze-swiftui.md +601 -0
  785. package/dist/data/designs/ios-waze.md +453 -0
  786. package/dist/data/designs/ios-webull-android.md +429 -0
  787. package/dist/data/designs/ios-webull-expo.md +384 -0
  788. package/dist/data/designs/ios-webull-swiftui.md +406 -0
  789. package/dist/data/designs/ios-webull.md +375 -0
  790. package/dist/data/designs/ios-wechat-android.md +545 -0
  791. package/dist/data/designs/ios-wechat-expo.md +398 -0
  792. package/dist/data/designs/ios-wechat-swiftui.md +394 -0
  793. package/dist/data/designs/ios-wechat.md +363 -0
  794. package/dist/data/designs/ios-whatsapp-android.md +568 -0
  795. package/dist/data/designs/ios-whatsapp-expo.md +502 -0
  796. package/dist/data/designs/ios-whatsapp-swiftui.md +483 -0
  797. package/dist/data/designs/ios-whatsapp.md +425 -0
  798. package/dist/data/designs/ios-whoop-android.md +635 -0
  799. package/dist/data/designs/ios-whoop-expo.md +562 -0
  800. package/dist/data/designs/ios-whoop-swiftui.md +553 -0
  801. package/dist/data/designs/ios-whoop.md +419 -0
  802. package/dist/data/designs/ios-wise-android.md +428 -0
  803. package/dist/data/designs/ios-wise-expo.md +357 -0
  804. package/dist/data/designs/ios-wise-swiftui.md +356 -0
  805. package/dist/data/designs/ios-wise.md +361 -0
  806. package/dist/data/designs/ios-x-twitter-android.md +618 -0
  807. package/dist/data/designs/ios-x-twitter-expo.md +442 -0
  808. package/dist/data/designs/ios-x-twitter-swiftui.md +429 -0
  809. package/dist/data/designs/ios-x-twitter.md +432 -0
  810. package/dist/data/designs/ios-yelp-android.md +455 -0
  811. package/dist/data/designs/ios-yelp-expo.md +397 -0
  812. package/dist/data/designs/ios-yelp-swiftui.md +369 -0
  813. package/dist/data/designs/ios-yelp.md +398 -0
  814. package/dist/data/designs/ios-youtube-android.md +668 -0
  815. package/dist/data/designs/ios-youtube-expo.md +435 -0
  816. package/dist/data/designs/ios-youtube-music-android.md +450 -0
  817. package/dist/data/designs/ios-youtube-music-expo.md +404 -0
  818. package/dist/data/designs/ios-youtube-music-swiftui.md +434 -0
  819. package/dist/data/designs/ios-youtube-music.md +381 -0
  820. package/dist/data/designs/ios-youtube-swiftui.md +496 -0
  821. package/dist/data/designs/ios-youtube.md +466 -0
  822. package/dist/data/designs/ios-zalo-android.md +510 -0
  823. package/dist/data/designs/ios-zalo-expo.md +389 -0
  824. package/dist/data/designs/ios-zalo-swiftui.md +431 -0
  825. package/dist/data/designs/ios-zalo.md +388 -0
  826. package/dist/data/designs/ios-zomato-android.md +527 -0
  827. package/dist/data/designs/ios-zomato-expo.md +437 -0
  828. package/dist/data/designs/ios-zomato-swiftui.md +433 -0
  829. package/dist/data/designs/ios-zomato.md +439 -0
  830. package/dist/data/designs/ios-zoom-android.md +423 -0
  831. package/dist/data/designs/ios-zoom-expo.md +355 -0
  832. package/dist/data/designs/ios-zoom-swiftui.md +379 -0
  833. package/dist/data/designs/ios-zoom.md +357 -0
  834. package/dist/data/designs/ios-zwift-android.md +402 -0
  835. package/dist/data/designs/ios-zwift-expo.md +402 -0
  836. package/dist/data/designs/ios-zwift-swiftui.md +378 -0
  837. package/dist/data/designs/ios-zwift.md +411 -0
  838. package/dist/data/designs/kraken.md +125 -0
  839. package/dist/data/designs/lamborghini.md +288 -0
  840. package/dist/data/designs/linear.app.md +548 -0
  841. package/dist/data/designs/lovable.md +298 -0
  842. package/dist/data/designs/mastercard.md +365 -0
  843. package/dist/data/designs/material-clean.md +289 -0
  844. package/dist/data/designs/meta.md +683 -0
  845. package/dist/data/designs/midnight-pro.md +256 -0
  846. package/dist/data/designs/minimal-brutalist.md +245 -0
  847. package/dist/data/designs/minimax.md +746 -0
  848. package/dist/data/designs/mintlify.md +852 -0
  849. package/dist/data/designs/miro.md +825 -0
  850. package/dist/data/designs/mistral.ai.md +773 -0
  851. package/dist/data/designs/mongodb.md +767 -0
  852. package/dist/data/designs/nike.md +575 -0
  853. package/dist/data/designs/nintendo-2001.md +649 -0
  854. package/dist/data/designs/notion.md +821 -0
  855. package/dist/data/designs/nova-mobile-design-md.md +235 -0
  856. package/dist/data/designs/nvidia.md +640 -0
  857. package/dist/data/designs/ollama.md +539 -0
  858. package/dist/data/designs/opencode.ai.md +521 -0
  859. package/dist/data/designs/pinterest.md +597 -0
  860. package/dist/data/designs/playful-color.md +253 -0
  861. package/dist/data/designs/playstation.md +661 -0
  862. package/dist/data/designs/posthog.md +690 -0
  863. package/dist/data/designs/raycast.md +669 -0
  864. package/dist/data/designs/renault.md +589 -0
  865. package/dist/data/designs/replicate.md +616 -0
  866. package/dist/data/designs/resend.md +585 -0
  867. package/dist/data/designs/revolut.md +636 -0
  868. package/dist/data/designs/runwayml.md +244 -0
  869. package/dist/data/designs/sanity.md +357 -0
  870. package/dist/data/designs/sentry.md +551 -0
  871. package/dist/data/designs/shopify.md +516 -0
  872. package/dist/data/designs/slack.md +482 -0
  873. package/dist/data/designs/soft-glass.md +258 -0
  874. package/dist/data/designs/spacex.md +363 -0
  875. package/dist/data/designs/spotify.md +246 -0
  876. package/dist/data/designs/starbucks.md +580 -0
  877. package/dist/data/designs/stripe.md +487 -0
  878. package/dist/data/designs/supabase.md +462 -0
  879. package/dist/data/designs/superhuman.md +448 -0
  880. package/dist/data/designs/tesla.md +286 -0
  881. package/dist/data/designs/theverge.md +339 -0
  882. package/dist/data/designs/together.ai.md +633 -0
  883. package/dist/data/designs/uber.md +636 -0
  884. package/dist/data/designs/vercel.md +736 -0
  885. package/dist/data/designs/vodafone.md +538 -0
  886. package/dist/data/designs/voltagent.md +521 -0
  887. package/dist/data/designs/warp.md +526 -0
  888. package/dist/data/designs/webflow.md +588 -0
  889. package/dist/data/designs/wired.md +497 -0
  890. package/dist/data/designs/wise.md +544 -0
  891. package/dist/data/designs/x.ai.md +465 -0
  892. package/dist/data/designs/zapier.md +537 -0
  893. package/dist/data/index.json +2600 -0
  894. package/dist/httpServer.js +83 -0
  895. package/dist/index.js +13 -0
  896. package/dist/server.js +32 -0
  897. package/dist/services/designStore.js +59 -0
  898. package/dist/services/linter.js +87 -0
  899. package/dist/services/sectionParser.js +154 -0
  900. package/dist/tools/authoring.js +131 -0
  901. package/dist/tools/browse.js +232 -0
  902. package/dist/tools/diff.js +88 -0
  903. package/dist/tools/getDesign.js +216 -0
  904. package/dist/tools/guardrails.js +87 -0
  905. package/dist/tools/lint.js +104 -0
  906. package/dist/types.js +1 -0
  907. package/package.json +65 -0
@@ -0,0 +1,341 @@
1
+ # Apple TV (iOS) — Expo / React Native Implementation Guide
2
+
3
+ Companion to [DESIGN.md](DESIGN.md) — the framework-neutral spec. This file translates the Apple TV app's visual language into paste-ready Expo / React Native code: a design-token module, themed components, and Reanimated snippets. The browse experience is true-black.
4
+
5
+ Assumes Expo SDK 51+ with `expo-router`, `expo-font`, `expo-haptics`, `expo-linear-gradient`, `expo-blur`, and `react-native-reanimated` v3.
6
+
7
+ ## 1. Color Tokens
8
+
9
+ ```ts
10
+ // theme/colors.ts
11
+ export const colors = {
12
+ // Canvas & surfaces (true-black product)
13
+ canvas: '#000000',
14
+ surface1: '#1C1C1E',
15
+ surface2: '#2C2C2E',
16
+ divider: '#38383A',
17
+
18
+ // Text (iOS dark label ramp)
19
+ textPrimary: '#FFFFFF',
20
+ textSecondary: '#98989F',
21
+ textTertiary: '#636366',
22
+
23
+ // Primary CTA (always white)
24
+ cta: '#FFFFFF',
25
+ ctaPressed: '#E5E5EA',
26
+ ctaLabel: '#000000',
27
+
28
+ // Accent (the only one — iOS dark systemBlue)
29
+ blue: '#0A84FF',
30
+ bluePressed: '#0060DF',
31
+
32
+ // iOS translucent control fill (secondary buttons, search base)
33
+ glassFill: 'rgba(120,120,128,0.36)',
34
+
35
+ // Semantic
36
+ mls: '#ED1A6F', // MLS Season Pass ONLY
37
+ live: '#FF453A',
38
+ success: '#30D158',
39
+ gold: '#FFD60A',
40
+ } as const;
41
+
42
+ export const gradients = {
43
+ heroScrim: ['transparent', 'rgba(0,0,0,0.65)', 'rgba(0,0,0,0.92)'],
44
+ } as const;
45
+
46
+ export type AppleTVColor = keyof typeof colors;
47
+ ```
48
+
49
+ ## 2. Typography
50
+
51
+ The brand face is **SF Pro**. On iOS, React Native's default `System` font already resolves to SF Pro (use `fontFamily: undefined` or omit it). For Android / cross-platform parity, bundle **Inter** (SIL OFL) via `expo-font`.
52
+
53
+ ```tsx
54
+ // app/_layout.tsx
55
+ import { Platform } from 'react-native';
56
+ import { useFonts } from 'expo-font';
57
+
58
+ export default function Root() {
59
+ // On iOS the system font IS SF Pro — only load Inter for Android parity
60
+ const [loaded] = useFonts(
61
+ Platform.OS === 'android'
62
+ ? {
63
+ 'Inter-Regular': require('../assets/fonts/Inter-Regular.ttf'),
64
+ 'Inter-Medium': require('../assets/fonts/Inter-Medium.ttf'),
65
+ 'Inter-SemiBold': require('../assets/fonts/Inter-SemiBold.ttf'),
66
+ 'Inter-Bold': require('../assets/fonts/Inter-Bold.ttf'),
67
+ 'Inter-ExtraBold': require('../assets/fonts/Inter-ExtraBold.ttf'),
68
+ }
69
+ : {},
70
+ );
71
+ if (!loaded) return null;
72
+ return <Stack screenOptions={{ contentStyle: { backgroundColor: '#000000' } }} />;
73
+ }
74
+ ```
75
+
76
+ ```ts
77
+ // theme/typography.ts
78
+ import { Platform, type TextStyle } from 'react-native';
79
+
80
+ // On iOS: System (SF Pro). On Android: bundled Inter.
81
+ const ff = (w: 'Regular' | 'Medium' | 'SemiBold' | 'Bold' | 'ExtraBold') =>
82
+ Platform.OS === 'android' ? { fontFamily: `Inter-${w}` } : {};
83
+
84
+ const white = { color: '#FFFFFF' } satisfies TextStyle;
85
+
86
+ export const typography = {
87
+ largeTitle: { ...white, ...ff('ExtraBold'), fontSize: 34, lineHeight: 36, letterSpacing: -0.8, fontWeight: '800' },
88
+ heroTitle: { ...white, ...ff('ExtraBold'), fontSize: 28, lineHeight: 30, letterSpacing: -0.6, fontWeight: '800' },
89
+ rowHeader: { ...white, ...ff('Bold'), fontSize: 22, lineHeight: 26, letterSpacing: -0.3, fontWeight: '700' },
90
+ title3: { ...white, ...ff('SemiBold'), fontSize: 20, lineHeight: 25, letterSpacing: -0.2, fontWeight: '600' },
91
+ body: { ...white, ...ff('Regular'), fontSize: 17, lineHeight: 25, fontWeight: '400' },
92
+ headline: { ...white, ...ff('SemiBold'), fontSize: 15, lineHeight: 20, fontWeight: '600' },
93
+ subhead: { color: '#98989F', ...ff('Regular'), fontSize: 13, lineHeight: 18, fontWeight: '400' },
94
+ caption: { ...white, ...ff('Medium'), fontSize: 12, lineHeight: 14, fontWeight: '500' },
95
+ eyebrow: { color: '#98989F', ...ff('Bold'), fontSize: 11, lineHeight: 11, letterSpacing: 1.2, fontWeight: '700', textTransform: 'uppercase' as const },
96
+ button: { ...white, ...ff('SemiBold'), fontSize: 15, lineHeight: 15, fontWeight: '600' },
97
+ channelTag: { ...white, ...ff('Bold'), fontSize: 9, lineHeight: 9, letterSpacing: 0.4, fontWeight: '700' },
98
+ } satisfies Record<string, TextStyle>;
99
+ ```
100
+
101
+ ## 3. Signature Components
102
+
103
+ ### Inset Rounded Hero Card
104
+
105
+ ```tsx
106
+ // components/HeroCard.tsx
107
+ import { ImageBackground, Pressable, Text, View } from 'react-native';
108
+ import { LinearGradient } from 'expo-linear-gradient';
109
+ import { BlurView } from 'expo-blur';
110
+ import Ionicons from '@expo/vector-icons/Ionicons';
111
+ import { colors, gradients } from '../theme/colors';
112
+ import { typography } from '../theme/typography';
113
+
114
+ export function HeroCard({
115
+ art, eyebrow, title, meta, onPlay, onAdd,
116
+ }: { art: string; eyebrow: string; title: string; meta: string; onPlay: () => void; onAdd: () => void }) {
117
+ return (
118
+ <View style={{ marginHorizontal: 14, borderRadius: 16, overflow: 'hidden' }}>
119
+ <ImageBackground source={{ uri: art }} style={{ height: 380, justifyContent: 'flex-end' }}>
120
+ <LinearGradient
121
+ colors={gradients.heroScrim}
122
+ locations={[0.4, 0.72, 1]}
123
+ style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }}
124
+ />
125
+ <View style={{ padding: 18, gap: 7 }}>
126
+ <Text style={typography.eyebrow}>{eyebrow}</Text>
127
+ <Text style={typography.heroTitle}>{title}</Text>
128
+ <Text style={[typography.caption, { color: colors.textSecondary }]}>{meta}</Text>
129
+ <View style={{ flexDirection: 'row', gap: 10, marginTop: 7 }}>
130
+ <Pressable
131
+ onPress={onPlay}
132
+ style={({ pressed }) => ({
133
+ flexDirection: 'row', alignItems: 'center', gap: 7,
134
+ backgroundColor: pressed ? colors.ctaPressed : colors.cta,
135
+ paddingVertical: 13, paddingHorizontal: 30, borderRadius: 12,
136
+ })}
137
+ >
138
+ <Text style={[typography.button, { color: colors.ctaLabel }]}>▶ Play</Text>
139
+ </Pressable>
140
+ <Pressable onPress={onAdd} style={{ width: 44, height: 44, borderRadius: 22, overflow: 'hidden' }}>
141
+ <BlurView intensity={28} tint="dark" style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
142
+ <Ionicons name="add" size={20} color="#fff" />
143
+ </BlurView>
144
+ </Pressable>
145
+ </View>
146
+ </View>
147
+ </ImageBackground>
148
+ </View>
149
+ );
150
+ }
151
+ ```
152
+
153
+ ### Up Next Thumbnail (16:9 + resume bar)
154
+
155
+ ```tsx
156
+ // components/UpNextThumb.tsx
157
+ import { Image, Pressable, Text, View } from 'react-native';
158
+ import { BlurView } from 'expo-blur';
159
+ import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';
160
+ import { colors } from '../theme/colors';
161
+ import { typography } from '../theme/typography';
162
+
163
+ export function UpNextThumb({
164
+ art, title, subhead, progress = 0, channelTag = 'Apple TV+',
165
+ }: { art: string; title: string; subhead: string; progress?: number; channelTag?: string | null }) {
166
+ const scale = useSharedValue(1);
167
+ const aStyle = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }] }));
168
+ return (
169
+ <Pressable
170
+ onPressIn={() => (scale.value = withTiming(0.97, { duration: 120 }))}
171
+ onPressOut={() => (scale.value = withTiming(1, { duration: 120 }))}
172
+ style={{ width: 196 }}
173
+ >
174
+ <Animated.View style={aStyle}>
175
+ <View style={{ width: 196, height: 110, borderRadius: 10, overflow: 'hidden' }}>
176
+ <Image source={{ uri: art }} style={{ width: '100%', height: '100%' }} />
177
+ {channelTag ? (
178
+ <View style={{ position: 'absolute', top: 8, left: 8, borderRadius: 5, overflow: 'hidden' }}>
179
+ <BlurView intensity={20} tint="dark" style={{ paddingHorizontal: 6, paddingVertical: 3 }}>
180
+ <Text style={typography.channelTag}>{channelTag}</Text>
181
+ </BlurView>
182
+ </View>
183
+ ) : null}
184
+ {progress > 0 ? (
185
+ <View style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 4, backgroundColor: 'rgba(255,255,255,0.28)' }}>
186
+ <View style={{ width: `${progress * 100}%`, height: '100%', backgroundColor: '#fff' }} />
187
+ </View>
188
+ ) : null}
189
+ </View>
190
+ <Text style={[typography.headline, { marginTop: 8 }]} numberOfLines={1}>{title}</Text>
191
+ <Text style={[typography.subhead, { marginTop: 2 }]} numberOfLines={1}>{subhead}</Text>
192
+ </Animated.View>
193
+ </Pressable>
194
+ );
195
+ }
196
+ ```
197
+
198
+ ### Live Badge & MLS Chip
199
+
200
+ ```tsx
201
+ // components/Badges.tsx
202
+ import { useEffect } from 'react';
203
+ import { Text, View } from 'react-native';
204
+ import Animated, { useSharedValue, useAnimatedStyle, withRepeat, withTiming } from 'react-native-reanimated';
205
+ import { colors } from '../theme/colors';
206
+ import { typography } from '../theme/typography';
207
+
208
+ export function LiveBadge() {
209
+ const o = useSharedValue(1);
210
+ useEffect(() => { o.value = withRepeat(withTiming(0.4, { duration: 1200 }), -1, true); }, []);
211
+ const dot = useAnimatedStyle(() => ({ opacity: o.value }));
212
+ return (
213
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, backgroundColor: colors.live, borderRadius: 6, paddingHorizontal: 10, paddingVertical: 5 }}>
214
+ <Animated.View style={[{ width: 7, height: 7, borderRadius: 4, backgroundColor: '#fff' }, dot]} />
215
+ <Text style={[typography.eyebrow, { color: '#fff', letterSpacing: 0.6 }]}>LIVE</Text>
216
+ </View>
217
+ );
218
+ }
219
+
220
+ export function MLSChip({ title }: { title: string }) {
221
+ // #ED1A6F is the ONLY non-system brand color — MLS Season Pass surfaces only
222
+ return (
223
+ <View style={{ backgroundColor: colors.mls, borderRadius: 10, paddingHorizontal: 14, paddingVertical: 7 }}>
224
+ <Text style={[typography.caption, { fontWeight: '700' }]}>{title}</Text>
225
+ </View>
226
+ );
227
+ }
228
+ ```
229
+
230
+ ### Shelf Header
231
+
232
+ ```tsx
233
+ // components/ShelfHeader.tsx
234
+ import { Text, View } from 'react-native';
235
+ import Ionicons from '@expo/vector-icons/Ionicons';
236
+ import { colors } from '../theme/colors';
237
+ import { typography } from '../theme/typography';
238
+
239
+ export function ShelfHeader({ title, accessory }: { title: string; accessory?: React.ReactNode }) {
240
+ return (
241
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 18, paddingBottom: 10 }}>
242
+ <Text style={typography.rowHeader}>{title}</Text>
243
+ {accessory}
244
+ <View style={{ flex: 1 }} />
245
+ <Ionicons name="chevron-forward" size={16} color={colors.textTertiary} />
246
+ </View>
247
+ );
248
+ }
249
+ ```
250
+
251
+ ## 4. Bottom Tab Bar
252
+
253
+ ```tsx
254
+ // app/(tabs)/_layout.tsx
255
+ import { Tabs } from 'expo-router';
256
+ import { BlurView } from 'expo-blur';
257
+ import Ionicons from '@expo/vector-icons/Ionicons';
258
+ import { colors } from '../../theme/colors';
259
+
260
+ export default function TabsLayout() {
261
+ return (
262
+ <Tabs
263
+ screenOptions={{
264
+ headerShown: false,
265
+ tabBarActiveTintColor: colors.blue, // system blue active
266
+ tabBarInactiveTintColor: colors.textTertiary,
267
+ tabBarStyle: { position: 'absolute', borderTopWidth: 0.33, borderTopColor: colors.divider, backgroundColor: 'transparent' },
268
+ tabBarBackground: () => <BlurView intensity={40} tint="dark" style={{ flex: 1 }} />,
269
+ tabBarLabelStyle: { fontSize: 12, fontWeight: '500' },
270
+ }}
271
+ >
272
+ <Tabs.Screen name="index" options={{ title: 'Watch Now', tabBarIcon: ({ color }) => <Ionicons name="play" size={24} color={color} /> }} />
273
+ <Tabs.Screen name="tvplus" options={{ title: 'TV+', tabBarIcon: ({ color }) => <Ionicons name="tv" size={24} color={color} /> }} />
274
+ <Tabs.Screen name="store" options={{ title: 'Store', tabBarIcon: ({ color }) => <Ionicons name="bag" size={24} color={color} /> }} />
275
+ <Tabs.Screen name="search" options={{ title: 'Search', tabBarIcon: ({ color }) => <Ionicons name="search" size={24} color={color} /> }} />
276
+ </Tabs>
277
+ );
278
+ }
279
+ ```
280
+
281
+ ## 5. Motion
282
+
283
+ ```tsx
284
+ // Thumbnail press — scale 0.97
285
+ scale.value = withTiming(0.97, { duration: 120 }); // onPressIn
286
+ scale.value = withTiming(1, { duration: 120 }); // onPressOut
287
+
288
+ // Live dot pulse
289
+ o.value = withRepeat(withTiming(0.4, { duration: 1200 }), -1, true);
290
+
291
+ // Hero cross-fade (~10s, if multiple) — FadeIn/FadeOut between featured (400ms)
292
+ import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
293
+ // key={featuredIndex} entering={FadeIn.duration(400)} exiting={FadeOut.duration(400)}
294
+
295
+ // Large title — use expo-router Stack large header OR a manual collapse driven by scroll offset
296
+
297
+ // Detail open — expo-router push / Modal (use system-feeling default 350ms transition)
298
+
299
+ // Resume bar appears at value (no fill animation — it's state, not feedback)
300
+
301
+ // Haptics — sparing, system feel
302
+ import * as Haptics from 'expo-haptics';
303
+ Haptics.selectionAsync(); // thumbnail tap
304
+ ```
305
+
306
+ ## 6. Icon Library
307
+
308
+ Use `@expo/vector-icons` (Ionicons) — its glyphs read close to SF Symbols. The Apple TV logomark should be a bundled SVG (`react-native-svg`), not an icon-font glyph.
309
+
310
+ | Purpose | Ionicons |
311
+ |---------|----------|
312
+ | Watch Now | `play` / `play-circle` |
313
+ | TV+ | `tv` |
314
+ | Store | `bag` |
315
+ | Search | `search` |
316
+ | MLS (when subscribed) | `football` / `trophy` |
317
+ | Play (CTA) | `play` |
318
+ | Add | `add` / `checkmark` |
319
+ | Back | `chevron-back` |
320
+ | More / disclosure | `chevron-forward` |
321
+ | Download | `arrow-down-circle-outline` |
322
+ | AirPlay / Cast | `tv-outline` |
323
+ | Profile | (avatar) / `person-circle-outline` |
324
+ | Live | `radio-outline` |
325
+ | Trailer | `play-circle-outline` |
326
+ | Info | `information-circle-outline` |
327
+ | Settings | `settings-outline` |
328
+
329
+ ## 7. Platform Notes
330
+
331
+ - **Font choice**: on iOS the default `System` font IS SF Pro — do not override `fontFamily`; only bundle **Inter** (SIL OFL) for Android parity. SF Pro itself is not redistributable off-platform
332
+ - **True-black**: set `contentStyle.backgroundColor = '#000000'`, `<StatusBar style="light" />`, and lock dark — the browse experience is always true-black; only embedded Store/account sheets follow system appearance
333
+ - **Inset hero**: the hero is `marginHorizontal: 14` + `borderRadius: 16` + `overflow: 'hidden'` — NOT full-bleed; this floating treatment is the signature; do not remove the inset
334
+ - **Glass chrome**: use `expo-blur` `BlurView` (`tint="dark"`) for the tab bar background and channel tags; on Android blur is weaker — fall back to `rgba(0,0,0,0.92)` solid for the tab bar
335
+ - **Resume bar**: render at the watched fraction with no animation — it is persistent state, not progress feedback
336
+ - **Rows bleed off the right edge**: horizontal `FlatList`/`ScrollView` `contentContainerStyle={{ paddingHorizontal: 18 }}`; let the last thumbnail clip — the "more content" affordance
337
+ - **Safe area**: wrap screens in `SafeAreaView`; the hero card sits below the large title; the absolute glass tab bar needs bottom safe-area padding and content padding so shelves scroll behind it
338
+ - **Dynamic Type**: `<Text>` honors system scale; set `allowFontScaling={false}` on tab labels, channel tags, eyebrows, "LIVE"
339
+ - **Accessibility**: label Up Next thumbnails "{title}, {subhead}, {progress}% watched"; mark the pulsing live dot `accessibilityElementsHidden`; the white CTA reads "Play {title}"
340
+ - **Reduce motion / transparency**: gate the hero cross-fade and live-dot pulse behind `AccessibilityInfo.isReduceMotionEnabled()`; swap `BlurView` chrome for opaque `#000000` when `isReduceTransparencyEnabled()`
341
+ - **MLS pink**: `#ED1A6F` is the ONLY non-system brand color — MLS Season Pass surfaces only; everything else is monochrome + the blue link accent
@@ -0,0 +1,348 @@
1
+ # Apple TV (iOS) — SwiftUI Implementation Guide
2
+
3
+ Companion to [DESIGN.md](DESIGN.md) — the framework-neutral spec. This file translates the Apple TV app's visual language into paste-ready SwiftUI code: `Color` extensions, `Font` extensions, `ViewModifier`s, and example views. The browse experience is true-black; only embedded Store/account sheets follow system appearance.
4
+
5
+ ## 1. Color Tokens
6
+
7
+ ```swift
8
+ import SwiftUI
9
+
10
+ extension Color {
11
+ // MARK: - Canvas & Surfaces (true-black product)
12
+ static let atvCanvas = Color.black // #000000
13
+ static let atvSurface1 = Color(red: 0.110, green: 0.110, blue: 0.118) // #1C1C1E
14
+ static let atvSurface2 = Color(red: 0.173, green: 0.173, blue: 0.180) // #2C2C2E
15
+ static let atvDivider = Color(red: 0.220, green: 0.220, blue: 0.227) // #38383A
16
+
17
+ // MARK: - Text (iOS dark label ramp)
18
+ static let atvTextPrimary = Color.white // #FFFFFF
19
+ static let atvTextSecondary = Color(red: 0.596, green: 0.596, blue: 0.624) // #98989F
20
+ static let atvTextTertiary = Color(red: 0.388, green: 0.388, blue: 0.400) // #636366
21
+
22
+ // MARK: - Primary CTA (always white)
23
+ static let atvCTA = Color.white // #FFFFFF
24
+ static let atvCTAPressed = Color(red: 0.898, green: 0.898, blue: 0.918) // #E5E5EA
25
+ static let atvCTALabel = Color.black // #000000
26
+
27
+ // MARK: - Accent (the only one — iOS dark systemBlue)
28
+ static let atvBlue = Color(red: 0.039, green: 0.518, blue: 1.000) // #0A84FF
29
+ static let atvBluePressed = Color(red: 0.000, green: 0.376, blue: 0.875) // #0060DF
30
+
31
+ // MARK: - Semantic
32
+ static let atvMLS = Color(red: 0.929, green: 0.102, blue: 0.435) // #ED1A6F (MLS only)
33
+ static let atvLive = Color(red: 1.000, green: 0.271, blue: 0.227) // #FF453A
34
+ static let atvSuccess = Color(red: 0.188, green: 0.820, blue: 0.345) // #30D158
35
+ static let atvGold = Color(red: 1.000, green: 0.839, blue: 0.039) // #FFD60A
36
+ }
37
+
38
+ extension Color {
39
+ /// iOS translucent control fill — secondary buttons, search field base.
40
+ static let atvGlassFill = Color(red: 0.471, green: 0.471, blue: 0.502).opacity(0.36)
41
+ }
42
+
43
+ extension LinearGradient {
44
+ /// Hero card bottom scrim.
45
+ static let atvHeroScrim = LinearGradient(
46
+ stops: [
47
+ .init(color: .clear, location: 0.40),
48
+ .init(color: .black.opacity(0.65), location: 0.72),
49
+ .init(color: .black.opacity(0.92), location: 1.0),
50
+ ],
51
+ startPoint: .top, endPoint: .bottom
52
+ )
53
+ }
54
+ ```
55
+
56
+ ## 2. Typography
57
+
58
+ The brand face is **SF Pro** — prefer `-apple-system` on iOS (it resolves to SF Pro and respects optical sizing + Dynamic Type automatically). For a non-Apple build, bundle **Inter** (SIL OFL) as the substitute.
59
+
60
+ ```swift
61
+ extension Font {
62
+ // Prefer system styles on iOS — they ARE SF Pro with optical sizing + Dynamic Type
63
+ static let atvLargeTitle = Font.system(size: 34, weight: .heavy, design: .default)
64
+ static let atvHeroTitle = Font.system(size: 28, weight: .heavy, design: .default)
65
+ static let atvRowHeader = Font.system(size: 22, weight: .bold, design: .default)
66
+ static let atvTitle3 = Font.system(size: 20, weight: .semibold, design: .default)
67
+ static let atvBody = Font.system(size: 17, weight: .regular, design: .default)
68
+ static let atvHeadline = Font.system(size: 15, weight: .semibold, design: .default)
69
+ static let atvSubhead = Font.system(size: 13, weight: .regular, design: .default)
70
+ static let atvCaption = Font.system(size: 12, weight: .medium, design: .default)
71
+ static let atvEyebrow = Font.system(size: 11, weight: .bold, design: .default)
72
+ static let atvButton = Font.system(size: 15, weight: .semibold, design: .default)
73
+ static let atvChannelTag = Font.system(size: 9, weight: .bold, design: .default)
74
+
75
+ // Non-Apple build (Inter substitute):
76
+ // static let atvLargeTitle = Font.custom("Inter-ExtraBold", size: 34)
77
+ }
78
+
79
+ // Eyebrow modifier — 11pt uppercase tracked, secondary
80
+ struct ATVEyebrow: ViewModifier {
81
+ func body(content: Content) -> some View {
82
+ content
83
+ .font(.atvEyebrow)
84
+ .tracking(1.2)
85
+ .textCase(.uppercase)
86
+ .foregroundStyle(Color.atvTextSecondary)
87
+ }
88
+ }
89
+ extension View { func atvEyebrow() -> some View { modifier(ATVEyebrow()) } }
90
+ ```
91
+
92
+ ## 3. Signature Components
93
+
94
+ ### Inset Rounded Hero Card
95
+
96
+ ```swift
97
+ struct HeroCard: View {
98
+ let artURL: URL?
99
+ let eyebrow: String // "Apple TV+ · New Episode"
100
+ let title: String
101
+ let meta: String
102
+ let onPlay: () -> Void
103
+ let onAdd: () -> Void
104
+
105
+ var body: some View {
106
+ ZStack(alignment: .bottomLeading) {
107
+ AsyncImage(url: artURL) { img in
108
+ img.resizable().aspectRatio(contentMode: .fill)
109
+ } placeholder: {
110
+ Rectangle().fill(Color.atvSurface1)
111
+ }
112
+ .frame(height: 380)
113
+ .clipped()
114
+
115
+ LinearGradient.atvHeroScrim
116
+
117
+ VStack(alignment: .leading, spacing: 7) {
118
+ Text(eyebrow).atvEyebrow()
119
+ Text(title).font(.atvHeroTitle).foregroundStyle(Color.atvTextPrimary)
120
+ Text(meta).font(.atvCaption).foregroundStyle(Color.atvTextSecondary)
121
+ HStack(spacing: 10) {
122
+ Button(action: onPlay) {
123
+ Label("Play", systemImage: "play.fill")
124
+ .font(.atvButton)
125
+ .foregroundStyle(Color.atvCTALabel)
126
+ .padding(.vertical, 13).padding(.horizontal, 30)
127
+ .background(Color.atvCTA, in: RoundedRectangle(cornerRadius: 12))
128
+ }
129
+ Button(action: onAdd) {
130
+ Image(systemName: "plus")
131
+ .font(.system(size: 18, weight: .semibold))
132
+ .foregroundStyle(.white)
133
+ .frame(width: 44, height: 44)
134
+ .background(.ultraThinMaterial, in: Circle())
135
+ }
136
+ }
137
+ .padding(.top, 7)
138
+ }
139
+ .padding(18)
140
+ }
141
+ .frame(height: 380)
142
+ .clipShape(RoundedRectangle(cornerRadius: 16)) // inset + rounded = floating gallery
143
+ .padding(.horizontal, 14)
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### Up Next Thumbnail (16:9 + resume bar)
149
+
150
+ ```swift
151
+ struct UpNextThumb: View {
152
+ let artURL: URL?
153
+ let title: String
154
+ let subhead: String // "S3 E8 · 24 min left"
155
+ var progress: Double = 0 // 0...1; 0 hides the bar
156
+ var channelTag: String? = "Apple TV+"
157
+ @State private var pressed = false
158
+
159
+ var body: some View {
160
+ VStack(alignment: .leading, spacing: 8) {
161
+ ZStack(alignment: .topLeading) {
162
+ AsyncImage(url: artURL) { $0.resizable().aspectRatio(contentMode: .fill) }
163
+ placeholder: { Rectangle().fill(Color.atvSurface1) }
164
+ .frame(width: 196, height: 110)
165
+ .clipShape(RoundedRectangle(cornerRadius: 10))
166
+
167
+ if let channelTag {
168
+ Text(channelTag)
169
+ .font(.atvChannelTag).tracking(0.4)
170
+ .foregroundStyle(.white)
171
+ .padding(.horizontal, 6).padding(.vertical, 3)
172
+ .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 5))
173
+ .padding(8)
174
+ }
175
+ if progress > 0 {
176
+ GeometryReader { geo in
177
+ ZStack(alignment: .leading) {
178
+ Rectangle().fill(Color.white.opacity(0.28))
179
+ Rectangle().fill(Color.white).frame(width: geo.size.width * progress)
180
+ }
181
+ .frame(height: 4)
182
+ .frame(maxHeight: .infinity, alignment: .bottom)
183
+ }
184
+ .frame(width: 196, height: 110)
185
+ }
186
+ }
187
+ Text(title).font(.atvHeadline).foregroundStyle(Color.atvTextPrimary).lineLimit(1)
188
+ Text(subhead).font(.atvSubhead).foregroundStyle(Color.atvTextSecondary).lineLimit(1)
189
+ }
190
+ .frame(width: 196)
191
+ .scaleEffect(pressed ? 0.97 : 1)
192
+ .animation(.easeOut(duration: 0.12), value: pressed)
193
+ ._onButtonGesture { pressed = $0 } perform: {}
194
+ }
195
+ }
196
+ ```
197
+
198
+ ### Live Badge & MLS Chip
199
+
200
+ ```swift
201
+ struct LiveBadge: View {
202
+ @State private var dim = false
203
+ var body: some View {
204
+ HStack(spacing: 6) {
205
+ Circle().fill(.white).frame(width: 7, height: 7)
206
+ .opacity(dim ? 0.4 : 1)
207
+ .animation(.easeInOut(duration: 1.2).repeatForever(autoreverses: true), value: dim)
208
+ Text("LIVE").font(.atvEyebrow).tracking(0.6).foregroundStyle(.white)
209
+ }
210
+ .padding(.horizontal, 10).padding(.vertical, 5)
211
+ .background(Color.atvLive, in: RoundedRectangle(cornerRadius: 6))
212
+ .onAppear { dim = true }
213
+ }
214
+ }
215
+
216
+ struct MLSChip: View {
217
+ let title: String // "MLS Season Pass"
218
+ var body: some View {
219
+ Text(title)
220
+ .font(.system(size: 12, weight: .bold))
221
+ .foregroundStyle(.white)
222
+ .padding(.horizontal, 14).padding(.vertical, 7)
223
+ .background(Color.atvMLS, in: RoundedRectangle(cornerRadius: 10)) // the ONLY non-system color
224
+ }
225
+ }
226
+ ```
227
+
228
+ ### Shelf Header
229
+
230
+ ```swift
231
+ struct ShelfHeader: View {
232
+ let title: String
233
+ var accessory: AnyView? = nil
234
+ var body: some View {
235
+ HStack(spacing: 8) {
236
+ Text(title).font(.atvRowHeader).foregroundStyle(Color.atvTextPrimary)
237
+ if let accessory { accessory }
238
+ Spacer()
239
+ Image(systemName: "chevron.right")
240
+ .font(.system(size: 16, weight: .semibold))
241
+ .foregroundStyle(Color.atvTextTertiary)
242
+ }
243
+ .padding(.horizontal, 18)
244
+ .padding(.bottom, 10)
245
+ }
246
+ }
247
+ ```
248
+
249
+ ## 4. Bottom Tab Bar
250
+
251
+ ```swift
252
+ struct AppleTVTabView: View {
253
+ init() {
254
+ let a = UITabBarAppearance()
255
+ a.configureWithDefaultBackground() // translucent blur material
256
+ a.backgroundColor = UIColor.black.withAlphaComponent(0.92)
257
+ a.shadowColor = UIColor(Color.atvDivider)
258
+ UITabBar.appearance().standardAppearance = a
259
+ UITabBar.appearance().scrollEdgeAppearance = a
260
+ }
261
+
262
+ var body: some View {
263
+ TabView {
264
+ WatchNowView().tabItem { Label("Watch Now", systemImage: "play.tv") }
265
+ TVPlusView().tabItem { Label("TV+", systemImage: "play.rectangle.on.rectangle") }
266
+ StoreView().tabItem { Label("Store", systemImage: "bag") }
267
+ SearchView().tabItem { Label("Search", systemImage: "magnifyingglass") }
268
+ }
269
+ .tint(.atvBlue) // active = system blue; standard iOS color+fill swap, no pill
270
+ }
271
+ }
272
+ ```
273
+
274
+ ## 5. Motion
275
+
276
+ ```swift
277
+ // Thumbnail press
278
+ .scaleEffect(pressed ? 0.97 : 1)
279
+ .animation(.easeOut(duration: 0.12), value: pressed)
280
+
281
+ // Live dot pulse
282
+ .opacity(dim ? 0.4 : 1)
283
+ .animation(.easeInOut(duration: 1.2).repeatForever(autoreverses: true), value: dim)
284
+
285
+ // Hero cross-fade between featured (~10s, if multiple)
286
+ .transition(.opacity)
287
+ .animation(.easeInOut(duration: 0.4), value: featuredIndex)
288
+
289
+ // Large title collapse — use a NavigationStack with .navigationTitle + .navigationBarTitleDisplayMode(.large)
290
+ // (system handles the large→inline transition tied to scroll)
291
+
292
+ // Detail open — standard iOS push or .sheet (system 350ms transition; no custom shared element)
293
+ .sheet(item: $selected) { DetailView(item: $0) }
294
+
295
+ // Resume bar appears at value (no fill animation — it's state, not feedback)
296
+
297
+ // Haptics — sparing, system only
298
+ let g = UISelectionFeedbackGenerator(); g.selectionChanged() // thumbnail tap
299
+ ```
300
+
301
+ ## 6. SF Symbols Used
302
+
303
+ | Component | Symbol | Size |
304
+ |-----------|--------|------|
305
+ | Watch Now (tab) | `play.tv` / `play.tv.fill` | 24pt |
306
+ | TV+ (tab) | `play.rectangle.on.rectangle` / `.fill` | 24pt |
307
+ | Store (tab) | `bag` / `bag.fill` | 24pt |
308
+ | Search (tab) | `magnifyingglass` | 24pt |
309
+ | MLS (tab, when subscribed) | `sportscourt` / `soccerball` | 24pt |
310
+ | Play (CTA) | `play.fill` | 14pt |
311
+ | Add to Watchlist | `plus` / `checkmark` | 18pt |
312
+ | Back | `chevron.left` | system |
313
+ | More / disclosure | `chevron.right` | 16pt |
314
+ | Download | `arrow.down.circle` / `.fill` | 20pt |
315
+ | Cast / AirPlay | `airplayvideo` | 22pt |
316
+ | Profile | (avatar image) / `person.crop.circle` | 30pt |
317
+ | Live indicator | `dot.radiowaves.left.and.right` | 14pt |
318
+ | Trailer | `play.rectangle` | 16pt |
319
+ | Info | `info.circle` | 18pt |
320
+ | Settings | `gearshape` | 22pt |
321
+
322
+ ## 7. Dark Mode
323
+
324
+ ```swift
325
+ struct AppleTVTheme: ViewModifier {
326
+ func body(content: Content) -> some View {
327
+ content
328
+ .background(Color.atvCanvas) // pure #000000
329
+ .foregroundStyle(Color.atvTextPrimary)
330
+ .preferredColorScheme(.dark) // browse is always true-black
331
+ }
332
+ }
333
+ extension View { func appleTVTheme() -> some View { modifier(AppleTVTheme()) } }
334
+ ```
335
+
336
+ The browse experience is **always true-black** — lock `.preferredColorScheme(.dark)` on the tab root. Only embedded Store / account `.sheet`s should drop the override and follow the system appearance (they are standard iOS surfaces). Depth comes from the inset rounded hero floating on `#000` plus iOS `.ultraThinMaterial` chrome — there are no drop shadows in browse.
337
+
338
+ ## 8. Minimum iOS & Accessibility Notes
339
+
340
+ - Minimum target: iOS 16 (`AsyncImage`, `.ultraThinMaterial`, `Label`, `NavigationStack` are comfortable; `.sensoryFeedback` needs iOS 17 — fall back to `UISelectionFeedbackGenerator`)
341
+ - **Prefer the system font**: use `Font.system(...)` / `-apple-system` on iOS — it IS SF Pro with optical sizing and Dynamic Type for free; only bundle Inter (SIL OFL) for non-Apple targets (SF Pro itself is not redistributable off-platform)
342
+ - Dynamic Type: rely on `.font(.largeTitle)` / `.body` text styles so everything scales per HIG; keep tab labels, channel tags, eyebrows, "LIVE" at FIXED sizes (layout-sensitive over art)
343
+ - VoiceOver: label Up Next thumbnails "{title}, {subhead}, {progress}% watched"; the white CTA "Play {title}"; live cards "Live now"; group hero eyebrow+title+meta as one element
344
+ - The pulsing live dot is decorative — mark `.accessibilityHidden(true)`; convey "Live" via the badge label
345
+ - Color contrast: white `#FFFFFF` and `#98989F` on `#000000` pass WCAG AA; the white CTA with black label passes AAA; `#0A84FF` is the system link color (AA on black); the MLS pink `#ED1A6F` with white passes AA
346
+ - Reduce Motion: disable the hero cross-fade and the live-dot pulse (static dot); keep the press scale subtle or remove; rely on system reduce-motion for transitions
347
+ - Reduce Transparency: when enabled, swap `.ultraThinMaterial` chrome for an opaque `Color.atvCanvas` tab bar (system does this automatically for UITabBar)
348
+ - Dark mode: browse is always true-black; do not invert. Only embedded Store/account sheets follow system light/dark