Compare commits

...

8 Commits

7 changed files with 1292 additions and 56 deletions

View File

@@ -10,7 +10,7 @@
<!-- wp:oribi/page-hero-animated {"label":"Hardware","title":"Signage Players Engineered for the Real World","description":"Compact, silent, and built for 24/7 operation. Plug into any HDMI screen, connect to your network, and your content is live in minutes."} /-->
<!-- wp:oribi/platform-section {"label":"Our Devices","heading":"Commercial-Grade Hardware, Consumer-Level Simplicity","lead":"No IT degree required. Our players are designed to be set up in minutes and forgotten about for years."} -->
<!-- wp:oribi/platform-row {"heading":"Plug Into Any Screen","description":"Our players work with any display that has an HDMI port — TVs, commercial panels, monitors, even projectors. Keep the screens you already own, or let us supply commercial-grade displays rated for continuous use. Either way, you\u0027re up and running fast.","btnText":"Get a Quote","btnUrl":"/contact"} /-->
<!-- wp:oribi/platform-row {"heading":"Works With Your Existing Screens","description":"Our player devices connect to any screen with an HDMI port — no proprietary hardware required. Already have displays? Plug in and go. Need a full setup? We offer bundled player-and-display packages too.","btnText":"Get a Quote","btnUrl":"/contact","tvStick":true} /-->
<!-- wp:oribi/platform-row {"heading":"Never Goes Dark","description":"Every player caches content locally. If your internet connection drops, your displays continue running seamlessly with the latest synced content. When connectivity returns, new content pulls down automatically — no manual steps, no reboots.","btnText":"See Features","btnUrl":"/features","reversed":true} /-->
<!-- wp:oribi/platform-row {"heading":"Locked Down by Default","description":"Secure boot, encrypted storage, and encrypted communications come standard on every device. Remote management lets you monitor, update, and troubleshoot from anywhere. Firmware updates roll out over the air with zero downtime.","btnText":"Learn More","btnUrl":"/about"} /-->
<!-- /wp:oribi/platform-section -->

View File

@@ -12,7 +12,6 @@
<!-- wp:oribi/platform-section {"label":"Core Features","heading":"Everything You Need, Nothing You Don\u0027t","lead":"Create, schedule, and manage digital signage content from a single dashboard — whether you have one screen or one thousand."} -->
<!-- wp:oribi/platform-row {"heading":"One Dashboard for Every Display","description":"Manage your entire signage network from a single cloud-based console. Organise screens by location, group, or purpose. Push content updates across your whole estate in one click — no matter how many sites you operate.","btnText":"Get Started","btnUrl":"/contact"} /-->
<!-- wp:oribi/platform-row {"heading":"Scheduling That Runs Itself","description":"Set content to appear at the right time, in the right place, automatically. Day-parting, date ranges, and event-triggered playback let you plan weeks ahead while the platform handles the execution.","btnText":"See Pricing","btnUrl":"/pricing","reversed":true} /-->
<!-- wp:oribi/platform-row {"heading":"Works With Your Existing Screens","description":"Our player devices connect to any screen with an HDMI port — no proprietary hardware required. Already have displays? Plug in and go. Need a full setup? We offer bundled player-and-display packages too.","btnText":"View Devices","btnUrl":"/devices","tvStick":true} /-->
<!-- wp:oribi/platform-row {"heading":"Live Data, Straight to Screen","description":"Pull in web dashboards, social feeds, KPIs, and real-time APIs directly to your displays. Content updates automatically — no manual refreshing, no extra steps. Turn any screen into a live information hub.","btnText":"Learn More","btnUrl":"/solutions","reversed":true} /-->
<!-- /wp:oribi/platform-section -->

View File

