المكوّنات · نجاح بخطوة تالية
نجاح بخطوة تالية
لا يقف عند «تمّ» — يعطي المرجع والإجراء الذي يليه
12 تصاميم من هذه العائلة
<div class="fb fbk"><div class="wrap">
<span class="tick" aria-hidden="true">
<svg viewBox="0 0 32 32" width="32" height="32" fill="none">
<circle cx="16" cy="16" r="14" stroke="currentColor" stroke-width="2" class="ring"/>
<path d="M10 16.5l4 4 8-8.5" stroke="currentColor" stroke-width="2.4"
stroke-linecap="round" stroke-linejoin="round" class="chk"/>
</svg></span>
<h4 data-ar="تأكّد حجزك" data-en="Your booking is confirmed">تأكّد حجزك</h4>
<p data-ar="أُرسلت بطاقة الصعود إلى بريدك، وتجدها أيضًا في «رحلاتي»." data-en="Your boarding pass was emailed, and it is also under “My trips”.">أُرسلت بطاقة الصعود إلى بريدك، وتجدها أيضًا في «رحلاتي».</p>
<div class="ref"><span data-ar="رقم الحجز" data-en="Booking ref">رقم الحجز</span>
<code class="code"></code>
<button class="cp" aria-label="نسخ">⧉</button></div>
<div class="acts">
<button class="p" data-ar="أضف إلى التقويم" data-en="Add to calendar">أضف إلى التقويم</button>
<button class="s" data-ar="اختر مقعدك" data-en="Choose your seat">اختر مقعدك</button>
</div>
<p class="out" role="status"></p>
</div></div>
/* pt-scoped */
/* feedback-success — شركة طيران */
.fbk{width:100%;height:100%;display:flex;flex-direction:column;
font-size:10px;color:var(--pt-text-secondary);overflow:hidden}
.fbk h4{margin:0;font-size:11px;color:var(--pt-text-primary);font-weight:600;line-height:1.5}
.fbk p{margin:0;font-size:9px;line-height:1.85;color:var(--pt-text-muted)}
.fbk .num{font-variant-numeric:tabular-nums}
.fbk button{font:inherit;cursor:pointer}
.fbk button:focus-visible, .fbk input:focus-visible, .fbk a:focus-visible{
outline:2px solid var(--pt-focus-ring);outline-offset:2px}
.fbk button:disabled{cursor:not-allowed;opacity:.45}
/* كل حالة تُعلَن لقارئ الشاشة: تغيّرٌ لا يُرى ولا يُسمَع لم يحدث */
.fbk [role=status], .fbk [role=alert]{display:block}
@media(pointer:coarse){.fbk button{min-height:44px}
}
/* شخصية: علامة صحّ ترتسم، مرجع قابل للنسخ، انحناء كبير */
.fbk{align-items:center;justify-content:center;padding:12px}
.fbk .wrap{display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;
max-width:280px;padding:13px 15px;border-radius:var(--pt-radius-xl);
background:var(--pt-surface);
border:1px solid color-mix(in srgb,var(--pt-accent) 38%,transparent)}
.fbk .tick{color:var(--pt-accent)}
.fbk .ring{stroke-dasharray:88;stroke-dashoffset:88;animation:fbring .5s ease-out forwards}
.fbk .chk{stroke-dasharray:22;stroke-dashoffset:22;animation:fbchk .3s .42s ease-out forwards}
@keyframes fbring{to{stroke-dashoffset:0}}
@keyframes fbchk{to{stroke-dashoffset:0}}
@media(prefers-reduced-motion:reduce){.fbk .ring, .fbk .chk{animation:none;stroke-dashoffset:0}
}
.fbk .ref{display:flex;align-items:center;gap:6px;padding:4px 9px;
border-radius:var(--pt-radius-full);background:var(--pt-bg-inset);font-size:8px;
color:var(--pt-text-muted)}
.fbk .code{font-family:var(--pt-font-mono);font-size:9.5px;color:var(--pt-text-primary);
letter-spacing:.08em;user-select:all}
.fbk .cp{width:16px;height:16px;min-height:0;padding:0;border:0;border-radius:var(--pt-radius-xs);
background:transparent;color:var(--pt-text-muted);font-size:9px}
.fbk .cp:hover{color:var(--pt-accent)}
.fbk .acts{display:flex;gap:5px;margin-top:2px}
.fbk .acts button{padding:6px 12px;border-radius:var(--pt-radius-full);font-size:8.5px;
font-weight:600}
.fbk .p{border:0;background:var(--pt-accent);color:var(--pt-color-ink-900)}
.fbk .s{border:1px solid var(--pt-border-default);background:transparent;
color:var(--pt-text-secondary)}
.fbk .s:hover{border-color:var(--pt-accent);color:var(--pt-accent)}
.fbk .out{font-size:8px;min-height:10px;color:var(--pt-accent)}
/* يعمل داخل إطار معزول — لا يعتمد على شيء خارجه */
/* pt-remount — يعاد التركيب عند تبديل اللغة */
(function () {
var host = document.querySelector('.fbk');
if (!host) return;
var snapshot = host.innerHTML;
var timers = [];
var ac = null;
/* الجسم كما كتبه المولِّد. يستقبل بدائل مظلَّلة لـ root وdocument
والمؤقّتات، فينظّف نفسه دون أن يعرف أنه قابل لإعادة التركيب. */
function run(root, document, setTimeout, setInterval) {
var ar = document.documentElement.lang !== 'en';
var n = function (v, d) { return Number(v).toLocaleString('en-US', {
minimumFractionDigits: d || 0, maximumFractionDigits: d || 0 }); };
/* المرجع مشتقّ لا عشوائي: يبقى ثابتًا لو أُعيد بناء المكوّن عند تبديل اللغة */
var SEED = 'SV553-24AUG';
var code = SEED.split('').reduce(function (a, c) { return (a * 31 + c.charCodeAt(0)) >>> 0; }, 7);
var REF = 'PT' + String(code).slice(0, 6);
root.querySelector('.code').textContent = REF;
var out = root.querySelector('.out');
function say(m) { out.textContent = m; setTimeout(function () { out.textContent = ''; }, 1800); }
root.querySelector('.cp').addEventListener('click', function () {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(REF).then(
function () { say(ar ? '✓ نُسخ رقم الحجز' : '✓ Reference copied'); },
function () { say(ar ? 'تعذّر النسخ — حدّده يدويًّا' : 'Copy failed — select it manually'); });
} else say(ar ? 'الحافظة غير متاحة' : 'Clipboard unavailable');
});
root.querySelector('.p').addEventListener('click', function () {
say(ar ? '✓ أُضيفت الرحلة إلى تقويمك' : '✓ Flight added to your calendar');
});
root.querySelector('.s').addEventListener('click', function () {
say(ar ? 'جارٍ فتح خريطة المقاعد…' : 'Opening the seat map…');
});
}
function mount() {
ac = new AbortController();
var real = window.document;
/* وسيط يمرّر كل شيء إلى المستند الحقيقي، ويعلّق كل مستمع بإشارة
تُقطع عند إعادة التركيب — فلا يبقى مستمع من نسخة ماتت. */
var doc = new Proxy(real, {
get: function (t, k) {
if (k === 'addEventListener') {
return function (type, fn, opts) {
var o = (opts && typeof opts === 'object') ? Object.assign({}, opts)
: { capture: !!opts };
o.signal = ac.signal;
return t.addEventListener(type, fn, o);
};
}
var v = t[k];
return typeof v === 'function' ? v.bind(t) : v;
}
});
function track(fn) {
return function (f, ms) { var id = fn(f, ms); timers.push(id); return id; };
}
run(host, doc, track(window.setTimeout.bind(window)),
track(window.setInterval.bind(window)));
}
function unmount() {
if (ac) ac.abort();
// المعرّفان يتشاركان فضاءً واحدًا في المتصفّح، فالإلغاء المزدوج آمن
timers.forEach(function (id) { window.clearTimeout(id); window.clearInterval(id); });
timers = [];
host.innerHTML = snapshot;
}
mount();
addEventListener('pt-lang', function () { unmount(); mount(); });
})();
# Success with a Next Step
**Role:** You are an Arabic-first UI designer and front-end engineer. Read the whole
specification before writing a single line, then follow it literally. If two requirements
conflict, favour usability over visual effect.
**Goal:** Success with a Next Step — Does not stop at “done” — it gives the reference and what comes next
**Why this component matters:** A success screen that only says “done” abandons the user at the exact moment they are most willing to act. Give the reference number and the single most likely next step.
**Direction:** Genuine RTL — not a mirrored Latin layout. Use logical properties
(`margin-inline-start`, `padding-inline`, `inset-inline-start`, `text-align: start`),
never physical ones (`margin-left`, `left`). The layout must flip with `dir` on its own,
with no duplicated rules.
**Typography:** Cairo for Arabic, IBM Plex Sans for Latin. Arabic line-height must be
`0.18` higher than the Latin equivalent — dots, hamzas and maddas need more vertical room.
Arabic font-size runs `1.06×` the Latin size at the same optical weight.
**Numerals:** Western digits in both languages (`1,234.50`). Only the currency changes:
`ر.س` **after** the number in Arabic, `$` **before** it in English. Jordanian dinar
uses **three** decimal places, not two.
**Colors:** Dark mode — background `#0D142B` · surfaces `#211F54` · borders `#545C91` · text `#918FC2`.
Accent `#ADA9E8` must never exceed 8% of the screen area.
**Language:** Bilingual — every string carries both Arabic and English, and the layout
flips with `dir` automatically.
**States:** `default` · `hover` · `focus` · `active` · `disabled` · `loading` · `error`.
Do not design the resting state alone.
**Accessibility:** Contrast ratio at least `4.5:1`, complete keyboard navigation,
visible focus rings, and honour `prefers-reduced-motion`.
**Output:** Clean HTML and CSS in two separate files. No frameworks, no libraries,
no external dependencies.