Ajándékozz kollégáidnak, partnereidnek körvonal termékeket! Minden korosztály körében nagyon népszerűek, olyan ajándék, amit valóban értékelnek majd a kollégák és partnerek.
Egyedi, személyes, figyelmes.
★★★★★ 4,8/5,0 (kiváló) 100 000+ vásárló
Special offers for business customers
0 produktů – sleva 10 %
20 produktů – sleva 20 %
Nad 100 kusů nás prosím kontaktujte!
Pokud plánuješ objednávat pravidelně, zaregistruj se jako náš velkoobchodní partner.
Můžeš si libovolně vybrat ze všech našich produktů.
Stačí je vložit do košíku – sleva se automaticky uplatní!
Nabídka platí do odvolání.
Card Games
The discounts are applied automatically once the items have been added to your cart.
All orders are shipped directly from stock. For orders of fewer than 100 items placed before 2 PM, we usually pack them and hand them over to the courier the same day. For larger orders, please allow an additional 1–2 days.
What order sizes can you handle?
Rendeléseket 100 termékig automatikusan feldolgozzuk. Nagyobb, akár több ezer darabos rendelésre je van lehetőség, gyors szállítással, azonban ilyenkor kérünk, hogy keress minket: business@korvonal.com
, which is BEFORE
// window.Shopify.currency exists — an eager HUF gate here silently exits on
// every page load (live-verified 2026-08-16: the preview param never stuck).
// So: arm resolution and the settings flip happen now (they need no
// currency), and the HUF gate runs at DOMContentLoaded, reverting the flip
// for non-HUF visitors before the component initialises.
// ── Preview plumbing (sticky per session, excluded from bookkeeping) ──────
var preview = null;
try {
var m = window.location.search.match(/[?&]consentexp=([a-z]+)/);
if (m) {
if (m[1] === 'off') sessionStorage.removeItem('kvce_prev');
else sessionStorage.setItem('kvce_prev', m[1] === 'control' ? 'control' : 'treatment');
}
preview = sessionStorage.getItem('kvce_prev');
} catch (e) { /* storage blocked: preview simply unavailable */ }
if (MODE === 'preview' && !preview) return;
// ── Arm ───────────────────────────────────────────────────────────────────
var arm;
var bookkeeping = MODE === 'ab' && !preview;
if (preview) arm = preview;
else if (MODE === 'on') arm = 'treatment';
else {
try {
arm = localStorage.getItem('kv_consent_arm');
if (arm !== 'control' && arm !== 'treatment') {
arm = Math.random() < 0.5 ? 'control' : 'treatment';
localStorage.setItem('kv_consent_arm', arm);
}
} catch (e) {
// Storage blocked: unassignable and unmeasurable, so leave the default
// banner and stay out of the books rather than pollute an arm.
return;
}
}
function visitorId() {
try {
var v = localStorage.getItem('otto_visitor_id');
if (!v) {
v = window.crypto && crypto.randomUUID ? crypto.randomUUID() : 'v-' + Date.now() + '-' + Math.random().toString(16).slice(2);
localStorage.setItem('otto_visitor_id', v);
}
return v;
} catch (e) { return null; }
}
function track(name, idSuffix, extra) {
if (!bookkeeping) return;
var vid = visitorId();
if (!vid) return;
var data = { experimentKey: KEY, variant: arm };
if (extra) for (var k in extra) data[k] = extra[k];
try {
fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
keepalive: true,
body: JSON.stringify({ events: [{
id: KEY + ':' + vid + (idSuffix ? ':' + idSuffix : ''),
eventName: name, clientId: vid,
occurredAt: new Date().toISOString(), data: data
}] })
}).catch(function () {});
} catch (e) { /* bookkeeping must never break the page */ }
}
function dayKey() { return new Date().toISOString().slice(0, 10); }
// ── Treatment step 1: flip Pandectes' own modality settings pre-init ──────
// Their component snapshots window.pandectesBannerSettings at init; this
// snippet renders before
, which in practice runs first. If it does
// not, step 3's fallback covers the gap.
var flipped = false;
if (arm === 'treatment') {
try {
var s = window.pandectesBannerSettings;
if (s && s.theme) { s.theme.isModal = false; s.theme.scrollLock = false; flipped = true; }
} catch (e) { /* fall through to the CSS fallback */ }
}
function revertFlip() {
if (!flipped) return;
try {
var s2 = window.pandectesBannerSettings;
if (s2 && s2.theme) { s2.theme.isModal = true; s2.theme.scrollLock = true; }
} catch (e) {}
}
var COMPACT_CSS =
// Scoped to the FIRST-VISIT view only. Live-verified 2026-08-16 at
// 375x812: this store's first-visit view renders `.dialog.notice`
// (231px tall by default; the button row is `.actions`, the text is
// `.intro`/#message inside `.body`). This CSS measures 182px on the
// real banner with both buttons fully visible. `.banner` is kept as an
// alias in case a Pandectes config change renames the view. The
// preferences dialog (a different view class) keeps its full layout,
// so the granular consent choices render exactly as Pandectes designed
// them.
//
// DELIBERATELY NO max-height/overflow cap: a cap that guesses low clips
// the consent BUTTONS (caught live at 148px), and a banner whose accept
// and decline are unreachable is a compliance bug, not a compact layout.
// Height comes from shrinking the parts instead.
'.dialog.notice,.dialog.banner{padding:10px 14px 12px;}' +
'.dialog.notice .header,.dialog.banner .header{margin:0;padding:0;min-height:0;}' +
'.dialog.notice .header .title,.dialog.banner .header .title{font-size:14px;margin:0;}' +
'.dialog.notice #message,.dialog.banner #message{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:12px;line-height:1.35;}' +
'.dialog.notice .intro ul,.dialog.notice .details,.dialog.banner .intro ul,.dialog.banner .details{display:none;}' +
'.dialog.notice .actions,.dialog.banner .actions{display:flex;flex-wrap:nowrap;gap:8px;margin:8px 0 0;padding:0;}' +
'.dialog.notice .actions button,.dialog.banner .actions button{flex:1;padding:9px 8px;font-size:13px;min-height:0;margin:0;}' +
'.overlay{display:none!important;}';
var seenFired = false;
function onBannerAppears(host) {
// Treatment step 2: inject the compact stylesheet into the open shadow
// root. A separate node, so Pandectes' own #pandectes-cmp-custom-styles
// (their dashboard CSS) is never touched.
if (arm === 'treatment') {
try {
var root = host.shadowRoot;
if (root && !root.getElementById('kv-consent-compact')) {
var st = document.createElement('style');
st.id = 'kv-consent-compact';
st.textContent = COMPACT_CSS;
root.appendChild(st);
}
} catch (e) { /* selectors missed: default banner, fail open */ }
// Treatment step 3: if the settings flip lost the init race, the
// component may have locked body scroll before we got here. One
// restore + one delayed recheck — not an observer war.
var unlock = function () {
try {
if (getComputedStyle(document.body).overflow === 'hidden') document.body.style.overflow = 'visible';
if (getComputedStyle(document.documentElement).overflow === 'hidden') document.documentElement.style.overflow = 'visible';
} catch (e) {}
};
unlock();
setTimeout(unlock, 600);
}
if (!seenFired) {
seenFired = true;
track('experiment_exposure', '', null); // once per visitor (upsert on stable id)
track('consent_seen', 'seen-' + dayKey(), null); // daily denominator
}
}
// The component mounts asynchronously; watch for it rather than racing it.
// A visitor with stored consent never mounts a banner → observer sees
// nothing → no exposure, which is exactly the right denominator.
function watch() {
var existing = document.querySelector('pandectes-cmp');
if (existing) { onBannerAppears(existing); return; }
var mo = new MutationObserver(function () {
var el = document.querySelector('pandectes-cmp');
if (el) { mo.disconnect(); onBannerAppears(el); }
});
mo.observe(document.documentElement, { childList: true, subtree: true });
// A banner that has not mounted within a minute is not mounting on this
// page view. Stop observing rather than watching forever.
setTimeout(function () { mo.disconnect(); }, 60000);
}
// The deferred HUF gate: non-HU visitors get the flip reverted (before the
// component initialises, which also happens after DOMContentLoaded) and are
// never bucketed, watched, or stamped.
function boot() {
if (!(window.Shopify && window.Shopify.currency && window.Shopify.currency.active === 'HUF')) {
revertFlip();
return;
}
watch();
stampCart();
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
else boot();
// ── Choice — Shopify's documented event, not Pandectes internals ──────────
document.addEventListener('visitorConsentCollected', function (e) {
var d = (e && e.detail && e.detail.customerPrivacy) || {};
track('consent_choice', 'choice-' + dayKey(), {
analytics: d.analyticsProcessingAllowed === true,
marketing: d.marketingAllowed === true
});
});
// ── Cart attribute stamp (both arms — a one-armed experiment cannot be read)
// Fired once per session when a cart exists. A cart created later on this
// same page view gets stamped on the next navigation, which every checkout
// path includes.
function stampCart() {
if (!bookkeeping) return;
try {
if (/(^|;\s*)cart=/.test(document.cookie) && !sessionStorage.getItem('kvce_stamped')) {
sessionStorage.setItem('kvce_stamped', '1');
fetch('/cart/update.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ attributes: { _experiment_consent: KEY + ':' + arm } })
}).catch(function () {
try { sessionStorage.removeItem('kvce_stamped'); } catch (e) {}
});
}
} catch (e) { /* never block the page on bookkeeping */ }
}
})();