@php
$__locale = app()->getLocale();
$__locales = config('locales.supported', ['en' => ['name' => 'English', 'flag' => '🇬🇧', 'rtl' => false]]);
$__isRtl = (bool) ($__locales[$__locale]['rtl'] ?? false);
// Operator-editable SEO meta + Open Graph / Twitter card image.
//
// Set at /super-admin/landing-page-editor → SEO tab (LandingContent.seo_*).
// Every field is optional: when empty the layout keeps the stock translator
// string / bundled brand image it rendered before, so a fresh OR unmigrated
// install is unchanged. (The previous code read GeneralSettings::og_image_url,
// a property that never existed on that class, so the OG image was never
// actually operator-settable.) try/catch keeps this green if the settings
// table isn't migrated yet.
try {
$__lcSeo = app(\App\Settings\LandingContent::class);
$seoTitle = trim((string) ($__lcSeo->seo_meta_title ?? ''));
$seoDescription = trim((string) ($__lcSeo->seo_meta_description ?? ''));
$seoKeywords = trim((string) ($__lcSeo->seo_meta_keywords ?? ''));
$seoOgImage = trim((string) ($__lcSeo->seo_og_image_url ?? ''));
} catch (\Throwable) {
$seoTitle = $seoDescription = $seoKeywords = $seoOgImage = '';
}
$ogImage = $seoOgImage !== '' ? $seoOgImage : url('/leadhub-brand.svg');
// SA-global branding overrides for the public marketing site.
// BrandingSettings.logo_url / favicon_url are set at
// /super-admin/branding. When unset (or the settings table isn't
// migrated yet) we fall back to the bundled /favicon.svg so a fresh
// install still renders a mark. Customer report: "logo dont change
// on the whole site" — the public pages used to hardcode favicon.svg
// and never read the operator's uploaded logo.
try {
$__brand = app(\App\Settings\BrandingSettings::class);
$brandLogo = \App\Support\PublicMedia::url($__brand->logo_url) ?? '/favicon.svg';
$brandFavicon = \App\Support\PublicMedia::url($__brand->favicon_url) ?? '/favicon.svg';
} catch (\Throwable) {
$brandLogo = '/favicon.svg';
$brandFavicon = '/favicon.svg';
}
@endphp
@yield('title', $seoTitle !== '' ? $seoTitle : $appName)
@if($seoKeywords !== '')
@endif
{{-- No explicit type= so an operator-uploaded PNG / ICO favicon is
sniffed correctly (the bundled default is still an SVG). --}}
{{-- Follow an operator-uploaded favicon; fall back to the bundled PNG when
none is set ($brandFavicon defaults to the bundled /favicon.svg). --}}
{{-- Inter font self-hosted under public/vendor/ — no Google Fonts
CDN load. Loaded as a at the top of so the
font-display: swap in @font-face fires before the page paints. --}}
{{-- Open Graph --}}
{{-- Twitter Card --}}
{{-- JSON-LD schema. The array is built inside a PHP block first
so the JSON-LD keys that start with the at sign do not collide
with Blade directives during compile. The encoded result is
then echoed raw into the script tag. --}}
@php
$__jsonLd = [
'CONTEXT_KEY' => 'https://schema.org',
'TYPE_KEY' => 'SoftwareApplication',
'applicationCategory' => 'BusinessApplication',
'operatingSystem' => 'Web',
'description' => __('marketing.jsonld_description'),
'offers' => [
'TYPE_KEY' => 'Offer',
'price' => '0',
'priceCurrency' => 'USD',
'description' => __('marketing.jsonld_offer_description'),
],
];
// Swap placeholder keys back to the @ form via a recursive walk
// because Blade's directive matcher treats '@context' / '@type'
// as directive calls when they appear inline in the template.
$__jsonLdSwap = static function (array $arr) use (&$__jsonLdSwap): array {
$out = [];
foreach ($arr as $k => $v) {
$k = $k === 'CONTEXT_KEY' ? '@context' : ($k === 'TYPE_KEY' ? '@type' : $k);
$out[$k] = is_array($v) ? $__jsonLdSwap($v) : $v;
}
return $out;
};
@endphp
{{-- Defense-in-depth: JSON_HEX_TAG escapes `<` and `>` as
`<` / `>` so a translator-edited `__('marketing.jsonld_description')`
string containing `` cannot close this
@stack('head')
@php
// Landing content drives nav visibility toggles; null = show.
$lc = app(\App\Settings\LandingContent::class);
// Custom static pages (About, Contact, etc.) for the marketing nav.
// Fresh query per request instead of Cache::remember — a stale
// cache entry with a wrong-shape payload was causing runtime
// "Attempt to read property 'slug' on string" errors when the
// iteration variable deserialised as a plain string. The one
// extra SELECT per landing-page view is cheap; the bug isn't.
$navStaticPages = \App\Models\StaticPage::forNav()
->get(['id', 'slug', 'title', 'translations']);
@endphp
{{-- Mobile nav panel — drops below the pill when the hamburger
is tapped. Duplicates the nav links + lang switcher that
the desktop pill renders inline, so mobile users can reach
every destination the desktop nav exposes. --}}