diff --git a/packages/docs/index.html b/packages/docs/index.html index e571854e..3275b3d3 100644 --- a/packages/docs/index.html +++ b/packages/docs/index.html @@ -10,7 +10,7 @@ OpenIAP - Unified Specification for In-App Purchases - + @@ -35,6 +35,10 @@ + + + + diff --git a/packages/docs/public/robots.txt b/packages/docs/public/robots.txt index f92e563a..20ded555 100644 --- a/packages/docs/public/robots.txt +++ b/packages/docs/public/robots.txt @@ -1,4 +1,20 @@ User-agent: * Allow: / -Sitemap: https://openiap.dev/sitemap.xml \ No newline at end of file +Sitemap: https://openiap.dev/sitemap.xml + +# AI Assistants / LLM Crawlers +# Reference: https://llmstxt.org/ +User-agent: GPTBot +User-agent: ChatGPT-User +User-agent: Claude-Web +User-agent: Anthropic-AI +User-agent: PerplexityBot +User-agent: Google-Extended +Allow: / +Allow: /llms.txt +Allow: /llms-full.txt + +# LLM context files for AI assistants +# llms.txt: https://openiap.dev/llms.txt (concise overview) +# llms-full.txt: https://openiap.dev/llms-full.txt (detailed reference) \ No newline at end of file diff --git a/packages/docs/public/sitemap.xml b/packages/docs/public/sitemap.xml index 9dd1d9cd..83953621 100644 --- a/packages/docs/public/sitemap.xml +++ b/packages/docs/public/sitemap.xml @@ -2,31 +2,31 @@ https://openiap.dev/ - 2025-11-26 + 2026-02-11 weekly 1.0 https://openiap.dev/introduction - 2025-11-26 + 2026-02-11 weekly 0.9 https://openiap.dev/languages - 2025-11-26 + 2026-02-11 monthly 0.8 https://openiap.dev/tutorials - 2025-11-26 + 2026-02-11 weekly 0.8 https://openiap.dev/sponsors - 2025-11-26 + 2026-02-11 monthly 0.7 @@ -34,43 +34,43 @@ https://openiap.dev/docs/ecosystem - 2025-11-26 + 2026-02-11 weekly 0.9 https://openiap.dev/docs/lifecycle - 2025-11-26 + 2026-02-11 weekly 0.9 https://openiap.dev/docs/lifecycle/subscription - 2025-11-26 + 2026-02-11 weekly 0.8 https://openiap.dev/docs/types - 2025-11-26 + 2026-02-11 weekly 0.9 https://openiap.dev/docs/apis - 2025-11-26 + 2026-02-11 weekly 0.9 https://openiap.dev/docs/events - 2025-11-26 + 2026-02-11 weekly 0.8 https://openiap.dev/docs/errors - 2025-11-26 + 2026-02-11 monthly 0.7 @@ -78,19 +78,19 @@ https://openiap.dev/docs/ios-setup - 2025-11-26 + 2026-02-11 monthly 0.8 https://openiap.dev/docs/android-setup - 2025-11-26 + 2026-02-11 monthly 0.8 https://openiap.dev/docs/horizon-setup - 2025-11-26 + 2026-02-11 monthly 0.7 @@ -98,31 +98,31 @@ https://openiap.dev/docs/features/purchase - 2025-11-26 + 2026-02-11 weekly 0.8 https://openiap.dev/docs/features/subscription - 2025-11-26 + 2026-02-11 weekly 0.8 https://openiap.dev/docs/features/offer-code-redemption - 2025-11-26 + 2026-02-11 monthly 0.7 https://openiap.dev/docs/features/external-purchase - 2025-11-26 + 2026-02-11 weekly 0.8 https://openiap.dev/docs/features/subscription-upgrade-downgrade - 2025-11-26 + 2026-02-11 monthly 0.7 @@ -130,19 +130,19 @@ https://openiap.dev/docs/updates/announcements - 2025-11-26 + 2026-02-11 weekly 0.7 https://openiap.dev/docs/updates/notes - 2025-11-26 + 2026-02-11 weekly 0.7 https://openiap.dev/docs/updates/versions - 2025-11-26 + 2026-02-11 weekly 0.7 diff --git a/packages/docs/src/components/SEO.tsx b/packages/docs/src/components/SEO.tsx index cbaaa022..c38cd752 100644 --- a/packages/docs/src/components/SEO.tsx +++ b/packages/docs/src/components/SEO.tsx @@ -5,17 +5,51 @@ interface SEOProps { description?: string; path?: string; keywords?: string; + type?: 'website' | 'article'; + image?: string; + includeAppSchema?: boolean; } const BASE_URL = 'https://openiap.dev'; const DEFAULT_TITLE = 'OpenIAP - Unified Specification for In-App Purchases'; const DEFAULT_DESCRIPTION = 'OpenIAP is a unified specification for in-app purchases across platforms, frameworks, and emerging technologies. Standardizing IAP implementations to reduce fragmentation.'; +const DEFAULT_IMAGE = '/og-image.png'; -function SEO({ title, description, path = '', keywords }: SEOProps) { +function SEO({ + title, + description, + path = '', + keywords, + type = 'website', + image, + includeAppSchema = false, +}: SEOProps) { const pageTitle = title ? `${title} | OpenIAP` : DEFAULT_TITLE; const pageDescription = description || DEFAULT_DESCRIPTION; const canonicalUrl = `${BASE_URL}${path}`; + const imageUrl = `${BASE_URL}${image || DEFAULT_IMAGE}`; + + // Schema.org structured data for SoftwareApplication + const schemaOrg = { + '@context': 'https://schema.org', + '@type': 'SoftwareApplication', + name: 'OpenIAP', + description: pageDescription, + url: canonicalUrl, + applicationCategory: 'DeveloperApplication', + operatingSystem: 'iOS, Android, visionOS, Horizon OS', + offers: { + '@type': 'Offer', + price: '0', + priceCurrency: 'USD', + }, + author: { + '@type': 'Organization', + name: 'OpenIAP', + url: BASE_URL, + }, + }; return ( @@ -26,14 +60,24 @@ function SEO({ title, description, path = '', keywords }: SEOProps) { {/* Open Graph */} + + + {/* Twitter */} - - - + + + + + + + {/* Schema.org JSON-LD */} + {includeAppSchema && ( + + )} ); } diff --git a/packages/docs/src/pages/404.tsx b/packages/docs/src/pages/404.tsx index 3f582c68..80929e22 100644 --- a/packages/docs/src/pages/404.tsx +++ b/packages/docs/src/pages/404.tsx @@ -1,6 +1,7 @@ import { Link } from 'react-router-dom'; import { Home, ArrowLeft } from 'lucide-react'; import { useEffect, useState } from 'react'; +import SEO from '../components/SEO'; export default function NotFound() { const [isDark, setIsDark] = useState(false); @@ -22,15 +23,21 @@ export default function NotFound() { }, []); return ( -
+ <> + +
+ ); } diff --git a/packages/docs/src/pages/docs/android-setup.tsx b/packages/docs/src/pages/docs/android-setup.tsx index 927ddd22..fd5dbce7 100644 --- a/packages/docs/src/pages/docs/android-setup.tsx +++ b/packages/docs/src/pages/docs/android-setup.tsx @@ -5,9 +5,9 @@ function AndroidSetup() {

Android Setup Guide

diff --git a/packages/docs/src/pages/docs/apis/index.tsx b/packages/docs/src/pages/docs/apis/index.tsx index 69751437..ad26903e 100644 --- a/packages/docs/src/pages/docs/apis/index.tsx +++ b/packages/docs/src/pages/docs/apis/index.tsx @@ -98,9 +98,9 @@ function APIsIndex() {

APIs

diff --git a/packages/docs/src/pages/docs/ecosystem.tsx b/packages/docs/src/pages/docs/ecosystem.tsx index 8590f12b..27c32161 100644 --- a/packages/docs/src/pages/docs/ecosystem.tsx +++ b/packages/docs/src/pages/docs/ecosystem.tsx @@ -10,8 +10,9 @@ function Ecosystem() {

Ecosystem

diff --git a/packages/docs/src/pages/docs/errors.tsx b/packages/docs/src/pages/docs/errors.tsx index 512d997f..567fdea7 100644 --- a/packages/docs/src/pages/docs/errors.tsx +++ b/packages/docs/src/pages/docs/errors.tsx @@ -12,9 +12,9 @@ function Errors() {

Error Codes

diff --git a/packages/docs/src/pages/docs/events.tsx b/packages/docs/src/pages/docs/events.tsx index bb7d4f0d..c7f7cf6c 100644 --- a/packages/docs/src/pages/docs/events.tsx +++ b/packages/docs/src/pages/docs/events.tsx @@ -12,9 +12,9 @@ function Events() {

Events

diff --git a/packages/docs/src/pages/docs/horizon-setup.tsx b/packages/docs/src/pages/docs/horizon-setup.tsx index b6d8c442..96c8fcde 100644 --- a/packages/docs/src/pages/docs/horizon-setup.tsx +++ b/packages/docs/src/pages/docs/horizon-setup.tsx @@ -6,9 +6,9 @@ function HorizonSetup() {

Horizon OS Setup Guide

diff --git a/packages/docs/src/pages/docs/types/index.tsx b/packages/docs/src/pages/docs/types/index.tsx index 74e392f9..03e9c464 100644 --- a/packages/docs/src/pages/docs/types/index.tsx +++ b/packages/docs/src/pages/docs/types/index.tsx @@ -231,9 +231,9 @@ function TypesIndex() {

- +

- Unifying fragmented IAP implementations across platforms, - frameworks, and emerging technologies + Stop rewriting IAP code for every platform. One API for iOS, + Android, Vision Pro, and Meta Quest.

+ {/* Quick Stats */} +
+ + {/* Aggregate stars across ecosystem repos - update periodically */} +
4K+
+
Combined Stars
+ +
+
5+
+
Framework Libraries
+
+
Get Started @@ -141,6 +159,42 @@ function Home() {
+ {/* Key Benefits */} +
+
+

Why Developers Choose OpenIAP

+

+ Build revenue-generating features faster with less code +

+
+
+
1x
+

Learn Once

+

+ Master one API instead of learning different patterns for iOS, + Android, and every framework +

+
+
+
0
+

Runtime Errors

+

+ Type-safe generated code catches mistakes at compile time, not + in production +

+
+
+
100%
+

Platform Features

+

+ Full access to StoreKit 2 and Play Billing v8 — no features + hidden or abstracted away +

+
+
+
+
+

The Problem We're Solving

@@ -202,21 +256,10 @@ function Home() {

-

- XR-Compatible{' '} - - (WIP) - -

+

XR-Compatible

- Horizon OS, Android XR, Vision Pro - new realities need - purchases. OpenIAP is ready for the spatial computing era. + Horizon OS and Vision Pro supported. Android XR coming soon. + OpenIAP is ready for the spatial computing era.

diff --git a/packages/docs/src/pages/introduction.tsx b/packages/docs/src/pages/introduction.tsx index 7e116300..fabb56a0 100644 --- a/packages/docs/src/pages/introduction.tsx +++ b/packages/docs/src/pages/introduction.tsx @@ -1,170 +1,576 @@ +import { Link } from 'react-router-dom'; import SEO from '../components/SEO'; +import CodeBlock from '../components/CodeBlock'; function Introduction() { return (
-

Introduction to OpenIAP

- -
-

What is OpenIAP?

-

- OpenIAP is an open specification that standardizes in-app purchase - implementations across diverse platforms and frameworks. As the IAP - ecosystem becomes increasingly fragmented with new platforms - (StoreKit 2, Android Billing v8, Vision Pro, Horizon OS) and - frameworks (React Native, Flutter, KMP), OpenIAP provides a unified - specification that reduces complexity and ensures consistency. -

-
+ {/* Title */} +

Why OpenIAP

+

+ OpenIAP is a unified specification for in-app purchases across iOS, + Android, and XR platforms. One GraphQL schema generates type-safe + native code for Swift, Kotlin, TypeScript, Dart, and GDScript. +

+ {/* The Problem */}

The Problem

-

- Every new platform and framework creates its own IAP implementation. - Library maintainers independently design APIs, leading to fragmented - specifications. Developers must learn different APIs for each - platform, increasing complexity and errors. As new technologies - emerge - XR platforms, cross-platform frameworks, and emerging - payment systems - this fragmentation only grows worse. +

+ In-app purchase implementations are fragmented across platforms and + frameworks. Each library defines its own API surface, type + definitions, and event patterns. This creates several challenges:

-

- In the AI coding era, this fragmentation becomes even more - problematic. AI assistants struggle to generate consistent code when - every library has different patterns, making IAP implementation - unnecessarily complex and error-prone. +

    +
  • + Inconsistent APIs — Method names, parameter + structures, and return types differ between{' '} + react-native-iap, flutter_inapp_purchase + , and other libraries +
  • +
  • + Duplicated effort — Library maintainers + independently solve the same problems (transaction handling, error + codes, subscription lifecycle) +
  • +
  • + Platform drift — When Apple adds StoreKit 2 + features or Google updates Play Billing, each library implements + changes differently +
  • +
  • + AI limitations — AI assistants cannot generate + reliable IAP code because no two libraries work the same way +
  • +
+

+ New platforms like{' '} + + Vision Pro + {' '} + and Horizon OS compound this + fragmentation.

+ {/* The Solution */}
-

Our Solution

- -

Unified APIs

-

- OpenIAP defines standard methods like initConnection(),{' '} - fetchProducts(),requestPurchase(), and{' '} - finishTransaction() that work consistently across all - platforms. Library maintainers implement these standard APIs, - ensuring developers have a consistent experience. +

The Solution

+

+ OpenIAP provides a single source of truth for IAP implementations. + The specification defines:

- -

Standard Events

-

- Event handling is standardized with patterns like{' '} - purchaseUpdatedListener and - purchaseErrorListener. No more platform-specific event - names or handling patterns - just consistent, predictable events - across all implementations. -

- -

Unified Types

-

- Common data structures like Product,{' '} - Purchase, and PurchaseError - are defined once and used everywhere. This ensures type safety and - reduces the cognitive load on developers switching between - platforms. -

-
- -
-

Why Now?

-
    +
    • - Platform Explosion: iOS StoreKit 2, Android - Billing v8, and new XR platforms are creating more fragmentation - than ever + Unified API methods —{' '} + + initConnection() + + ,{' '} + + fetchProducts() + + ,{' '} + + requestPurchase() + + ,{' '} + + finishTransaction() +
    • - Framework Diversity: React Native, Flutter, - Kotlin Multiplatform, and emerging frameworks each need IAP - support + Shared type definitions —{' '} + + Product + + ,{' '} + + Purchase + + ,{' '} + + SubscriptionPeriod + + ,{' '} + + PurchaseError +
    • - AI Coding Era: Standardized APIs are crucial for - AI assistants to generate reliable, consistent IAP code + Standard event patterns —{' '} + + purchaseUpdatedListener + + ,{' '} + + purchaseErrorListener +
    • - Developer Experience: Reducing cognitive load by - providing one specification to learn instead of dozens -
    • -
    • - Community Collaboration: Library maintainers can - focus on implementation quality rather than API design + Platform-aware naming — Cross-platform types use + no suffix, platform-specific use IOS/ + Android suffix
+ {/* Architecture */}
-

Who's Using OpenIAP?

-

- Leading IAP libraries are already implementing the OpenIAP - specification: +

Architecture

+

+ OpenIAP uses a schema-driven approach. A single GraphQL schema + defines all types and operations, which are then generated into + native code for each target platform.

-
    -
  • + +
    + + OpenIAP Architecture - GraphQL schema generates native modules + +

    + View ecosystem documentation → +

    +
    + +

    Code Generation

    +

    + The{' '} + + openiap-gql + {' '} + package contains the GraphQL schema and generators. Running{' '} + bun run generate produces: +

    +
    +
    +              {`packages/apple/Sources/Models/Types.swift    # Swift types
    +packages/google/openiap/src/main/Types.kt    # Kotlin types
    +src/generated/types.ts                       # TypeScript types
    +src/generated/types.dart                     # Dart types
    +src/generated/types.gd                       # GDScript types`}
    +            
    +
    + +

    Native Modules

    +

    + Two native modules implement the specification on top of platform + APIs: +

    +
    +
    - react-native-iap + openiap-apple - : - {' '} - React Native & Expo implementation (Nitro Modules) -
  • -
  • - + +

    + Swift module built on{' '} - expo-iap + StoreKit 2 - : - {' '} - React Native & Expo implementation (Expo Modules) -

  • -
  • + . Supports iOS 15+, macOS 12+, visionOS 1.0+. +

    +
+
- flutter_inapp_purchase + openiap-google - : - {' '} - Flutter implementation - -
  • - + +

    + Kotlin module built on{' '} - kmp-iap + Play Billing v8 - : - {' '} - Kotlin Multiplatform implementation -

  • - -

    - These libraries demonstrate that OpenIAP's unified approach works in - practice, providing consistent APIs while leveraging - platform-specific capabilities. + . Supports Android 5.0+ (API 21+). +

    +
    +
    + + + {/* API Design */} +
    +

    API Design

    + +

    Naming Conventions

    +

    + OpenIAP uses consistent naming across all implementations: +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    ScopePatternExample
    Cross-platform + functionName + + fetchProducts(), requestPurchase() +
    iOS-only + functionNameIOS + + syncIOS(), getStorefrontIOS() +
    Android-only + functionNameAndroid + + acknowledgePurchaseAndroid() +
    +
    + +

    Type Safety

    +

    + Generated types ensure compile-time safety. Platform-specific fields + use suffixes to prevent accidental cross-platform usage: +

    + + {`// Cross-platform fields (no suffix) +interface Product { + id: string; + title: string; + price: string; + priceAmount: number; + currency: string; +} + +// Platform-specific fields (with suffix) +interface Purchase { + productId: string; + transactionId: string; + // iOS-specific + originalTransactionIdIOS?: string; + // Android-specific + purchaseTokenAndroid?: string; + orderIdAndroid?: string; +}`} + +
    + + {/* Purchase Flow */} +
    +

    Purchase Flow

    +

    + The standard purchase flow works identically across all OpenIAP + implementations: +

    + + {`// 1. Initialize connection +await initConnection(); + +// 2. Set up listeners (event-based, not promise-based) +const subscription = purchaseUpdatedListener(async (purchase) => { + // 3. Verify on your server + const verified = await verifyPurchase(purchase); + + // 4. Grant entitlement + if (verified) { + await grantAccess(purchase.productId); + } + + // 5. Acknowledge the purchase + // Android: auto-refunds after 3 days if not acknowledged + await finishTransaction(purchase, isConsumable); +}); + +// 6. Fetch products +const products = await fetchProducts({ + products: [ + { id: 'com.app.premium', type: 'inapp' }, + { id: 'com.app.monthly', type: 'subs' }, + ], +}); + +// 7. Request purchase (result comes via listener) +await requestPurchase({ + request: { + apple: { sku: 'com.app.premium' }, + google: { skus: ['com.app.premium'] }, + }, + type: 'inapp', +}); + +// 8. Cleanup on unmount +subscription.remove(); +await endConnection();`} + +

    + See Purchase Lifecycle for + detailed flow documentation. +

    +
    + + {/* Supported Platforms */} +
    +

    Supported Platforms

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PlatformBilling APIMin Version
    iOS + + StoreKit 2 + + iOS 15.0+
    macOSStoreKit 2macOS 12.0+
    visionOSStoreKit 2visionOS 1.0+
    Android + + Play Billing v8 + + API 21+ (5.0)
    Meta Quest + Horizon OS + Quest 2+
    +
    +
    + + {/* Framework Implementations */} +
    +

    Framework Implementations

    +

    + Production-ready libraries implementing the OpenIAP specification: +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LibraryFrameworkBridge
    + + react-native-iap + + React Native + + Nitro Modules + +
    + + expo-iap + + Expo + + Expo Modules + +
    + + flutter_inapp_purchase + + Flutter + + Pigeon + +
    + + kmp-iap + + Kotlin Multiplatform + + K/N Interop + +
    + + godot-iap + + Godot 4.x + + GDExtension + +
    +
    +

    + View all implementations → +

    +
    + + {/* Getting Started */} +
    +

    Getting Started

    +

    + Choose your framework to get started:

    +
    + + API Reference +

    Core methods and patterns

    + + + Type Definitions +

    Generated types for all languages

    + + + Purchase Lifecycle +

    Transaction flow diagrams

    + + + Tutorials +

    Step-by-step guides

    + +
    diff --git a/packages/docs/src/pages/languages.tsx b/packages/docs/src/pages/languages.tsx index 56662b16..c714ad25 100644 --- a/packages/docs/src/pages/languages.tsx +++ b/packages/docs/src/pages/languages.tsx @@ -6,9 +6,9 @@ function Languages() {

    OpenIAP Implementations

    diff --git a/packages/docs/src/pages/sponsors.tsx b/packages/docs/src/pages/sponsors.tsx index 268de961..b86128b0 100644 --- a/packages/docs/src/pages/sponsors.tsx +++ b/packages/docs/src/pages/sponsors.tsx @@ -6,8 +6,9 @@ function Sponsors() {

    Support OpenIAP

    diff --git a/packages/docs/src/pages/tutorials.tsx b/packages/docs/src/pages/tutorials.tsx index 28574669..249c224a 100644 --- a/packages/docs/src/pages/tutorials.tsx +++ b/packages/docs/src/pages/tutorials.tsx @@ -9,9 +9,9 @@ function Tutorials() {

    Tutorials

    diff --git a/packages/docs/src/styles/code.css b/packages/docs/src/styles/code.css index 91bf6573..4743ab68 100644 --- a/packages/docs/src/styles/code.css +++ b/packages/docs/src/styles/code.css @@ -9,8 +9,8 @@ pre.code-block { overflow-x: auto; overflow-y: hidden; font-family: 'SF Mono', 'Monaco', 'Consolas', 'Liberation Mono', monospace; - font-size: var(--font-size-sm); - line-height: 1.5; + font-size: 0.9375rem; + line-height: 1.6; margin: var(--spacing-md) 0; position: relative; scrollbar-width: thin; @@ -164,7 +164,7 @@ pre code { padding: 0; white-space: pre; display: block; - font-size: var(--font-size-sm); + font-size: 0.9375rem; border-radius: 0; } diff --git a/packages/docs/src/styles/home.css b/packages/docs/src/styles/home.css index 8d004c8e..f84cf342 100644 --- a/packages/docs/src/styles/home.css +++ b/packages/docs/src/styles/home.css @@ -356,10 +356,16 @@ color: var(--text-primary); } +.section-title { + text-align: center; + margin-bottom: 0.5rem; +} + .section-subtitle { font-size: 1.125rem; color: var(--text-secondary); - margin-bottom: 3rem; + margin-bottom: 2rem; + text-align: center; } /* Specification Grid */ @@ -557,3 +563,64 @@ a.spec-item:hover code { :root:not(.dark) .benefit p { color: #333333; } + +/* Quick Stats Section */ +.quick-stats { + display: flex; + justify-content: center; + gap: 2.5rem; + margin-bottom: 1.5rem; + flex-wrap: wrap; +} + +.quick-stats-item { + text-decoration: none; + text-align: center; +} + +.quick-stats-value { + font-size: 1.5rem; + font-weight: 700; + color: var(--primary-color); +} + +.quick-stats-label { + font-size: 0.75rem; + color: var(--text-secondary); +} + +/* Key Benefits Section */ +.key-benefits { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 1.5rem; + max-width: 900px; + margin: 0 auto; +} + +.key-benefit-card { + padding: 2rem; + background: var(--bg-secondary); + border-radius: 12px; + border: 1px solid var(--border-color); + text-align: center; +} + +.key-benefit-value { + font-size: 2.5rem; + font-weight: 700; + color: var(--primary-color); + margin-bottom: 0.5rem; +} + +.key-benefit-card h3 { + margin: 0 0 0.5rem; + font-size: 1.1rem; +} + +.key-benefit-card p { + margin: 0; + font-size: 0.9rem; + color: var(--text-secondary); + line-height: 1.6; +} diff --git a/packages/docs/src/styles/pages.css b/packages/docs/src/styles/pages.css index 19c919dc..56bcc509 100644 --- a/packages/docs/src/styles/pages.css +++ b/packages/docs/src/styles/pages.css @@ -372,6 +372,155 @@ text-decoration-color: rgba(143, 199, 227, 0.6); } +/* Introduction page specific styles */ +.intro-lead { + font-size: 1.15rem; + color: var(--text-secondary); + margin-bottom: 2.5rem; + line-height: 1.7; +} + +.intro-text { + font-size: 1.05rem; + line-height: 1.8; + margin-bottom: 1.5rem; +} + +.intro-text-secondary { + font-size: 1.05rem; + line-height: 1.8; + color: var(--text-secondary); +} + +.intro-text-note { + font-size: 1.05rem; + line-height: 1.8; + color: var(--text-secondary); + margin-top: 1rem; +} + +.intro-list { + font-size: 1.05rem; + line-height: 1.8; + margin-bottom: 1.5rem; + padding-left: 1.5rem; +} + +.intro-list li { + margin-bottom: 0.75rem; +} + +.intro-image-container { + margin: 1.5rem 0; + text-align: center; +} + +.intro-image { + max-width: 100%; + height: auto; + border-radius: 8px; + border: 1px solid var(--border-color); +} + +.intro-image-caption { + font-size: 0.85rem; + color: var(--text-secondary); + margin-top: 0.75rem; +} + +.intro-code-output { + background: var(--bg-secondary); + border-radius: 8px; + padding: 1rem; + font-family: var(--font-mono); + font-size: 1rem; + overflow-x: auto; + margin-bottom: 1.5rem; + border: 1px solid var(--border-color); +} + +.intro-code-output pre { + margin: 0; +} + +.native-module-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 1rem; + margin-bottom: 1rem; +} + +.native-module-card { + padding: 1rem; + background: var(--bg-secondary); + border-radius: 8px; + border: 1px solid var(--border-color); +} + +.native-module-card strong { + color: var(--text-primary); +} + +.native-module-card p { + margin: 0.5rem 0 0; + font-size: 1rem; + color: var(--text-secondary); +} + +.intro-table-wrapper { + overflow-x: auto; + margin-bottom: 1.5rem; +} + +.intro-table { + width: 100%; + border-collapse: collapse; + font-size: 1rem; +} + +.intro-table thead tr { + border-bottom: 2px solid var(--border-color); + text-align: left; +} + +.intro-table th, +.intro-table td { + padding: 0.75rem 1rem; +} + +.intro-table tbody tr { + border-bottom: 1px solid var(--border-color); +} + +.getting-started-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-bottom: 1.5rem; +} + +.getting-started-card { + display: block; + padding: 1rem; + background: var(--bg-secondary); + border-radius: 8px; + border: 1px solid var(--border-color); + text-decoration: none; + color: var(--text-primary); + transition: transform 0.2s, box-shadow 0.2s; +} + +.getting-started-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgb(0 0 0 / 8%); +} + +.getting-started-card p { + margin: 0.25rem 0 0; + font-size: 0.85rem; + color: var(--text-secondary); +} + .platform-links { display: flex; gap: 1rem;