@@ -8,10 +8,12 @@
return <<<'ORIBI_SYNC_CONTENT'
<!-- wp:oribi/hero-animated {"label":"● Digital Signage Solutions","title":"Turn any screen into a dynamic communication tool.","highlightWord":"dynamic","description":"Digital signage is the modern way to connect with your audience. From eye-catching retail displays to dynamic informational screens, we craft tailored solutions that capture attention and deliver your message.","secondaryBtnText":"Request Demo","secondaryBtnUrl":"/demo","stat1Value":"4K","stat1Label":"Resolution Supported","stat2Value":"500+","stat2Label":"Screens Supported","stat3Value":"99.9%","stat3Label":"Uptime"} /-->
<!-- wp:oribi/platform-section {"label":"The Complete Package","heading":"Everything You Need for Engaging Digital Signage","lead":"High-quality visuals, real-time data, and reliable playback — all managed from one powerful platform."} -->
<!-- wp:oribi/platform-row {"heading":"Professional Content Creation","description":"Our in-house photography and video production services showcase your products, services, and environment with polished, engaging visuals. From digital menu boards to branded promotions, we create content that captures attention.","btnText":"See Features","btnUrl":"/features"} /-->
<!-- wp:oribi/use-cases {"label":"● Use Cases","heading":"Built for Every Scenario","lead":"From menus to meeting-room dashboards, digital signage adapts to your environment.","case1Title":"Menu Boards","case1Desc":"Showcase food, drinks, and daily specials with dynamic, always-current displays.","case2Title":"Event Displays","case2Desc":"Promote schedules, speakers, and live countdowns across lobbies and venues.","case3Title":"Office Dashboards","case3Desc":"Surface KPIs, occupancy data, and team alerts on screens throughout your workspace.","case4Title":"Wayfinding","case4Desc":"Guide visitors through complex buildings with interactive maps and directional signs."} /-->
<!-- wp:oribi/platform-row {"heading":"Live Data \u0026amp; Web Dashboards","description":"Integrate your existing web dashboards, social feeds, and real-time data sources directly to your displays. Bring your most important information to life on screen, automatically and effortlessly.","btnUrl":"/features","reversed":true,"isDashboard":true} /-->
<!-- wp:oribi/platform-section {"label":"The Complete Package","heading":"Everything You Need for Engaging Digital Signage","lead":"High-quality visuals, real-time data, and reliable playback — all managed from one powerful platform."} -->
<!-- wp:oribi/platform-row {"heading":"Professional Content Creation","description":"Our in-house photography and video production services showcase your products, services, and environment with polished, engaging visuals. From digital menu boards to branded promotions, we create content that captures attention.","btnText":"See Features","btnUrl":"/features","cameraAnim":true} /-->
<!-- wp:oribi/platform-row {"heading":"Live Data u0026amp; Web Dashboards","description":"Integrate your existing web dashboards, social feeds, and real-time data sources directly to your displays. Bring your most important information to life on screen, automatically and effortlessly.","btnUrl":"/features","reversed":true,"isDashboard":true} /-->
<!-- wp:oribi/platform-row {"heading":"Reliable on Any Screen","description":"Our intelligent player devices work on any screen with HDMI, and keep your message running even when the internet goes down. Enterprise-grade hardware designed for uninterrupted, always-on signage.","btnText":"View Devices","btnUrl":"/devices","deviceAnim":true} /-->
<!-- /wp:oribi/platform-section -->

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@
var LINE_W = 340; // line graph width in SVG units
var PIE_R = 55; // pie chart radius
var DARK = { text: '#E0E0E0', muted: '#9E9E9E', border: '#333', center: '#222' };
var DARK = { text: '#E0E0E0', muted: '#9E9E9E', border: '#333', center: '#1A1A1A' };
var LIGHT = { text: '#333333', muted: '#666666', border: '#E0E0E0', center: '#fff' };
function isDark() { return document.documentElement.getAttribute('data-theme') === 'dark'; }

View File

