<% // PricingCard.template.html — 13-style card wrapper. // Context: style, highlighted, badge, icon, accent, renderIcon(name,size,color) // cell_index, cell_count (0-based + total, used by banded/tier) // + blocks, formatter, vertical_align, cell_gap, cell_count var _style = (typeof style === 'string' && style) ? style : 'highlighted'; var _highlighted = !!highlighted; var _badge = (typeof badge === 'string' && badge.trim()) ? badge.trim() : ''; var _icon = (typeof icon === 'string' && icon.trim()) ? icon.trim() : ''; var _accent = (typeof accent === 'string' && accent.trim()) ? accent.trim() : '#ffcc2a'; var _idx = (typeof cell_index === 'number' && cell_index >= 0) ? cell_index : 0; var _count = (typeof cell_count === 'number' && cell_count > 0) ? cell_count : 1; var _isFirst = (_idx === 0); var _isLast = (_idx === _count - 1); // Inline SVG icon renderer — falls back to emoji passthrough for non-ASCII // input and first-letter circle for unknown names. See pricingCardIcons.js. var _renderIcon = (typeof renderIcon === 'function') ? renderIcon : function () { return ''; }; var TOKENS = { minimal: { radius: '12px', pad: '24px 20px', shadow: '0 1px 2px rgba(15,23,42,0.04)', border: '1px solid #e5e7eb', bg: '#ffffff', color: '#111827' }, highlighted: { radius: '12px', pad: '24px 20px', shadow: '0 1px 2px rgba(15,23,42,0.04)', border: '1px solid #e5e7eb', bg: '#ffffff', color: '#111827' }, featured: { radius: '18px', pad: '36px 20px 28px', shadow: '0 16px 40px rgba(15,23,42,0.08)', border: '1px solid #f0d0c8', bg: '#ffffff', color: '#111827' }, compact: { radius: '10px', pad: '18px 16px', shadow: '0 1px 2px rgba(15,23,42,0.04)', border: '1px solid #d1d5db', bg: '#ffffff', color: '#111827' }, glass: { radius: '16px', pad: '28px 22px', shadow: '0 8px 32px rgba(49,46,129,0.12)', border: '1px solid rgba(255,255,255,0.5)', bg: 'rgba(255,255,255,0.65)', color: '#312e81' }, pill: { radius: '24px', pad: '32px 22px', shadow: '0 2px 8px rgba(0,0,0,0.04)', border: '0', bg: '#ffffff', color: '#111827' }, neon: { radius: '10px', pad: '24px 20px', shadow: '0 0 24px rgba(0,229,255,0.25)', border: '1px solid rgba(0,229,255,0.35)', bg: '#14141c', color: '#e5e7eb' }, brutalist: { radius: '0', pad: '24px 20px', shadow: '8px 8px 0 0 #000', border: '2px solid #000', bg: '#ffffff', color: '#111827' }, editorial: { radius: '2px', pad: '28px 22px', shadow: '0 2px 8px rgba(28,25,23,0.06)', border: '1px solid #d4d4aa', bg: '#ffffff', color: '#1c1917' }, gradient: { radius: '14px', pad: '28px 22px', shadow: '0 12px 32px rgba(0,0,0,0.12)', border: '0', bg: 'linear-gradient(135deg,' + _accent + ',' + _accent + 'cc)', color: '#ffffff' }, // Joined table — border-radius computed dynamically below (only outer // corners round, inner corners sharp). Inner vertical border creates // the divider between cells. Highlighted card gets a light-blue top // strip for the Mailchimp "Best value" label. banded: { radius: 'DYN', pad: '32px 28px', shadow: '0 1px 2px rgba(15,23,42,0.05)', border: 'DYN', bg: '#ffffff', color: '#1c1917' }, // Staircase elevation — each card sits at a different margin-top so // the row of cards looks like steps climbing from index 0 → N-1. // Shadow grows with index to reinforce the climb. tier: { radius: '16px', pad: '28px 22px', shadow: 'DYN', border: '1px solid #e0e7ff', bg: '#ffffff', color: '#1e1b4b' }, // Neumorphism — soft gray surface with dual-direction shadow (outer // bright + outer dark) for the "pushed out" look. Highlighted flips // to inset for "pushed in". neo: { radius: '22px', pad: '32px 26px', shadow: 'DYN', border: '0', bg: '#e9edf3', color: '#1e293b' } }; var T = TOKENS[_style] || TOKENS.highlighted; // Resolve dynamic tokens for banded / tier / neo. var _extraStyles = ''; // injected into rootStyle list below (banded divider) if (_style === 'banded') { // Outer radius on first/last card only, 0 on inner corners. Middle // cards have no radius at all. Highlighted override handled // separately below. var _bRadius = '0'; if (_count === 1) _bRadius = '12px'; else if (_isFirst) _bRadius = '12px 0 0 12px'; else if (_isLast) _bRadius = '0 12px 12px 0'; T = Object.assign({}, T, { radius: _bRadius, border: '1px solid #e5e7eb', }); // Drop the right border on non-last cards so the divider reads as a // single shared line between joined cells (otherwise adjacent 1px // borders stack visually to 2px). Done via separate extra style so // it composes cleanly with the cardBorder highlighted override below. if (!_isLast) _extraStyles += ' border-right: 0;'; } if (_style === 'tier') { // Shadow ramp: index 0 = smallest, last = largest. Keeps the base // shadow subtle so stacks of 4 cards don't feel crushed. var _shadowStep = Math.round((_idx / Math.max(1, _count - 1)) * 20); T = Object.assign({}, T, { shadow: '0 ' + (4 + _shadowStep) + 'px ' + (16 + _shadowStep * 2) + 'px rgba(79,70,229,' + (0.06 + _idx * 0.02) + ')', }); } if (_style === 'neo') { // Dual-direction neumorphism — LIGHT shadow on top-left, DARK on // bottom-right. Values tuned against #e9edf3 card bg. T = Object.assign({}, T, { shadow: _highlighted ? 'inset 8px 8px 16px #c7cdd6, inset -8px -8px 16px #ffffff' : '10px 10px 24px #c7cdd6, -10px -10px 24px #ffffff', }); } var cardBorder = _highlighted ? ('2px solid ' + _accent) : T.border; var cardShadow = _highlighted ? ('0 16px 36px ' + _accent + '33, ' + T.shadow) : T.shadow; // No translateY on root — it broke featured ribbon's translateX anchor and // caused painted shadow/border to overlap across style switches. Apply lift // via a top margin-bottom offset that doesn't stack-context collide. var cardMarginTop = (_style === 'highlighted' && _highlighted) ? '-6px' : '0'; var cardMarginBottom = (_style === 'highlighted' && _highlighted) ? '6px' : '0'; if (_style === 'brutalist' && _highlighted) { cardBorder = '3px solid #000'; cardShadow = '10px 10px 0 0 ' + _accent; // Flood the highlighted brutalist card with accent so white-on-white // text doesn't disappear — also matches the genre (solid accent = // "the loud one"). Override rootStyle's background token further down. T = Object.assign({}, T, { bg: _accent, color: '#ffffff' }); } if (_style === 'neon' && _highlighted) { cardBorder = '2px solid ' + _accent; cardShadow = '0 0 36px ' + _accent + '66, inset 0 0 16px ' + _accent + '22'; } if (_style === 'banded' && _highlighted) { // Subtle tinted background on highlighted Mailchimp-style cell; // card keeps its joined-row appearance (don't lift or add stroke // that would break the table). cardBorder = T.border; cardShadow = T.shadow; T = Object.assign({}, T, { bg: '#fffdf0' }); } if (_style === 'tier') { // Staircase offset — first card sits LOWEST (largest top margin), // last card sits HIGHEST (zero top margin). Climbs left→right. var _tierStep = 12; var _fromBottom = (_count - 1 - _idx); cardMarginTop = (_fromBottom * _tierStep) + 'px'; cardMarginBottom = (_idx * _tierStep) + 'px'; if (_highlighted) { cardBorder = '2px solid ' + _accent; cardShadow = '0 18px 40px ' + _accent + '33'; } } if (_style === 'neo' && _highlighted) { // Already set T.shadow to inset above; also add a subtle accent ring. cardBorder = '2px solid ' + _accent + '66'; } // Width via grid — parent uses display: grid, so cells stretch naturally. Keep // height override for vertical sizing only. var height = formatter.getFormat('height'); var heightStyle = ''; if (height !== null && height !== '' && height !== undefined) { heightStyle = 'height: ' + height + (typeof height === 'number' ? 'px' : '') + ';'; } // Other formats (user-customized bg/border/padding on the cell formatter itself) var otherStyles = formatter.toStyleStringAll().replace(/width:\s*[^;]+;?\s*/gi, '').replace(/height:\s*[^;]+;?\s*/gi, '').trim(); var rootStyle = [ 'position: relative', 'display: flex', 'flex-direction: column', 'gap: 8px', 'min-height: 100%', 'box-sizing: border-box', 'border: ' + cardBorder, 'border-radius: ' + T.radius, 'padding: ' + T.pad, 'background: ' + T.bg, 'box-shadow: ' + cardShadow, 'margin-top: ' + cardMarginTop, 'margin-bottom: ' + cardMarginBottom, 'color: ' + T.color, 'transition: box-shadow 150ms ease, border-color 150ms ease', 'overflow: visible', heightStyle, otherStyles ].filter(function (s) { return s && s.length; }).join('; ') + ';' + _extraStyles; if (_style === 'glass') { rootStyle += ' backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);'; } // ---- BADGE ---- var badgeHtml = ''; if (_badge) { if (_style === 'featured') { badgeHtml = '
' + _badge + '
'; } else if (_style === 'highlighted' && _highlighted) { badgeHtml = '
' + _badge + '
'; } else if (_style === 'brutalist') { badgeHtml = '
' + _badge + '
'; } else if (_style === 'neon') { badgeHtml = '
' + _badge + '
'; } else if (_style === 'editorial') { badgeHtml = '
' + _badge + '
'; } else if (_style === 'gradient') { badgeHtml = '
' + _badge + '
'; } else if (_style === 'pill') { badgeHtml = '
' + _badge + '
'; } else if (_style === 'glass') { badgeHtml = '
' + _badge + '
'; } else if (_style === 'banded') { // Mailchimp-style "Best value" label — centered, underline, soft // blue tint strip that sits flush on top of the card (negative // margin matches the card's top padding so the strip fills the // full card width at the top edge). badgeHtml = '
' + _badge + '
'; } else if (_style === 'tier') { // Tier badge — bold uppercase pill in the accent color, sits // above the heading. Quiet unless highlighted. badgeHtml = '
' + _badge + '
'; } else if (_style === 'neo') { // Neumorphic chip — inset soft shadow, no fill, accent text. badgeHtml = '
' + _badge + '
'; } else { // minimal + compact fallback badgeHtml = '
' + _badge + '
'; } } // ---- ICON (inline SVG via registry) ---- var iconHtml = ''; if (_icon) { if (_style === 'featured') { iconHtml = '
' + _renderIcon(_icon, 26, _accent) + '
'; } else if (_style === 'pill') { iconHtml = '
' + _renderIcon(_icon, 36, _accent) + '
'; } else if (_style === 'compact') { iconHtml = ''; // compact hides icon } else if (_style === 'gradient') { iconHtml = '
' + _renderIcon(_icon, 22, '#ffffff') + '
'; } else if (_style === 'neon') { iconHtml = '
' + _renderIcon(_icon, 22, _accent) + '
'; } else if (_style === 'editorial') { iconHtml = '
' + _renderIcon(_icon, 20, _accent) + '
'; } else if (_style === 'brutalist') { iconHtml = '
' + _renderIcon(_icon, 24, '#000') + '
'; } else if (_style === 'banded') { // Subtle mono icon in serif-card context — small, aligned with // the serif heading below it. iconHtml = '
' + _renderIcon(_icon, 20, '#44403c') + '
'; } else if (_style === 'tier') { // Accent-filled circle chip — feels like a "rank medallion" for // each tier. iconHtml = '
' + _renderIcon(_icon, 22, _accent) + '
'; } else if (_style === 'neo') { // Neumorphic icon cell — soft inset square with accent glyph. iconHtml = '
' + _renderIcon(_icon, 22, _accent) + '
'; } else { // minimal + highlighted + glass fallback iconHtml = '
' + _renderIcon(_icon, 22, _accent) + '
'; } } %>
<%- badgeHtml %><%- iconHtml %><% if (blocks && blocks.length) { blocks.forEach(function (block) { %><%- block %><% }); } %>