(function () {
'use strict';
var root = document.getElementById('iph2');
if (!root || root.getAttribute('data-ready')) return;
root.setAttribute('data-ready', '1');
var track = root.querySelector('.iph-track');
var slides = Array.prototype.slice.call(root.querySelectorAll('.iph-slide'));
var dotList = root.querySelector('.iph-dot-list');
var playBtn = root.querySelector('.iph-play');
var progress = root.querySelector('.iph-progress');
var live = root.querySelector('.iph-sr');
var TOTAL = slides.length;
var DELAY = 5200;
var reduce = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches;
var cur = 0, dots = [], leaveTimer = null;
/* Why autoplay may be stopped; it runs only when every flag is clear */
var hold = { offscreen: false, hover: false, focus: false, tabHidden: document.hidden, drag: false, user: reduce };
/* ── Images: only slide 1 loads with the page; the rest load just
before they are needed, so they don't compete with the hero ── */
function load(i) {
var img = slides[(i + TOTAL) % TOTAL].querySelector('img[data-src]');
if (!img) return;
img.addEventListener('load', function () { img.removeAttribute('data-src'); }, { once: true });
img.addEventListener('error', function () { img.removeAttribute('data-src'); }, { once: true });
img.src = img.getAttribute('data-src');
}
function loadAround(i) { load(i); load(i + 1); load(i - 1); }
function warmUp() {
var idle = window.requestIdleCallback || function (fn) { return setTimeout(fn, 600); };
idle(function () { load(1); load(TOTAL - 1); });
}
if (document.readyState === 'complete') warmUp(); else window.addEventListener('load', warmUp, { once: true });
/* ── Accessibility state for slides ── */
function setActiveA11y(slide, on) {
if (on) slide.removeAttribute('aria-hidden'); else slide.setAttribute('aria-hidden', 'true');
var f = slide.querySelectorAll('a, button');
for (var k = 0; k 8 && Math.abs(mx) > Math.abs(my) * 1.2) {
dragging = true; hold.drag = true; sync();
try { root.setPointerCapture(pid); } catch (x) {}
} else if (Math.abs(my) > 10) { pid = null; return; }
else return;
}
dx = mx;
var edge = (cur === 0 && dx > 0) || (cur === TOTAL - 1 && dx 0.45;
if (dx < -w * 0.18 || (fast && dx w * 0.18 || (fast && dx > 30)) goTo(cur - 1, true);
else { setTrack(-100 * cur, 0, true); sync(); }
}
root.addEventListener('pointerup', endDrag);
root.addEventListener('pointercancel', endDrag);
root.addEventListener('click', function (e) { if (blockClick) { e.preventDefault(); e.stopPropagation(); } }, true);
if (reduce) root.classList.add('is-static');
sync();
})();
Best ceiling panel sri lanka
Three Signature Series. One Premium Standard.
Engineered to perform beautifully for decades in Sri Lanka’s tropical climate. Discover the perfect system for your space.
Almost every operator runs a points programme, usually presented as a tier ladder with escalating perks. What matters is arithmetic rather than badges, specifically how many points a stake earns and what those points are worth in cash.
Reading a Rewards Programme Honestly
Slots usually earn points at full rate while table games earn at a fraction, mirroring the way bonus weighting works. Anyone judging whether a club is worth concentrating play at one operator may Slotlair casino first. Watch for point expiry too, because dormant balances are commonly cleared after a few months of inactivity.
Element
What to Check
Conversion rate
Points needed for one unit of credit
Tier speed
How much play each level demands
Expiry
How long unused points survive
Convert points into a cash percentage before judging a scheme
Check which games earn at the full rate
Note whether points expire during inactive periods
A loyalty scheme is a modest rebate on money already staked, not a source of profit, and it never offsets the house edge. Its correct use is choosing between operators you would have played at anyway. Set your budget independently of any tier target, and never extend a session to chase points.
Podczas gdy bonus powitalny sluzy pozyskaniu gracza, reload ma go zatrzymac. Pojawia sie regularnie, czesto co tydzien, i wlasnie ta powtarzalnosc sprawia, ze warto przyjrzec sie jego warunkom raz, a stosowac wielokrotnie.
Warunki powtarzalnej oferty
Powtarzalny bonus kusi do czestszych wplat, dlatego warto oddzielic go od wlasnego planu gry. Zeby ocenic warunki, mozna bison casino online i przeczytac wymog obrotu oraz limit czasu przed skorzystaniem. Reload objety krotkim terminem czesto wymusza szybsza gre.
Punkt
Dlaczego wazny
Czestotliwosc
Zacheca do czestszych wplat
Limit czasu
Wymusza tempo gry
Zobacz limit czasu na spelnienie warunkow
Nie zwiekszaj czestotliwosci wplat pod oferte
Regularny bonus najlatwiej popycha do czestszych depozytow, niz sam by chcial. Traktuj go jak drobny dodatek do zaplanowanej gry, sprawdzaj warunki za kazdym razem i nie pozwol, by kalendarz ofert dyktowal Twoje wplaty.
i‑panel’s island‑wide network of authorised dealers brings our premium solutions within reach of every Sri Lankan home and project. It is how we deliver quality, trust, and service – wherever you are.
While imitation panels warp, crack, and discolor within two years of exposure to humidity and heat, the original i-Panel maintains its form and finish for decades.
Raw Slab
Exposed Concrete
Unfinished structural ceilings leave wiring and uneven concrete surfaces visible to residents.
Elevated Living
Seamless Integration
A flawless matte finish conceals utilities while instantly brightening the residential space.
Advanced fire-resistant materials that meet safety standards and provide excellent protection against fire hazards in construction applications.
No Need to Paint
Pre-finished surface eliminates the need for painting, saving time and maintenance costs while maintaining aesthetic appeal.
Easy Maintenance
Simple cleaning and minimal upkeep required. Resistant to stains and dirt, making maintenance effortless and cost-effective.
Saves Labor
Cut labor costs with our fast, simple, and innovative ceiling installation.
Water Resist
Excellent water resistance properties prevent moisture damage, mold growth, and structural deterioration over time.
Zero Toxicity
Non-toxic materials that are safe for indoor use, containing no harmful chemicals or volatile organic compounds (VOCs).
Any Climate Tolerant
Performs excellently in various weather conditions — from extreme heat to cold, humidity, and changing seasonal conditions.
Saves Time
Streamlined installation process and reduced preparation time leads to faster project completion and quicker occupancy.
Free from Insect
Naturally resistant to termites, ants, and other insects, eliminating the need for chemical treatments and pest control.
Non-Carcinogenic
Completely safe and non-carcinogenic materials that pose no health risks to occupants or construction workers.
Less Wastage
Precise manufacturing and easy cutting reduce material waste, making it an environmentally friendly and cost-effective choice.
Light Weighted
Lightweight design reduces structural load requirements and makes handling and installation easier without compromising strength.
i-Panel CATALOG
Sri Lanka's #1 Interior Panel
For over 15 years, i-Panel has shaped the interiors of Sri Lanka’s most distinguished spaces. Proudly manufactured to international standards, our premium solutions are distributed through a strong, islandwide network covering all major districts—delivering architectural precision and enduring performance wherever you are.
Explore our latest ceiling design ideas, interior inspirations, and real project showcases curated just for you.
/* ── i-Panel Pinterest Feed · every rule is scoped to .ipf-wrap / .ipf-lb ── */
/* Design tokens live on the widget, not :root, so they can't clash with the host theme.
The lightbox is appended to , so it gets its own copy. */
.ipf-wrap,.ipf-lb{
--ipf-text:#2D2D2D;
--ipf-text-2:#6E6E6E; /* was #8C8C8C (3.4:1) — now passes WCAG AA for small text */
--ipf-border:#E8E5DF;
--ipf-border-hover:#D1CFC9;
--ipf-bg:#FFFFFF;
--ipf-bg-2:#F7F5F0;
--ipf-accent:#1C38FF;
--ipf-accent-soft:#E8F0FE;
font-family:'Outfit',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
color:var(--ipf-text);
line-height:1.4;
-webkit-font-smoothing:antialiased;
}
/* Scoped reset + light hardening against host-page element styles */
.ipf-wrap,.ipf-wrap *,.ipf-wrap *::before,.ipf-wrap *::after,
.ipf-lb,.ipf-lb *,.ipf-lb *::before,.ipf-lb *::after{box-sizing:border-box;margin:0;padding:0}
.ipf-wrap [hidden],.ipf-lb [hidden]{display:none!important}
.ipf-wrap button,.ipf-lb button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;-webkit-appearance:none;appearance:none;text-transform:none;letter-spacing:normal}
.ipf-wrap a,.ipf-lb a{color:inherit;text-decoration:none}
.ipf-wrap ul{list-style:none}
.ipf-wrap img,.ipf-lb img{border:0}
.ipf-wrap :focus-visible,.ipf-lb :focus-visible{outline:2px solid var(--ipf-accent);outline-offset:2px}
.ipf-icon{width:16px;height:16px;display:inline-block;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;vertical-align:-.15em}
/* Shell */
.ipf-wrap{
width:100%;display:flex;gap:32px;align-items:flex-start;padding:32px;
background:var(--ipf-bg);border:1px solid var(--ipf-border);border-radius:24px;
box-shadow:0 4px 20px rgba(0,0,0,.03);
}
/* Sidebar */
.ipf-wrap .ipf-sidebar{flex:0 0 220px;display:flex;flex-direction:column;gap:18px}
.ipf-wrap .ipf-brand{display:flex;align-items:center;gap:12px}
.ipf-wrap .ipf-avatar{width:44px;height:44px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--ipf-accent-soft);color:var(--ipf-accent)}
.ipf-wrap .ipf-avatar .ipf-icon{width:22px;height:22px}
.ipf-wrap .ipf-brand-name{font-size:16px;font-weight:600;line-height:1.3}
.ipf-wrap .ipf-brand-handle{font-size:12px;color:var(--ipf-text-2);margin-top:2px}
.ipf-wrap .ipf-desc{font-size:13px;line-height:1.6;color:var(--ipf-text-2);border-left:2px solid var(--ipf-border);padding-left:10px}
.ipf-wrap .ipf-stats{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.ipf-wrap .ipf-stat{background:var(--ipf-bg-2);border-radius:10px;padding:10px 12px;text-align:center}
.ipf-wrap .ipf-stat-num{font-size:18px;font-weight:600}
.ipf-wrap .ipf-stat-lbl{font-size:11px;color:var(--ipf-text-2);margin-top:2px}
.ipf-wrap .ipf-follow-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:11px 16px;border-radius:10px;background:var(--ipf-accent);color:#fff;font-size:13px;font-weight:600;transition:opacity .15s}
.ipf-wrap .ipf-follow-btn:hover{opacity:.88}
.ipf-wrap .ipf-tags{display:flex;flex-wrap:wrap;gap:6px}
.ipf-wrap .ipf-tag{font-size:11px;color:var(--ipf-text-2);background:var(--ipf-bg-2);border:1px solid var(--ipf-border);border-radius:999px;padding:3px 10px}
/* Main panel */
.ipf-wrap .ipf-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:20px}
.ipf-wrap .ipf-filters{display:flex;flex-wrap:wrap;gap:8px}
.ipf-wrap .ipf-chip{font-size:12px;padding:5px 12px;border-radius:999px;border:1px solid var(--ipf-border);color:var(--ipf-text);transition:background-color .15s,color .15s,border-color .15s}
.ipf-wrap .ipf-chip:hover{background:var(--ipf-bg-2)}
.ipf-wrap .ipf-chip.is-active{background:var(--ipf-accent);border-color:var(--ipf-accent);color:#fff}
/* Grid — fade-in only: content swaps instantly, then animates from 0 → 1 */
.ipf-wrap .ipf-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;align-items:start;min-height:320px;opacity:1;transition:opacity .2s ease}
.ipf-wrap .ipf-grid.is-entering{opacity:0;transition:none}
/* Pin card */
.ipf-wrap .ipf-pin{display:flex;flex-direction:column;overflow:hidden;border-radius:16px;background:var(--ipf-bg);border:1px solid var(--ipf-border);box-shadow:0 4px 12px rgba(0,0,0,.03);transition:transform .25s,box-shadow .25s,border-color .25s}
.ipf-wrap .ipf-pin:hover,.ipf-wrap .ipf-pin:focus-within{transform:translateY(-4px);box-shadow:0 12px 24px rgba(0,0,0,.06);border-color:var(--ipf-border-hover)}
.ipf-wrap .ipf-pin-open{display:block;width:100%;text-align:left}
.ipf-wrap .ipf-pin-open:focus-visible{outline-offset:-3px;border-radius:16px 16px 0 0}
/* Image area: skeleton and image are stacked, so the fade-in can actually animate */
.ipf-wrap .ipf-pin-media{position:relative;display:block;aspect-ratio:3/4;overflow:hidden;background:var(--ipf-bg-2)}
.ipf-wrap .ipf-pin-skel{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;overflow:hidden}
.ipf-wrap .ipf-pin-skel::after{content:'';position:absolute;inset:0;background:linear-gradient(90deg,transparent 20%,rgba(255,255,255,.55) 50%,transparent 80%);background-size:200% 100%;animation:ipfShimmer 1.6s ease-in-out infinite}
.ipf-wrap .ipf-pin-skel .ipf-icon{display:none;width:24px;height:24px;color:var(--ipf-text-2);opacity:.4}
.ipf-wrap .ipf-pin-media.is-error .ipf-pin-skel::after{display:none}
.ipf-wrap .ipf-pin-media.is-error .ipf-pin-skel .ipf-icon{display:inline-block}
.ipf-wrap .ipf-pin-img{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .3s ease,transform .45s ease}
.ipf-wrap .ipf-pin-media.is-loaded .ipf-pin-img{opacity:1}
.ipf-wrap .ipf-pin-media.is-error .ipf-pin-img{display:none}
.ipf-wrap .ipf-pin-open:hover .ipf-pin-img{transform:scale(1.045)}
.ipf-wrap .ipf-pin-title{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;padding:12px 14px 0;font-size:13px;font-weight:500;line-height:1.45}
.ipf-wrap .ipf-pin-footer{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px 14px 14px}
.ipf-wrap .ipf-pin-view{display:inline-flex;align-items:center;gap:4px;font-size:12px;color:var(--ipf-text-2);transition:color .15s}
.ipf-wrap .ipf-pin-view .ipf-icon{width:13px;height:13px}
.ipf-wrap .ipf-pin-view:hover{color:var(--ipf-accent)}
.ipf-wrap .ipf-pin-save{display:inline-flex;align-items:center;gap:5px;height:28px;padding:0 10px;border-radius:14px;background:var(--ipf-accent);color:#fff;font-size:12px;font-weight:600;transition:transform .15s}
.ipf-wrap .ipf-pin-save .ipf-icon{width:13px;height:13px}
.ipf-wrap .ipf-pin-save:hover{transform:scale(1.05)}
/* Loading placeholders (shown while pins are fetched) */
.ipf-wrap .ipf-pin.is-skeleton{pointer-events:none;box-shadow:none}
.ipf-wrap .ipf-skel-line{position:relative;display:block;height:10px;margin:14px 14px 0;border-radius:5px;background:var(--ipf-bg-2);overflow:hidden}
.ipf-wrap .ipf-skel-line.is-short{width:45%;margin-bottom:18px}
/* Empty state */
.ipf-wrap .ipf-empty{grid-column:1/-1;display:flex;flex-direction:column;align-items:center;gap:12px;padding:48px 24px;text-align:center;font-size:14px;color:var(--ipf-text-2)}
.ipf-wrap .ipf-empty .ipf-icon{width:32px;height:32px;opacity:.5}
.ipf-wrap .ipf-empty-action{font-size:13px;font-weight:600;color:var(--ipf-accent);padding:6px 12px;border-radius:8px;transition:background-color .15s}
.ipf-wrap .ipf-empty-action:hover{background:var(--ipf-accent-soft)}
/* Pagination */
.ipf-wrap .ipf-pag-row{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;padding-top:18px;border-top:1px solid var(--ipf-border)}
.ipf-wrap .ipf-pag-info{font-size:12px;color:var(--ipf-text-2);min-height:1.2em}
.ipf-wrap .ipf-pag-btns{display:flex;align-items:center;gap:4px}
.ipf-wrap .ipf-pag-btn{min-width:36px;height:36px;padding:0 6px;display:flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid var(--ipf-border);color:var(--ipf-text-2);font-size:13px;font-weight:500;transition:background-color .15s,color .15s}
.ipf-wrap .ipf-pag-btn:not(.is-active):not(:disabled):hover{background:var(--ipf-bg-2);color:var(--ipf-text)}
.ipf-wrap .ipf-pag-btn.is-active{background:var(--ipf-accent);border-color:var(--ipf-accent);color:#fff}
.ipf-wrap .ipf-pag-btn:disabled{opacity:.35;cursor:not-allowed}
.ipf-wrap .ipf-pag-gap{padding:0 4px;font-size:13px;color:var(--ipf-text-2)}
/* ── Lightbox (appended to by the script) ──
visibility is delayed on close so the fade-out actually plays */
.ipf-lb{position:fixed;inset:0;z-index:99999;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(0,0,0,0);opacity:0;visibility:hidden;transition:opacity .2s ease,background-color .2s ease,visibility 0s linear .2s}
.ipf-lb.is-open{opacity:1;visibility:visible;background:rgba(0,0,0,.75);transition:opacity .2s ease,background-color .2s ease,visibility 0s}
.ipf-lb .ipf-lb-panel{position:relative;display:flex;flex-direction:column;width:100%;max-width:680px;max-height:calc(100vh - 48px);overflow:hidden;background:var(--ipf-bg);border:1px solid var(--ipf-border);border-radius:24px;transform:scale(.96);transition:transform .2s ease}
.ipf-lb.is-open .ipf-lb-panel{transform:scale(1)}
/* Fixed-height media area: no layout jump when switching between tall and wide images */
.ipf-lb .ipf-lb-media{position:relative;flex:0 0 auto;height:min(60vh,520px);background:var(--ipf-bg-2)}
.ipf-lb .ipf-lb-img{display:block;width:100%;height:100%;object-fit:contain;opacity:0;transition:opacity .25s ease}
.ipf-lb .ipf-lb-media.is-loaded .ipf-lb-img{opacity:1}
.ipf-lb .ipf-lb-spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none;transition:opacity .2s}
.ipf-lb .ipf-lb-spinner::after{content:'';width:32px;height:32px;border:3px solid var(--ipf-border);border-top-color:var(--ipf-accent);border-radius:50%;animation:ipfSpin .8s linear infinite}
.ipf-lb .ipf-lb-media.is-loaded .ipf-lb-spinner,.ipf-lb .ipf-lb-media.is-error .ipf-lb-spinner{opacity:0}
.ipf-lb .ipf-lb-error{position:absolute;inset:0;display:none;flex-direction:column;align-items:center;justify-content:center;gap:8px;font-size:13px;color:var(--ipf-text-2)}
.ipf-lb .ipf-lb-error .ipf-icon{width:28px;height:28px;opacity:.5}
.ipf-lb .ipf-lb-media.is-error .ipf-lb-error{display:flex}
.ipf-lb .ipf-lb-close{position:absolute;top:12px;right:12px;z-index:2;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.55);border:1px solid rgba(255,255,255,.15);color:#fff;transition:background-color .2s}
.ipf-lb .ipf-lb-close:hover{background:rgba(0,0,0,.8)}
/* Dark buttons: the old white-on-cream arrows were nearly invisible */
.ipf-lb .ipf-lb-nav{position:absolute;top:50%;z-index:1;width:40px;height:40px;transform:translateY(-50%);border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45);border:1px solid rgba(255,255,255,.2);color:#fff;transition:background-color .2s}
.ipf-lb .ipf-lb-nav:hover{background:rgba(0,0,0,.7)}
.ipf-lb .ipf-lb-nav .ipf-icon{width:18px;height:18px}
.ipf-lb .ipf-lb-prev{left:16px}
.ipf-lb .ipf-lb-next{right:16px}
.ipf-lb .ipf-lb-body{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:10px;padding:20px 24px 24px}
.ipf-lb .ipf-lb-counter{font-size:12px;color:var(--ipf-text-2)}
.ipf-lb .ipf-lb-title{font-family:inherit;font-size:15px;font-weight:600;line-height:1.4;color:var(--ipf-text);letter-spacing:normal;text-transform:none;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ipf-lb .ipf-lb-desc{font-size:13px;line-height:1.6;color:var(--ipf-text-2)}
.ipf-lb .ipf-lb-actions{display:flex;gap:8px;margin-top:4px}
.ipf-lb .ipf-lb-link{flex:1;display:flex;align-items:center;justify-content:center;gap:8px;padding:10px;border-radius:10px;background:var(--ipf-accent);color:#fff;font-size:13px;font-weight:500}
.ipf-lb .ipf-lb-closebtn{padding:10px 14px;border-radius:10px;border:1px solid var(--ipf-border);color:var(--ipf-text-2);font-size:13px;transition:background-color .15s}
.ipf-lb .ipf-lb-closebtn:hover{background:var(--ipf-bg-2)}
@keyframes ipfShimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
@keyframes ipfSpin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
.ipf-wrap *,.ipf-wrap *::after,.ipf-lb,.ipf-lb *,.ipf-lb *::after{transition:none!important;animation:none!important}
.ipf-wrap .ipf-pin:hover,.ipf-wrap .ipf-pin:focus-within,.ipf-wrap .ipf-pin-open:hover .ipf-pin-img{transform:none}
}
@media (max-width:680px){
.ipf-wrap{flex-direction:column;gap:24px;padding:20px}
.ipf-wrap .ipf-sidebar{flex:none;width:100%}
.ipf-wrap .ipf-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:480px){
.ipf-lb{padding:12px}
.ipf-lb .ipf-lb-panel{border-radius:16px;max-height:calc(100vh - 24px)}
.ipf-lb .ipf-lb-media{height:min(50vh,420px)}
}
@media (max-width:420px){
.ipf-wrap .ipf-grid{grid-template-columns:1fr}
}
(function () {
'use strict';
// Included twice (e.g. two embeds)? Reuse the first copy and just pick up any new roots.
if (window.IPanelFeed && typeof window.IPanelFeed.autoInit === 'function') {
window.IPanelFeed.autoInit();
return;
}
const SVG_NS = 'http://www.w3.org/2000/svg';
const DEFAULT_PROFILE_URL = 'https://www.pinterest.com/ipanelceiling/';
const reducedMotion = window.matchMedia
? window.matchMedia('(prefers-reduced-motion: reduce)')
: { matches: false };
// Keyword fallback for pins without tags. Whole-word match (plus plurals / -ing),
// so "led" no longer matches "instal-led" and "tiled".
const FILTER_KEYWORDS = {
wood: ['wood', 'wooden', 'timber', 'kithul', 'teak', 'oak', 'beam', 'plank'],
modern: ['modern', 'minimalist', 'contemporary', 'slim', 'open-plan'],
luxury: ['luxury', 'hotel', 'premium', 'elegant', 'high-end'],
lighting: ['light', 'lighting', 'pendant', 'lamp', 'recessed', 'ambient', 'led', 'glow']
};
const FILTER_PATTERNS = {};
Object.keys(FILTER_KEYWORDS).forEach((key) => {
FILTER_PATTERNS[key] = new RegExp('\\b(?:' + FILTER_KEYWORDS[key].join('|') + ')(?:s|es|ing)?\\b', 'i');
});
// Demo data — only used on localhost / file:// or with data-ipf-demo (see header comment).
const DEMO_PINS = [
{ title: 'Gray Wood luxury ceiling panel', description: 'Waterproof finish, perfect for bathrooms and kitchens.',
img: 'https://images.unsplash.com/photo-1631889993959-41b4e9c6e3c5?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1631889993959-41b4e9c6e3c5?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['wood', 'luxury'] },
{ title: 'Kithul dark wood ceiling — built to last', description: 'Authentic Sri Lankan kithul timber, naturally termite-resistant.',
img: 'https://images.unsplash.com/photo-1600585154526-990dced4db0d?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1600585154526-990dced4db0d?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['wood', 'luxury'] },
{ title: 'Minimalist white panel living room', description: 'Seamless, modern finish for any ceiling.',
img: 'https://images.unsplash.com/photo-1555041469-a586c61ea9bc?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1555041469-a586c61ea9bc?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['modern'] },
{ title: 'Recessed lighting with slim ceiling panels', description: 'Ambient lighting integrated perfectly with i‑Panel boards.',
img: 'https://images.unsplash.com/photo-1565538810643-b5bdb714032a?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1565538810643-b5bdb714032a?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['lighting', 'modern'] },
{ title: 'Open-plan dining ceiling design', description: 'Inspiration for spacious, light-filled interiors.',
img: 'https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['modern', 'luxury'] },
{ title: 'Natural wood ceiling with beam detailing', description: 'Rustic yet refined – adds character to any room.',
img: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['wood'] },
{ title: 'Contemporary bedroom ceiling panel install', description: 'Fast, clean installation – no mess, no stress.',
img: 'https://images.unsplash.com/photo-1616594039964-ae9021a400a0?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1616594039964-ae9021a400a0?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['modern'] },
{ title: 'Luxury hotel lobby ceiling inspiration', description: 'Premium finishes for high‑end commercial projects.',
img: 'https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['luxury'] },
{ title: 'Pendant light + wood panel combination', description: 'Warm, inviting atmosphere with wooden ceilings and soft lighting.',
img: 'https://images.unsplash.com/photo-1513694203232-719a280e022f?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1513694203232-719a280e022f?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['lighting', 'wood'] },
{ title: 'Waterproof bathroom ceiling panel', description: 'No mould, no warping – perfect for high‑humidity areas.',
img: 'https://images.unsplash.com/photo-1552321554-5fefe8c9ef14?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1552321554-5fefe8c9ef14?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['modern'] },
{ title: 'Fast-install ceiling panels for offices', description: 'Transform your workspace in hours, not days.',
img: 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['modern'] },
{ title: 'Sri Lanka No 1 ceiling solution showroom', description: 'Visit our showroom to experience the i‑Panel difference.',
img: 'https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=400&q=80',
imgFull: 'https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=1200&q=90',
link: 'https://www.pinterest.com/ipanelceiling/', tags: ['luxury'] }
];
/* ── Helpers ─────────────────────────────────────────────── */
// Tiny DOM builder. Strings become text nodes, so pin data can never inject markup.
function h(tag, props, ...children) {
const node = document.createElement(tag);
Object.keys(props || {}).forEach((key) => {
const value = props[key];
if (value == null || value === false) return;
if (key === 'class') node.className = value;
else if (key === 'text') node.textContent = value;
else if (key.slice(0, 2) === 'on') node.addEventListener(key.slice(2), value);
else node.setAttribute(key, value === true ? '' : String(value));
});
children.flat().forEach((child) => { if (child != null) node.append(child); });
return node;
}
function icon(name) {
const svg = document.createElementNS(SVG_NS, 'svg');
svg.setAttribute('class', 'ipf-icon');
svg.setAttribute('aria-hidden', 'true');
svg.setAttribute('focusable', 'false');
const use = document.createElementNS(SVG_NS, 'use');
use.setAttribute('href', '#ipf-i-' + name);
svg.appendChild(use);
return svg;
}
// Only http(s) URLs get through — blocks javascript:, data: and other schemes.
function safeUrl(url, fallback) {
if (typeof url !== 'string' || !url.trim()) return fallback || '';
try {
const parsed = new URL(url, window.location.href);
return parsed.protocol === 'https:' || parsed.protocol === 'http:' ? parsed.href : (fallback || '');
} catch (e) {
return fallback || '';
}
}
// Swap the size segment of a Pinterest CDN URL (e.g. /236x/ → /736x/).
function upgradePinUrl(url, size) {
if (!url || url.indexOf('pinimg.com') === -1) return url;
return url.replace(/\/\d+x\//, '/' + size + '/');
}
function normalizePins(list, profileUrl) {
if (!Array.isArray(list)) {
if (list != null) console.warn('[i-Panel feed] Pin data must be an array; got', typeof list);
return [];
}
const pins = list.map((raw) => {
if (!raw || typeof raw !== 'object') return null;
const img = safeUrl(raw.img);
if (!img) return null;
return {
title: String(raw.title || '').trim(),
description: String(raw.description || '').trim(),
img: img,
imgFull: safeUrl(raw.imgFull) || img,
link: safeUrl(raw.link, profileUrl),
tags: Array.isArray(raw.tags) ? raw.tags.map((t) => String(t).toLowerCase()) : []
};
}).filter(Boolean);
if (pins.length c.classList.contains('is-active'));
let activeFilter = initialChip ? initialChip.getAttribute('data-filter') : 'all';
let allPins = [];
let filtered = [];
let currentPage = 0;
let loadState = 'ready'; // 'loading' | 'ready' | 'error'
/* Lightbox (one per feed, appended to so no ancestor can clip it) */
const lbTitleId = 'ipf-lb-title-' + uid;
const lbImg = h('img', { class: 'ipf-lb-img', alt: '' });
const lbClose = h('button', { class: 'ipf-lb-close', type: 'button', 'aria-label': 'Close' }, icon('close'));
const lbPrev = h('button', { class: 'ipf-lb-nav ipf-lb-prev', type: 'button', 'aria-label': 'Previous pin' }, icon('chevron-left'));
const lbNext = h('button', { class: 'ipf-lb-nav ipf-lb-next', type: 'button', 'aria-label': 'Next pin' }, icon('chevron-right'));
const lbMedia = h('div', { class: 'ipf-lb-media' },
h('div', { class: 'ipf-lb-spinner', 'aria-hidden': 'true' }),
h('div', { class: 'ipf-lb-error' }, icon('photo-off'), h('span', { text: 'Image unavailable' })),
lbImg, lbPrev, lbNext);
const lbCounter = h('p', { class: 'ipf-lb-counter' });
const lbTitle = h('h2', { class: 'ipf-lb-title', id: lbTitleId });
const lbDesc = h('p', { class: 'ipf-lb-desc' });
const lbLink = h('a', { class: 'ipf-lb-link', target: '_blank', rel: 'noopener noreferrer' }, icon('pinterest'), 'View on Pinterest');
const lbCloseBtn = h('button', { class: 'ipf-lb-closebtn', type: 'button' }, 'Close');
const lbEl = h('div', { class: 'ipf-lb', role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': lbTitleId, 'aria-hidden': 'true' },
h('div', { class: 'ipf-lb-panel' },
lbClose,
lbMedia,
h('div', { class: 'ipf-lb-body' }, lbCounter, lbTitle, lbDesc, h('div', { class: 'ipf-lb-actions' }, lbLink, lbCloseBtn))));
document.body.appendChild(lbEl);
let lbPos = 0;
let lbLoadId = 0;
let lastFocused = null;
let savedScroll = null;
const isOpen = () => lbEl.classList.contains('is-open');
function lockScroll() {
const docEl = document.documentElement;
const body = document.body;
const scrollbar = window.innerWidth - docEl.clientWidth;
savedScroll = { overflow: docEl.style.overflow, paddingRight: body.style.paddingRight };
docEl.style.overflow = 'hidden';
if (scrollbar > 0) {
const current = parseFloat(window.getComputedStyle(body).paddingRight) || 0;
body.style.paddingRight = (current + scrollbar) + 'px';
}
}
function unlockScroll() {
if (!savedScroll) return;
document.documentElement.style.overflow = savedScroll.overflow;
document.body.style.paddingRight = savedScroll.paddingRight;
savedScroll = null;
}
function showLightboxPin(pin) {
const loadId = ++lbLoadId;
const many = filtered.length > 1;
lbMedia.classList.remove('is-loaded', 'is-error');
lbTitle.textContent = pin.title || 'Untitled pin';
lbDesc.textContent = pin.description;
lbDesc.hidden = !pin.description;
lbLink.href = pin.link;
lbCounter.textContent = (lbPos + 1) + ' / ' + filtered.length;
lbCounter.hidden = !many;
lbPrev.hidden = !many;
lbNext.hidden = !many;
lbImg.alt = pin.title;
// Try the full-size image first, then the thumbnail. Every handler checks loadId,
// so a late event from a previous pin can never affect the current one.
const full = upgradePinUrl(pin.imgFull, '736x');
const sources = full === pin.img ? [full] : [full, pin.img];
let attempt = 0;
lbImg.onload = () => { if (loadId === lbLoadId) lbMedia.classList.add('is-loaded'); };
lbImg.onerror = () => {
if (loadId !== lbLoadId) return;
attempt += 1;
if (attempt !el.hidden && !el.disabled && el.getClientRects().length > 0);
if (!focusable.length) return;
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (!lbEl.contains(document.activeElement)) {
e.preventDefault();
first.focus();
} else if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
lbClose.addEventListener('click', () => closeLightbox());
lbCloseBtn.addEventListener('click', () => closeLightbox());
lbPrev.addEventListener('click', () => openLightbox(lbPos - 1));
lbNext.addEventListener('click', () => openLightbox(lbPos + 1));
lbEl.addEventListener('click', (e) => { if (e.target === lbEl) closeLightbox(); });
document.addEventListener('keydown', (e) => {
if (!isOpen()) return;
switch (e.key) {
case 'Escape':
e.preventDefault();
closeLightbox();
break;
case 'ArrowLeft':
if (filtered.length > 1) { e.preventDefault(); openLightbox(lbPos - 1); }
break;
case 'ArrowRight':
if (filtered.length > 1) { e.preventDefault(); openLightbox(lbPos + 1); }
break;
case 'Tab':
trapFocus(e);
break;
default:
break;
}
});
/* Cards */
function buildCard(pin, pos) {
const media = h('span', { class: 'ipf-pin-media' }, h('span', { class: 'ipf-pin-skel' }, icon('photo-off')));
// alt="" because the title is right below; a duplicate alt would be read twice.
const img = h('img', { class: 'ipf-pin-img', alt: '', decoding: 'async', width: 474, height: 632 });
img.addEventListener('load', () => media.classList.add('is-loaded'), { once: true });
img.addEventListener('error', () => media.classList.add('is-error'), { once: true });
media.append(img);
img.src = upgradePinUrl(pin.img, '474x');
const label = pin.title || 'Untitled pin';
const openBtn = h('button', {
class: 'ipf-pin-open', type: 'button', 'aria-haspopup': 'dialog',
onclick: () => openLightbox(pos)
}, media, h('span', { class: 'ipf-pin-title', text: label }));
const viewLink = h('a', {
class: 'ipf-pin-view', href: pin.link, target: '_blank', rel: 'noopener noreferrer',
'aria-label': 'View pin: ' + label
}, icon('external'), 'View pin');
// A real link, so it still works if popups are blocked or JS fails.
const saveLink = h('a', {
class: 'ipf-pin-save', href: saveUrlFor(pin), target: '_blank', rel: 'noopener noreferrer',
'aria-label': 'Save: ' + label + ' to Pinterest'
}, icon('bookmark'), 'Save');
saveLink.addEventListener('click', (e) => {
const popup = window.open(saveLink.href, '_blank', 'width=750,height=550');
if (popup) {
popup.opener = null; // the Pinterest page gets no handle back to this one
e.preventDefault();
} // if blocked, the normal new-tab link behaviour takes over
});
return h('li', { class: 'ipf-pin', 'data-pos': pos },
openBtn,
h('div', { class: 'ipf-pin-footer' }, viewLink, saveLink));
}
function activeChipLabel() {
const chip = chips.find((c) => c.getAttribute('data-filter') === activeFilter);
return chip ? chip.textContent.trim() : activeFilter;
}
function buildSkeletonCard() {
return h('li', { class: 'ipf-pin is-skeleton', 'aria-hidden': 'true' },
h('span', { class: 'ipf-pin-media' }, h('span', { class: 'ipf-pin-skel' })),
h('span', { class: 'ipf-skel-line' }),
h('span', { class: 'ipf-skel-line is-short' }));
}
function buildEmpty() {
if (loadState === 'error') {
return h('li', { class: 'ipf-empty' },
icon('photo-off'),
h('p', { text: 'We couldn’t load our latest pins right now.' }),
h('a', { class: 'ipf-empty-action', href: opts.profileUrl, target: '_blank', rel: 'noopener noreferrer' }, 'See them on Pinterest'));
}
if (!allPins.length) {
return h('li', { class: 'ipf-empty' },
icon('empty'),
h('p', { text: 'New pins are on their way — check back soon.' }),
h('a', { class: 'ipf-empty-action', href: opts.profileUrl, target: '_blank', rel: 'noopener noreferrer' }, 'See our boards on Pinterest'));
}
return h('li', { class: 'ipf-empty' },
icon('empty'),
h('p', { text: 'No ' + activeChipLabel().toLowerCase() + ' pins yet.' }),
h('button', { class: 'ipf-empty-action', type: 'button', onclick: () => setFilter('all', { focusChip: true }) }, 'Show all pins'));
}
/* Rendering */
function renderPage(page, settings) {
const cfg = Object.assign({ animate: true, focus: null }, settings || {});
if (loadState === 'loading') {
grid.setAttribute('aria-busy', 'true');
grid.replaceChildren(...Array.from({ length: opts.pageSize }, buildSkeletonCard));
pagInfo.textContent = 'Loading pins…';
pagBtns.replaceChildren();
return;
}
grid.removeAttribute('aria-busy');
const total = filtered.length;
const totalPages = Math.ceil(total / opts.pageSize);
currentPage = Math.min(Math.max(0, page), Math.max(0, totalPages - 1));
const start = currentPage * opts.pageSize;
const slice = filtered.slice(start, start + opts.pageSize);
grid.replaceChildren(...(total ? slice.map((pin, i) => buildCard(pin, start + i)) : [buildEmpty()]));
if (cfg.animate && !reducedMotion.matches) {
grid.classList.add('is-entering');
void grid.offsetWidth; // commit opacity:0 before transitioning back to 1
grid.classList.remove('is-entering');
}
if (total) {
pagInfo.textContent = 'Showing ' + (start + 1) + '–' + (start + slice.length) + ' of ' + total +
(totalPages > 1 ? ' · page ' + (currentPage + 1) + ' of ' + totalPages : '');
} else {
pagInfo.textContent = allPins.length ? 'No pins in this filter' : '';
}
renderPagination(totalPages);
if (cfg.focus) focusPaginationControl(cfg.focus);
}
function pagesToShow(cur, total) {
if (total i);
const pages = [0];
if (cur > 2) pages.push('gap');
for (let i = Math.max(1, cur - 1); i <= Math.min(total - 2, cur + 1); i++) pages.push(i);
if (cur < total - 3) pages.push('gap');
pages.push(total - 1);
return pages;
}
function renderPagination(totalPages) {
pagBtns.replaceChildren();
if (totalPages h('button', {
class: 'ipf-pag-btn' + (state.current ? ' is-active' : ''),
type: 'button',
'aria-label': label,
'aria-current': state.current ? 'page' : null,
'data-role': role,
disabled: !!state.disabled,
onclick: onClick
}, content);
pagBtns.append(makeBtn(icon('chevron-left'), 'Previous page', 'prev',
() => renderPage(currentPage - 1, { focus: 'prev' }), { disabled: currentPage === 0 }));
pagesToShow(currentPage, totalPages).forEach((p) => {
if (p === 'gap') {
pagBtns.append(h('span', { class: 'ipf-pag-gap', 'aria-hidden': 'true' }, '…'));
} else {
pagBtns.append(makeBtn(String(p + 1), 'Page ' + (p + 1), 'page',
() => renderPage(p, { focus: 'page' }), { current: p === currentPage }));
}
});
pagBtns.append(makeBtn(icon('chevron-right'), 'Next page', 'next',
() => renderPage(currentPage + 1, { focus: 'next' }), { disabled: currentPage === totalPages - 1 }));
}
// Buttons are rebuilt on every page change, so put focus back on the matching control.
function focusPaginationControl(which) {
let target = which === 'page' ? null : pagBtns.querySelector('[data-role="' + which + '"]:not(:disabled)');
if (!target) target = pagBtns.querySelector('[aria-current="page"]');
if (target) target.focus();
}
function setFilter(filter, settings) {
const cfg = settings || {};
activeFilter = filter;
chips.forEach((chip) => {
const on = chip.getAttribute('data-filter') === filter;
chip.classList.toggle('is-active', on);
chip.setAttribute('aria-pressed', String(on));
if (on && cfg.focusChip) chip.focus();
});
filtered = allPins.filter((pin) => matchesFilter(pin, filter));
renderPage(0);
}
function setPins(pins) {
if (isOpen()) closeLightbox(false);
loadState = 'ready';
allPins = normalizePins(pins, opts.profileUrl);
if (pinCountEl) pinCountEl.textContent = String(allPins.length); // total, not the filtered count
// Real pins won't cover every category: hide filter chips that would match nothing.
let visibleFilters = 0;
chips.forEach((chip) => {
const filter = chip.getAttribute('data-filter');
const hasPins = filter === 'all' || allPins.some((pin) => matchesFilter(pin, filter));
chip.hidden = !hasPins;
if (hasPins && filter !== 'all') visibleFilters += 1;
});
const filterBar = root.querySelector('.ipf-filters');
if (filterBar) filterBar.hidden = visibleFilters === 0; // "All" on its own is pointless
const activeChip = chips.find((c) => c.getAttribute('data-filter') === activeFilter);
if (!activeChip || activeChip.hidden) activeFilter = 'all';
setFilter(activeFilter);
}
function showLoadError() {
loadState = 'error';
allPins = [];
filtered = [];
if (pinCountEl) pinCountEl.textContent = '—';
const filterBar = root.querySelector('.ipf-filters');
if (filterBar) filterBar.hidden = true;
renderPage(0);
}
// Fetch pins from the server endpoint (ipanel-pins.php), which reads the Pinterest feed.
async function loadPins() {
loadState = 'loading';
renderPage(0);
const controller = typeof AbortController === 'function' ? new AbortController() : null;
const timer = controller ? setTimeout(() => controller.abort(), 15000) : null;
try {
const res = await fetch(opts.pinsUrl, {
headers: { Accept: 'application/json' },
credentials: 'same-origin',
signal: controller ? controller.signal : undefined
});
const data = await res.json().catch(() => null);
if (!res.ok || !data || !Array.isArray(data.pins)) {
throw new Error((data && data.error) || 'HTTP ' + res.status);
}
if (data.stale) console.info('[i-Panel feed] Pinterest is unreachable; showing pins cached at ' + data.updated + '.');
setPins(data.pins);
} catch (err) {
if (opts.demo) {
console.info('[i-Panel feed] ' + opts.pinsUrl + ' unavailable here (' + err.message + ') — showing demo pins (dev/demo mode only).');
setPins(DEMO_PINS);
} else {
console.error('[i-Panel feed] Could not load pins from ' + opts.pinsUrl + ':', err);
showLoadError();
}
} finally {
if (timer) clearTimeout(timer);
}
}
chips.forEach((chip) => {
chip.addEventListener('click', () => setFilter(chip.getAttribute('data-filter')));
});
/* Initial data */
const initial = opts.pins !== undefined ? opts.pins : window.ipnlPins;
if (initial != null) {
setPins(initial);
} else if (opts.pinsUrl) {
loadPins();
} else if (opts.demo) {
console.info('[i-Panel feed] No pin data — showing demo pins (dev/demo mode only).');
setPins(DEMO_PINS);
} else {
console.warn('[i-Panel feed] No pin data yet. Define window.ipnlPins or call IPanelFeed.setPins([...]).');
setPins([]);
}
return {
root: root,
setPins: setPins,
reload: () => (opts.pinsUrl ? loadPins() : undefined),
setFilter: (filter) => setFilter(filter),
goToPage: (page) => renderPage(page),
open: (pos) => openLightbox(pos),
close: () => closeLightbox()
};
}
/* ── Public API ──────────────────────────────────────────── */
const registry = new WeakMap();
const instances = [];
function init(root, options) {
if (!root) return null;
if (registry.has(root)) return registry.get(root);
const instance = createFeed(root, options);
if (instance) {
registry.set(root, instance);
instances.push(instance);
}
return instance;
}
function autoInit() {
document.querySelectorAll('[data-ipf-feed]').forEach((el) => init(el));
}
window.IPanelFeed = {
init: init,
autoInit: autoInit,
instances: instances,
// Convenience for the common single-feed case: IPanelFeed.setPins(data)
setPins: (pins) => instances.forEach((instance) => instance.setPins(pins))
};
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', autoInit);
else autoInit();
})();
Visual Showcase
Inspiring Interior
Gallery Collection
Explore our collection of stunning visuals that showcase our work. Each image tells a unique story and represents our creative vision in transforming interior spaces.
Hall of Excellence
A Legacy of
Innovation & Trust.
Recognized globally and locally for pushing the boundaries of sustainable design and mobile user experience.
2025
Best Mobile User Experience
iPanel Wins Best Mobile User Experience Website at BestWeb.LK 2025, recognized for delivering an outstanding and intuitive digital experience.
2024
Green Brand of the Year
Named ‘Green Brand of the Year’ at SLIM Brand Excellence 2024 for our unwavering commitment to sustainable and eco-friendly practices.
2023
Green Labeled Product
Recognized by the Green Building Council of Sri Lanka for outstanding eco-friendly building solutions.
2016
ISO 9001
German Technology certification ensuring international quality standards.
2015
Best Innovative Product
UPVC ceiling and wall panels awarded at the Kadella Exhibition for revolutionary design.
Tell us about your space and our specialists will handle the rest. Whether it’s a private estate, luxury hotel, or commercial development, our team provides tailored material guidance and precision quotations.