@@ -1180,6 +1180,7 @@ reg('oribi/platform-row', {
imgUrl: { type: 'string', default: '' },
imgAlt: { type: 'string', default: '' },
imgWidth: { type: 'number', default: 300 },
cameraAnim: { type: 'boolean', default: false },
},
edit: function (props) {
var a = props.attributes, s = props.setAttributes;
@@ -1189,7 +1190,8 @@ reg('oribi/platform-row', {
el(PB, { title: 'Row Settings' },
el(TC, { label: 'Visual (emoji)', value: a.visual, onChange: function(v){s({visual:v});} }),
el(TC, { label: 'Button URL', value: a.btnUrl, onChange: function(v){s({btnUrl:v});} }),
el(TG, { label: 'Reversed', checked: !!a.reversed, onChange: function(v){s({reversed:v});} })
el(TG, { label: 'Reversed', checked: !!a.reversed, onChange: function(v){s({reversed:v});} }),
el(TG, { label: 'Camera Animation', checked: !!a.cameraAnim, onChange: function(v){s({cameraAnim:v});} })
),
el(PB, { title: 'Visual Image', initialOpen: false },
el(MUC, null,
@@ -1220,7 +1222,67 @@ reg('oribi/platform-row', {
a.btnUrl ? el(RT, { tagName: 'span', className: 'btn btn-outline mt-3',
value: a.btnText, onChange: function(v){s({btnText:v});}, placeholder: 'Button...' }) : null
),
a.imgUrl
a.cameraAnim
? el('div', { className: 'platform-visual has-camera' },
el('div', { className: 'cam-stage', 'aria-hidden': 'true' },
// Photo camera (left)
el('div', { className: 'pc-wrap' },
el('div', { className: 'pc-body' },
el('div', { className: 'pc-flash-unit' }),
el('div', { className: 'pc-top' },
el('div', { className: 'pc-shutter-btn' }),
el('div', { className: 'pc-viewfinder' })
),
el('div', { className: 'pc-front' },
el('div', { className: 'pc-lens-ring' },
el('div', { className: 'pc-lens-glass' },
el('div', { className: 'pc-lens-reflex' })
)
),
el('div', { className: 'pc-grip' })
)
),
el('div', { className: 'pc-prints' },
el('div', { className: 'pc-print pc-print--1', style: { opacity: '1', transform: 'rotate(-12deg) translateY(0)' } },
el('div', { className: 'pc-print__img' })
)
)
),
// Centre scene
el('div', { className: 'cam-scene' },
el('div', { className: 'cam-subject cam-subject--1' }),
el('div', { className: 'cam-flash-overlay' }),
el('div', { className: 'cam-vid-overlay' })
),
// Video camera on tripod (right)
el('div', { className: 'vc-wrap' },
el('div', { className: 'vc-camera' },
el('div', { className: 'vc-handle' }),
el('div', { className: 'vc-body' },
el('div', { className: 'vc-lens-barrel' },
el('div', { className: 'vc-lens-tip' },
el('div', { className: 'vc-lens-glass' },
el('div', { className: 'vc-lens-reflex' })
)
)
),
el('div', { className: 'vc-top-rail' }),
el('div', { className: 'vc-rec-light' }),
el('div', { className: 'vc-eyepiece' })
)
),
el('div', { className: 'vc-tripod' },
el('div', { className: 'vc-stem' }),
el('div', { className: 'vc-legs' },
el('div', { className: 'vc-leg vc-leg--l' }),
el('div', { className: 'vc-leg vc-leg--c' }),
el('div', { className: 'vc-leg vc-leg--r' })
)
)
)
)
)
: a.imgUrl
? el('div', { className: 'platform-visual has-img' },
el('img', { src: a.imgUrl, style: { width: imgW + 'px', maxWidth: '100%', height: 'auto', borderRadius: '4px', objectFit: 'contain', display: 'block', marginInline: 'auto' } })
)
@@ -1701,7 +1763,6 @@ reg('oribi/hero-animated', {
save: function () { return null; }
});
/* ANIMATED PAGE HERO ──────────────────────────────────────────────────── */
reg('oribi/page-hero-animated', {
title: 'Animated Page Hero',
icon: 'flag',
@@ -1784,4 +1845,81 @@ reg('oribi/site-footer', {
save: function () { return null; }
});
/* USE CASES SHOWCASE ──────────────────────────────────────────────────── */
reg('oribi/use-cases', {
title: 'Use Cases Showcase',
icon: 'grid-view',
category: 'oribi',
supports: { html: false },
attributes: {
label: { type: 'string', default: '\u25cf Use Cases' },
heading: { type: 'string', default: 'Built for Every Scenario' },
lead: { type: 'string', default: 'From menus to meeting-room dashboards, digital signage adapts to your environment.' },
case1Title: { type: 'string', default: 'Menu Boards' },
case1Desc: { type: 'string', default: 'Showcase food, drinks, and daily specials with dynamic, always-current displays.' },
case2Title: { type: 'string', default: 'Event Displays' },
case2Desc: { type: 'string', default: 'Promote schedules, speakers, and live countdowns across lobbies and venues.' },
case3Title: { type: 'string', default: 'Office Dashboards' },
case3Desc: { type: 'string', default: 'Surface KPIs, occupancy data, and team alerts on screens throughout your workspace.' },
case4Title: { type: 'string', default: 'Wayfinding' },
case4Desc: { type: 'string', default: 'Guide visitors through complex buildings with interactive maps and directional signs.' },
},
edit: function (props) {
var a = props.attributes, s = props.setAttributes;
return el(Frag, null,
el(IC, null,
el(PB, { title: 'Section Header' },
el(TC, { label: 'Label', value: a.label, onChange: function(v){s({label:v});} }),
el(TC, { label: 'Heading', value: a.heading, onChange: function(v){s({heading:v});} }),
el(TA, { label: 'Lead', value: a.lead, onChange: function(v){s({lead:v});} })
),
el(PB, { title: 'Use Case 1 Menu Boards', initialOpen: false },
el(TC, { label: 'Title', value: a.case1Title, onChange: function(v){s({case1Title:v});} }),
el(TA, { label: 'Description', value: a.case1Desc, onChange: function(v){s({case1Desc:v});} })
),
el(PB, { title: 'Use Case 2 Events', initialOpen: false },
el(TC, { label: 'Title', value: a.case2Title, onChange: function(v){s({case2Title:v});} }),
el(TA, { label: 'Description', value: a.case2Desc, onChange: function(v){s({case2Desc:v});} })
),
el(PB, { title: 'Use Case 3 Dashboards', initialOpen: false },
el(TC, { label: 'Title', value: a.case3Title, onChange: function(v){s({case3Title:v});} }),
el(TA, { label: 'Description', value: a.case3Desc, onChange: function(v){s({case3Desc:v});} })
),
el(PB, { title: 'Use Case 4 Wayfinding', initialOpen: false },
el(TC, { label: 'Title', value: a.case4Title, onChange: function(v){s({case4Title:v});} }),
el(TA, { label: 'Description', value: a.case4Desc, onChange: function(v){s({case4Desc:v});} })
)
),
el('section', { className: 'section use-cases-section' },
el('div', { className: 'container' },
el('div', { className: 'section-header' },
a.label ? el('span', { className: 'section-label' }, a.label) : null,
a.heading ? el('h2', null, a.heading) : null,
a.lead ? el('p', { className: 'lead' }, a.lead) : null
),
el('div', { className: 'uc-track' },
['menu', 'event', 'dashboard', 'wayfinding'].map(function (mod, i) {
var n = i + 1;
var title = a['case' + n + 'Title'];
var desc = a['case' + n + 'Desc'];
return el('div', { key: mod, className: 'uc-item' },
el('div', { className: 'uc-circle uc-anim--' + mod,
style: { display:'flex', alignItems:'center', justifyContent:'center',
fontSize:'.7rem', color:'var(--color-muted)', textAlign:'center', padding:'8px' } },
mod
),
el('div', { className: 'uc-item-body' },
el('div', { className: 'uc-item-title' }, title),
desc ? el('p', { className: 'uc-item-desc' }, desc) : null
)
);
})
)
)
)
);
},
save: function () { return null; }
});
})(window.wp);

View File

@@ -555,6 +555,7 @@ add_action( 'init', function () {
'imgWidth' => [ 'type' => 'number', 'default' => 300 ],
'deviceAnim' => [ 'type' => 'boolean', 'default' => false ],
'tvStick' => [ 'type' => 'boolean', 'default' => false ],
'cameraAnim' => [ 'type' => 'boolean', 'default' => false ],
],
'supports' => $block_supports,
'render_callback' => 'oribi_render_platform_row',
@@ -655,6 +656,25 @@ add_action( 'init', function () {
'render_callback' => 'oribi_render_page_hero_animated',
] );
/* Use Cases Showcase - 4 animated circles beneath the homepage hero */
register_block_type( 'oribi/use-cases', [
'attributes' => [
'label' => [ 'type' => 'string', 'default' => '● Use Cases' ],
'heading' => [ 'type' => 'string', 'default' => 'Built for Every Scenario' ],
'lead' => [ 'type' => 'string', 'default' => 'From menus to meeting-room dashboards, digital signage adapts to your environment.' ],
'case1Title' => [ 'type' => 'string', 'default' => 'Menu Boards' ],
'case1Desc' => [ 'type' => 'string', 'default' => 'Showcase food, drinks, and daily specials with dynamic, always-current displays.' ],
'case2Title' => [ 'type' => 'string', 'default' => 'Event Displays' ],
'case2Desc' => [ 'type' => 'string', 'default' => 'Promote schedules, speakers, and live countdowns across lobbies and venues.' ],
'case3Title' => [ 'type' => 'string', 'default' => 'Office Dashboards' ],
'case3Desc' => [ 'type' => 'string', 'default' => 'Surface KPIs, occupancy data, and team alerts on screens throughout your workspace.' ],
'case4Title' => [ 'type' => 'string', 'default' => 'Wayfinding' ],
'case4Desc' => [ 'type' => 'string', 'default' => 'Guide visitors through complex buildings with interactive maps and directional signs.' ],
],
'supports' => $block_supports,
'render_callback' => 'oribi_render_use_cases',
] );
} );
/* ══════════════════════════════════════════════════════════════════════════════
@@ -1498,6 +1518,59 @@ function oribi_render_platform_row( $a ) {
$ts .= '</div>';
$visual_html = $ts;
$visual_cls = 'platform-visual has-tv-stick';
} elseif ( ! empty( $a['cameraAnim'] ) ) {
$ca = '<div class="cam-stage" aria-hidden="true">';
// ── Left: compact photo camera ──
$ca .= '<div class="pc-wrap">';
$ca .= '<div class="pc-body">';
$ca .= '<div class="pc-flash-unit"></div>';
$ca .= '<div class="pc-top"><div class="pc-shutter-btn"></div><div class="pc-viewfinder"></div></div>';
$ca .= '<div class="pc-front">';
$ca .= '<div class="pc-lens-ring"><div class="pc-lens-glass"><div class="pc-lens-reflex"></div></div></div>';
$ca .= '<div class="pc-grip"></div>';
$ca .= '</div>';
$ca .= '</div>'; // pc-body
$ca .= '<div class="pc-prints">';
$ca .= '<div class="pc-print pc-print--1"><div class="pc-print__img"></div></div>';
$ca .= '<div class="pc-print pc-print--2"><div class="pc-print__img"></div></div>';
$ca .= '<div class="pc-print pc-print--3"><div class="pc-print__img"></div></div>';
$ca .= '</div>'; // pc-prints
$ca .= '</div>'; // pc-wrap
// ── Centre: product scene both cameras shoot ──
$ca .= '<div class="cam-scene">';
$ca .= '<div class="cam-subject cam-subject--1"></div>';
$ca .= '<div class="cam-subject cam-subject--2"></div>';
$ca .= '<div class="cam-subject cam-subject--3"></div>';
$ca .= '<div class="cam-flash-overlay"></div>';
$ca .= '<div class="cam-vid-overlay"></div>';
$ca .= '</div>'; // cam-scene
// ── Right: retro VHS video camera on tripod ──
$ca .= '<div class="vc-wrap">';
$ca .= '<div class="vc-camera">';
$ca .= '<div class="vc-handle"></div>';
$ca .= '<div class="vc-body">';
$ca .= '<div class="vc-lens-barrel"><div class="vc-lens-tip"><div class="vc-lens-glass"><div class="vc-lens-reflex"></div></div></div></div>';
$ca .= '<div class="vc-top-rail"></div>';
$ca .= '<div class="vc-rec-light"></div>';
$ca .= '<div class="vc-eyepiece"></div>';
$ca .= '</div>'; // vc-body
$ca .= '</div>'; // vc-camera
$ca .= '<div class="vc-tripod">';
$ca .= '<div class="vc-stem"></div>';
$ca .= '<div class="vc-legs">';
$ca .= '<div class="vc-leg vc-leg--l"></div>';
$ca .= '<div class="vc-leg vc-leg--c"></div>';
$ca .= '<div class="vc-leg vc-leg--r"></div>';
$ca .= '</div>'; // vc-legs
$ca .= '</div>'; // vc-tripod
$ca .= '</div>'; // vc-wrap
$ca .= '</div>'; // cam-stage
$visual_html = $ca;
$visual_cls = 'platform-visual has-camera';
} else {
$visual_html = oribi_render_icon( $a['visual'] ?? '' );
$visual_cls = 'platform-visual';
@@ -1708,3 +1781,95 @@ function oribi_render_page_hero_animated( $a ) {
</section>
<?php return ob_get_clean();
}
/* ── Use Cases Showcase ────────────────────────────────────────────────── */
function oribi_uc_anim_inner( $mod ) {
switch ( $mod ) {
case 'menu':
return '
<div class="uc-inner uc-inner--menu" aria-hidden="true">
<div class="uc-menu-header"></div>
<div class="uc-menu-row"><span class="uc-menu-name"></span><span class="uc-menu-price"></span></div>
<div class="uc-menu-row uc-menu-row--highlight"><span class="uc-menu-name"></span><span class="uc-menu-price"></span></div>
<div class="uc-menu-row"><span class="uc-menu-name uc-menu-name--sm"></span><span class="uc-menu-price"></span></div>
<div class="uc-menu-row"><span class="uc-menu-name"></span><span class="uc-menu-price"></span></div>
<div class="uc-menu-divider"></div>
<div class="uc-menu-row"><span class="uc-menu-name uc-menu-name--sm"></span><span class="uc-menu-price"></span></div>
</div>';
case 'event':
return '
<div class="uc-inner uc-inner--event" aria-hidden="true">
<div class="uc-event-cursor"></div>
<div class="uc-event-header"></div>
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar uc-event-bar--active"></div></div>
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar"></div></div>
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar uc-event-bar--accent"></div></div>
<div class="uc-event-row"><div class="uc-event-time"></div><div class="uc-event-bar"></div></div>
</div>';
case 'dashboard':
return '
<div class="uc-inner uc-inner--dashboard" aria-hidden="true">
<div class="uc-db-bars">
<div class="uc-db-bar uc-db-bar--1"></div>
<div class="uc-db-bar uc-db-bar--2"></div>
<div class="uc-db-bar uc-db-bar--3"></div>
<div class="uc-db-bar uc-db-bar--4"></div>
</div>
<div class="uc-db-baseline"></div>
<div class="uc-db-labels">
<div class="uc-db-lbl"></div>
<div class="uc-db-lbl"></div>
<div class="uc-db-lbl"></div>
<div class="uc-db-lbl"></div>
</div>
</div>';
case 'wayfinding':
return '
<div class="uc-inner uc-inner--wayfinding" aria-hidden="true">
<div class="uc-wf-corridor uc-wf-corridor--h"></div>
<div class="uc-wf-corridor uc-wf-corridor--v"></div>
<div class="uc-wf-room uc-wf-room--1"></div>
<div class="uc-wf-room uc-wf-room--2"></div>
<div class="uc-wf-room uc-wf-room--3"></div>
<div class="uc-wf-dot"></div>
<div class="uc-wf-arrow"></div>
</div>';
default:
return '';
}
}
function oribi_render_use_cases( $a ) {
$cases = [
[ 'title' => $a['case1Title'], 'desc' => $a['case1Desc'], 'mod' => 'menu' ],
[ 'title' => $a['case2Title'], 'desc' => $a['case2Desc'], 'mod' => 'event' ],
[ 'title' => $a['case3Title'], 'desc' => $a['case3Desc'], 'mod' => 'dashboard' ],
[ 'title' => $a['case4Title'], 'desc' => $a['case4Desc'], 'mod' => 'wayfinding' ],
];
ob_start(); ?>
<section class="section use-cases-section">
<div class="container">
<?php if ( $a['label'] || $a['heading'] || $a['lead'] ) : ?>
<div class="section-header">
<?php if ( $a['label'] ) : ?><span class="section-label"><?php echo esc_html( $a['label'] ); ?></span><?php endif; ?>
<?php if ( $a['heading'] ) : ?><h2><?php echo wp_kses_post( $a['heading'] ); ?></h2><?php endif; ?>
<?php if ( $a['lead'] ) : ?><p class="lead"><?php echo wp_kses_post( $a['lead'] ); ?></p><?php endif; ?>
</div>
<?php endif; ?>
<div class="uc-track">
<?php foreach ( $cases as $c ) : ?>
<div class="uc-item">
<div class="uc-circle uc-anim--<?php echo esc_attr( $c['mod'] ); ?>">
<?php echo oribi_uc_anim_inner( $c['mod'] ); ?>
</div>
<div class="uc-item-body">
<div class="uc-item-title"><?php echo esc_html( $c['title'] ); ?></div>
<?php if ( $c['desc'] ) : ?><p class="uc-item-desc"><?php echo esc_html( $c['desc'] ); ?></p><?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</section>
<?php return ob_get_clean();
}