{{-- Contextual miniature illustration for service cards (outcomes, features, process). Types: stack | checkout | seo | modules | ads | analytics | brand | social | email | content | local | cro | timeline | integrations | deliverable When optional title + body (aliases headline / support) yield non-empty normalized copy, the graphic is derived from crc32(copy) and keyword chips — legacy `type` is ignored for that card. Decorative only — parent sets aria-hidden where appropriate. --}} @props([ 'type' => 'deliverable', 'title' => null, 'body' => null, 'headline' => null, 'support' => null, ]) @php return; @endphp @php $title = $title ?? $headline; $body = $body ?? $support; $rawTitle = trim((string) ($title ?? '')); $rawBody = trim((string) ($body ?? '')); if ($rawTitle === '' && $rawBody !== '') { $w = preg_split('/\s+/u', $rawBody); $rawTitle = implode(' ', array_slice($w, 0, min(10, count($w)))); } $normalized = mb_strtolower(preg_replace('/\s+/u', ' ', $rawTitle.' '.$rawBody)); $normalized = trim($normalized); $useCopyDerived = $normalized !== ''; if ($useCopyDerived) { $h = crc32($normalized); $layoutId = (($h % 8) + 8) % 8; $motifIdx = (int) (($h >> 7) % 6); $density = 3 + (int) (($h >> 11) % 4); $stop = array_flip([ 'the', 'a', 'an', 'and', 'or', 'but', 'if', 'then', 'else', 'when', 'at', 'from', 'by', 'for', 'with', 'about', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'between', 'under', 'again', 'further', 'of', 'to', 'in', 'on', 'as', 'is', 'was', 'are', 'were', 'been', 'be', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'will', 'would', 'could', 'should', 'may', 'might', 'must', 'shall', 'can', 'this', 'that', 'these', 'those', 'it', 'its', 'we', 'you', 'your', 'our', 'their', 'they', 'them', 'not', 'no', 'nor', 'so', 'than', 'too', 'very', 'just', 'also', 'only', 'own', 'same', 'such', 'here', 'there', 'all', 'each', 'every', 'both', 'few', 'more', 'most', 'other', 'some', 'any', 'such', 'what', 'which', 'who', 'whom', 'how', 'why', 'where', 'i', 'me', 'my', 'he', 'him', 'his', 'she', 'her', 'hers', 'get', 'gets', 'got', 'make', 'made', 'use', 'uses', 'using', 'used', 'let', 'lets', 'say', 'said', 'way', 'ways', 'new', 'like', 'well', 'back', 'over', ]); $blob = mb_strtolower($rawTitle.' '.$rawBody); $blob = preg_replace('/[^\p{L}\p{N}\s]/u', ' ', $blob); $tokens = preg_split('/\s+/u', trim($blob), -1, PREG_SPLIT_NO_EMPTY); $freq = []; foreach ($tokens as $tok) { $tok = mb_strtolower($tok); if (mb_strlen($tok) < 3) { continue; } if (isset($stop[$tok])) { continue; } $freq[$tok] = ($freq[$tok] ?? 0) + 1; } $candidates = array_keys($freq); usort($candidates, static function (string $a, string $b) use ($freq): int { $la = mb_strlen($a); $lb = mb_strlen($b); if ($lb !== $la) { return $lb <=> $la; } return ($freq[$b] ?? 0) <=> ($freq[$a] ?? 0); }); $keywords = array_slice(array_values(array_unique($candidates)), 0, 4); if (count($keywords) < 2) { foreach ($tokens as $tok) { $lt = mb_strtolower($tok); if (mb_strlen($lt) >= 2 && ! isset($stop[$lt])) { $keywords[] = $lt; } if (count($keywords) >= 4) { break; } } $keywords = array_slice(array_values(array_unique($keywords)), 0, 4); } if (count($keywords) < 2) { $keywords = array_slice($tokens, 0, min(4, count($tokens))); } if (count($keywords) === 1) { $one = $keywords[0]; $cut = max(3, (int) floor(mb_strlen($one) / 2)); $tail = mb_substr($one, $cut); $keywords[] = $tail !== '' ? $tail : mb_substr($one, 0, $cut); } // Accent rotates by hash; keyword chips stay editorial neutral (set in copy partial). $paletteBank = [ ['badge' => 'bg-criazo-primary/[0.09]', 'icon' => 'text-criazo-primary', 'stroke' => 'text-criazo-primary', 'fillSoft' => 'text-criazo-primary/20', 'barBg' => 'bg-neutral-200/75', 'barStrong' => 'bg-gradient-to-r from-neutral-400/55 to-neutral-300/40', 'dot' => 'bg-criazo-primary', 'softCol' => 'bg-neutral-50', 'accentSlash' => 'bg-criazo-primary', 'mini' => 'bg-neutral-300/60', 'pillOn' => 'bg-criazo-primary text-white shadow-sm shadow-criazo-primary/15', 'pillOff' => 'bg-white border border-neutral-200 text-neutral-400', 'num' => 'text-criazo-primary'], ['badge' => 'bg-slate-500/[0.08]', 'icon' => 'text-slate-700', 'stroke' => 'text-slate-600', 'fillSoft' => 'text-slate-400/22', 'barBg' => 'bg-neutral-200/75', 'barStrong' => 'bg-gradient-to-r from-slate-400/45 to-neutral-300/35', 'dot' => 'bg-slate-500', 'softCol' => 'bg-slate-50/90', 'accentSlash' => 'bg-slate-500', 'mini' => 'bg-slate-300/45', 'pillOn' => 'bg-slate-700 text-white shadow-sm shadow-slate-700/15', 'pillOff' => 'bg-white border border-neutral-200 text-neutral-400', 'num' => 'text-slate-800'], ['badge' => 'bg-sky-500/[0.08]', 'icon' => 'text-sky-800', 'stroke' => 'text-sky-600', 'fillSoft' => 'text-sky-400/22', 'barBg' => 'bg-neutral-200/75', 'barStrong' => 'bg-gradient-to-r from-sky-400/35 to-neutral-300/35', 'dot' => 'bg-sky-500', 'softCol' => 'bg-sky-50/80', 'accentSlash' => 'bg-sky-500', 'mini' => 'bg-sky-200/50', 'pillOn' => 'bg-sky-700 text-white shadow-sm shadow-sky-700/15', 'pillOff' => 'bg-white border border-neutral-200 text-neutral-400', 'num' => 'text-sky-900'], ['badge' => 'bg-neutral-800/[0.07]', 'icon' => 'text-neutral-800', 'stroke' => 'text-neutral-600', 'fillSoft' => 'text-neutral-400/20', 'barBg' => 'bg-neutral-200/75', 'barStrong' => 'bg-gradient-to-r from-neutral-500/40 to-neutral-300/38', 'dot' => 'bg-neutral-600', 'softCol' => 'bg-neutral-50', 'accentSlash' => 'bg-neutral-600', 'mini' => 'bg-neutral-300/55', 'pillOn' => 'bg-neutral-900 text-white shadow-sm shadow-neutral-900/15', 'pillOff' => 'bg-white border border-neutral-200 text-neutral-400', 'num' => 'text-neutral-900'], ]; $palette = $paletteBank[((int) (($h >> 4) & 7)) % count($paletteBank)]; $kw = array_values(array_filter(array_map( static fn (string $s): string => \Illuminate\Support\Str::limit(trim($s), 14, ''), $keywords ?? [] ))); $kw = array_slice($kw, 0, 4); $lineCount = min(6, max(3, (int) ($density ?? 4))); $micro = (int) (($h ?? 0) & 255); $displayTitle = trim($rawTitle) !== '' ? \Illuminate\Support\Str::limit(trim($rawTitle), 38, '…') : ''; if ($displayTitle === '' && count($kw) > 0) { $displayTitle = \Illuminate\Support\Str::limit(implode(' ', $kw), 38, ''); } } @endphp @if($useCopyDerived) @include('components.partials.service-outcome-visual-copy', [ 'layoutId' => $layoutId, 'motifIdx' => $motifIdx, 'density' => $density, 'keywords' => $keywords, 'palette' => $palette, 'h' => $h, 'kw' => $kw, 'lineCount' => $lineCount, 'micro' => $micro, 'displayTitle' => $displayTitle ?? '', 'rawTitle' => $rawTitle, 'rawBody' => $rawBody, 'normalizedCopy' => $normalized, ]) @else @php $t = $type; @endphp @if($t === 'stack') {{-- Layered platform architecture: core CMS → commerce → extensions --}}