{{-- Pricing cards. The cards are the LIVE plans (Admin → Plans), not landing copy: a price on the public page is a promise, so it is read from the same row the reseller is actually charged from. Only the heading stays landing-editable and carries [data-lp] markers; the cards moved, so the Studio no longer patches them (same move as sections/faq.blade.php). The old hand-written `plans` JSON stays in panels.landing, dormant. --}} @php // Owner-only. A reseller sells services, not memberships, so their storefront // must never offer the owner's plans. sections.blade.php already drops this // block from a reseller's running order; the guard here makes the leak // impossible by construction, whatever route renders the partial. $isOwner = $isOwnerPanel ?? true; // Plan is owner-global (no panel scope): is_public is the "show it on the // landing" switch, status is the "still sold at all" switch, and `sort` is // the order the owner arranged in Admin → Plans. $lpPlans = $isOwner ? \App\Models\Plan::query() ->where('is_public', true) ->where('status', true) ->orderBy('sort') ->orderBy('id') ->get() : collect(); // MOST POPULAR = the cheapest PAID tier: the first plan, in the owner's own // order, whose price is above zero. It needs no extra column, it cannot go // stale when plans are added or reordered, and it lands where a visitor // expects the recommendation — the step up from free. An all-free lineup // crowns nothing rather than badging a $0 tier as the popular choice. $lpFeaturedId = $lpPlans->first(fn ($p) => (float) $p->price > 0)?->id; // With signups closed, /register bounces straight back here; offer the door // that is actually open. $lpCtaUrl = ($disableSignup ?? false) ? route('login') : route('register'); $lpPill = 'display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:999px;font-size:11.5px;font-weight:600;line-height:1.5;'; @endphp @if ($lpPlans->isNotEmpty())
{{ data_get($c, 'pricing_heading.eyebrow') }}

{{ data_get($c, 'pricing_heading.title') }}

{{ data_get($c, 'pricing_heading.subtitle') }}

@foreach ($lpPlans as $plan) @php $feat = $plan->id === $lpFeaturedId; $isFree = (float) $plan->price <= 0; // Brand ink is unreadable on the featured card's dark // ground; lighten it exactly as the check icons do. $accent = $feat ? 'color-mix(in srgb, var(--lp-brand) 55%, #fff)' : 'var(--lp-brand)'; // The owner's marketing lines for this tier. A plan with // none falls back to its description, so a card is never // a bare price. $lines = $plan->highlights() ?: array_filter([$plan->description]); @endphp
@if ($feat){{ __('Most popular') }}@endif
{{ $plan->name }}
{{-- The tier difference a visitor can scan in one pass: where the supply comes from, and whether they can try it before paying. Same words as the reseller's own billing screen (components/admin/plan-perks) so a tier never describes itself differently once they sign up. --}}
@if ($plan->ownProviders()) {{ __('Your own supplier') }} @else {{ __('Catalogue only') }} @endif @if ($plan->trial_days > 0) {{ __(':days-day free trial', ['days' => $plan->trial_days]) }} @endif
{{-- A $0 tier reads "Free", not "$0.00" — the same number, but an offer instead of an invoice. The period goes with it: free does not renew. --}}
{{ $isFree ? __('Free') : money($plan->price, $plan->currency) }} @unless ($isFree) {{ \App\Support\Plans\BillingPeriod::publicSuffix($plan->billing_period) }} @endunless
    @foreach ($lines as $line)
  • @include('frontend.partials.icon', ['name' => 'check', 'size' => 16, 'sw' => 2.6]){{ $line }}
  • @endforeach
{{ $isFree ? __('Start free') : ($plan->trial_days > 0 ? __('Start free trial') : __('Get started')) }}
@endforeach
@endif