/* ============================================================
   tree.css — لوحة الشجرة، بطاقات الأشخاص، الروابط
   The pan/zoom canvas, person cards, connector links, panels.
   ============================================================ */

/* ---------- 1. Canvas ---------- */
.canvas {
  position: relative;
  flex: 1;
  overflow: hidden;
  touch-action: none;            /* نتحكم بالسحب والتكبير يدوياً */
  cursor: grab;
  background-color: var(--bg);
  background-image:
    radial-gradient(circle at 1px 1px, var(--bg-grid) 1.4px, transparent 0);
  background-size: 26px 26px;
  contain: layout paint;
}
.canvas--grabbing { cursor: grabbing; }
.canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* اللوحة نفسها LTR ومثبّتة على الزاوية العليا اليسرى
   حتى تبقى الإحداثيات (x, y) صحيحة مهما كان اتجاه الصفحة. */
.viewport {
  position: absolute;
  top: 0;
  left: 0;
  direction: ltr;
  transform-origin: 0 0;
  will-change: transform;
}

.links {
  position: absolute;
  inset-block-start: 0;
  left: 0;
  overflow: visible;
  pointer-events: none;
}
.link {
  fill: none;
  stroke: var(--g, var(--border-strong));
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .55;
  transition: opacity .2s, stroke-width .2s;
}
.link--active { opacity: 1; stroke-width: 3; }
.link--dim { opacity: .12; }

.nodes { position: absolute; inset-block-start: 0; left: 0; }

/* ---------- 2. Person card ---------- */
.node {
  position: absolute;
  inset-block-start: 0;
  left: 0;
  width: var(--node-w, 136px);
  direction: rtl;
  will-change: transform;
}

.node__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 10px 8px 12px;
  border: 1px solid var(--border);
  border-block-start: 3px solid var(--g);
  border-radius: var(--r-lg);
  background: color-mix(in oklab, var(--g) 7%, var(--surface));
  box-shadow: var(--shadow-sm);
  font: inherit;
  color: inherit;
  text-align: center;
  cursor: pointer;
  transition: box-shadow .18s, border-color .18s, transform .12s, opacity .2s;
}
.node__card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--g);
  transform: translateY(-2px);
}

.node--selected .node__card {
  border-color: var(--g);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--g) 45%, transparent), var(--shadow-md);
}
.node--match .node__card {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 60%, transparent), var(--shadow-md);
}
.node--dim { opacity: .3; }

/* الصورة / photo */
.node__photo {
  position: relative;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--surface-sunk);
  box-shadow: 0 0 0 3px var(--g), 0 0 0 5px color-mix(in oklab, var(--g) 22%, transparent);
  flex: none;
}
.node__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* من لا صورة له: دائرة فارغة بلون جيله، لا حرف — الاسم تحتها كاملاً.
   No photo: an empty circle in the generation's colour, no letter — the
   full name is written right underneath it. */
.node__photo:empty {
  background: color-mix(in oklab, var(--g) 16%, var(--surface-sunk));
}

/* الاسم تحت الصورة / name under the photo */
.node__name {
  font-family: var(--font-head);
  /* قياسات SF Mada أصغر بصرياً من الخطّ الذي سبقه عند نفس الرقم، فرُفعت
     الأربعة معاً — الاسم والإقامة على البطاقتين — لتبقى النسبة بينها.
     SF Mada reads smaller than the face it replaced at the same size, so
     all four sizes moved together and their ratios held. */
  font-size: .95rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--text);
  /* `pre-line` لا `normal`: الكسرة التي كتبها المحرّر تُحترم، والمسافات
     الزائدة تُطوى كالمعتاد. بدونها يُطبع السطران متلاصقين في سطر.
     `pre-line`, not `normal`: an editor's line break is honoured while
     runs of spaces still collapse. */
  white-space: pre-line;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* البطاقة بلا صورة: الاسم يرث حيّز الدائرة فيكبر ويتوسّط.
   `min-height` يطابق `BARE_H` في layout.js — عليه تُحسب بداية وصلات هذه
   البطاقة إلى أبنائها، فإن غُيّر أحدهما غُيّر الآخر معه.
   A photo-less card: the name inherits the circle's room, grows and
   centres. `min-height` must match `BARE_H` in layout.js. */
.node--bare .node__card {
  min-height: 104px;
  justify-content: center;
}
.node--bare .node__name {
  font-size: 1.4rem;
  line-height: 1.25;
  /* ثلاثة أسطر لا سطران: كسرةٌ مكتوبة قد يلتفّ أحد شطريها، والقصّ عند
     سطرين كان يبتر الاسم بعد أن قرّر المحرّر أين يكسره. */
  -webkit-line-clamp: 3;
  line-clamp: 3;
}

/* بطاقة الزوجة: صندوقٌ كبقيّة البطاقات — يميّزها لونها الخاصّ والحدّ
   المتقطّع وخلوّها من الصورة، لا شكلٌ مختلف. */
.node--wife .node__card {
  border-style: dashed;
  background: color-mix(in oklab, var(--g) 8%, var(--surface));
}
.node--wife .node__name { font-weight: 600; }

/* مكان الإقامة تحت الاسم — سطر واحد يُقصّ بالنقاط.
   nowrap مقصود: لو التفّ لسطرين لطالت البطاقة حتى تلامس الجيل الذي
   تحتها، والفجوة بين الأجيال ٦٢ بكسل لا تحتمل ذلك على كل بطاقة.
   والهامش السالب يُلصقه بالاسم بدل أن يقف في منتصف المسافة بينه وبين
   السنوات، ويستردّ جزءاً من الارتفاع الذي أضافه. */
.node__where {
  max-width: 100%;
  margin-block-start: -3px;
  /* أصغر من الاسم دائماً وأكبر من السنوات: ٠٫٧٢ تحت اسمٍ ٠٫٨ على البطاقة
     المصوّرة، و٠٫٨٥ تحت اسمٍ ١٫٢ على العارية — فالنسبة محفوظة في الحالتين.
     Always smaller than the name and larger than the years: .72 under a
     .8 name on a photo card, .85 under a 1.2 name on a bare one. */
  font-size: .82rem;
  line-height: 1.3;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* البطاقة العارية اسمها ١٫٢rem، فيكبر تابعه معه ويبقى دونه */
.node--bare .node__where { font-size: 1rem; }

/*
   «للتحديث : فلان» — بلونٍ خاصّ خارج دورة الأجيال، فلا يُقرأ كأنّه
   جيلٌ آخر ولا يلتبس بمكان الإقامة تحته. ويُقصّ بالنقاط كما يُقصّ:
   البطاقة ١٣٦ بكسلاً، والأسماء تطول.
   Its own colour, outside the generation cycle, so it reads as a note
   rather than another generation — and clipped like the line above it.
*/
.node__keeper {
  position: absolute;
  /* فوق البطاقة في الفرجة التي بين الجيلين، لا داخلها: البطاقة للشخص
     وهذه صفةُ إدارةٍ عليه. وتمتدّ على الجانبين إن طال الاسم — الفرجة
     خالية والبطاقة ١٣٦ بكسلاً لا تسع سطراً كاملاً.
     Above the card, in the gap between generations rather than inside it:
     the card is the person, this is a note about him. It overflows to
     both sides when the name is long — the gap is empty and a 136px card
     could not hold the line anyway. */
  inset-block-end: calc(100% + 4px);
  inset-inline: 0;
  text-align: center;
  font-size: .72rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--keeper);
  white-space: nowrap;
  pointer-events: none;      /* لا تحجب زرّ الإضافة تحتها */
}
.node--bare .node__keeper { font-size: .82rem; }
.node__keeper[hidden] { display: none; }

.node__meta {
  font-size: .68rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  direction: ltr;
}

.node__gen {
  position: absolute;
  inset-block-start: 6px;
  inset-inline-start: 8px;
  font-size: .62rem;
  font-weight: 700;
  color: var(--g);
  opacity: .8;
  font-variant-numeric: tabular-nums;
}

/* زر طيّ/فتح الأبناء / collapse toggle */
.node__toggle {
  position: absolute;
  inset-block-end: -13px;
  inset-inline-start: 50%;
  transform: translateX(50%);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  height: 26px;
  padding: 0 7px;
  border: 2px solid var(--g);
  border-radius: 999px;
  background: var(--surface);
  color: var(--g);
  font-family: var(--font-body);
  font-size: .72rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  z-index: 2;
  transition: background .15s, color .15s;
  font-variant-numeric: tabular-nums;
}
.node__toggle:hover { background: var(--g); color: var(--surface); }
.node__toggle--open { background: var(--g); color: var(--surface); }
.node__toggle--open:hover { opacity: .82; }

/* زر إضافة ابن (لوحة الإدارة) / add-son button, admin only.
   ظاهر دائماً — الإخفاء حتى المرور بالفأرة يجعل الإضافة صعبة الاكتشاف.
   Always visible: hiding it until hover made adding names undiscoverable. */
.node__add {
  position: absolute;
  inset-block-start: -10px;
  inset-inline-end: -10px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px; height: 30px;
  border: 2px solid var(--surface);
  border-radius: 50%;
  background: var(--success);
  color: #fff;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-md);
  transition: transform .14s, filter .14s;
  z-index: 4;
}
.node__add:hover { transform: scale(1.15); filter: brightness(1.08); }
.node__add:active { transform: scale(.96); }

/* وضع الرؤية البعيدة: عند التصغير الشديد نرسم خرزات ملوّنة فقط
   Low-detail mode: at far zoom we draw coloured beads instead of
   full cards, so a tree with thousands of people stays smooth. */
.node--far { pointer-events: none; }
.node__bead {
  width: 84px;
  height: 84px;
  margin: 10px auto 0;
  border-radius: 50%;
  background: var(--g);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--g) 25%, transparent);
}
.node--far.node--selected .node__bead { box-shadow: 0 0 0 10px color-mix(in oklab, var(--g) 45%, transparent); }
.node--far.node--match .node__bead { box-shadow: 0 0 0 10px color-mix(in oklab, var(--accent) 70%, transparent); }

/* ---------- 3. Floating toolbar ---------- */
.toolbar {
  position: absolute;
  inset-block-end: 16px;
  inset-inline-start: 50%;
  transform: translateX(50%);
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 5px;
  border-radius: 999px;
  background: color-mix(in oklab, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  z-index: 30;
}
:dir(ltr) .toolbar { transform: translateX(-50%); }

.toolbar .btn--icon {
  width: 36px;
  min-height: 36px;
  border: none;
  border-radius: 50%;
  background: transparent;
}
.toolbar .btn--icon:hover:not(:disabled) { background: var(--surface-sunk); }

.toolbar__sep {
  width: 1px;
  height: 22px;
  background: var(--border);
  margin: 0 3px;
}

.toolbar__zoom {
  min-width: 46px;
  text-align: center;
  font-size: .74rem;
  font-weight: 700;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* ---------- 4. Generation legend ---------- */
.legend {
  position: absolute;
  inset-block-start: 12px;
  inset-inline-start: 12px;
  max-width: 190px;
  padding: 8px 10px;
  border-radius: var(--r-md);
  background: color-mix(in oklab, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  z-index: 25;
  font-size: .74rem;
}
.legend__head {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-head);
  font-size: .76rem;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
}
.legend__caret { margin-inline-start: auto; color: var(--text-faint); transition: transform .2s; }
.legend[data-open="false"] .legend__caret { transform: rotate(-90deg); }
.legend[data-open="false"] .legend__list { display: none; }

.legend__list {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  max-height: 42vh;
  overflow-y: auto;
}
.legend__item {
  display: flex;
  align-items: center;
  gap: 7px;
  color: var(--text-muted);
}
.legend__swatch {
  width: 12px; height: 12px;
  border-radius: 3px;
  background: var(--g);
  flex: none;
}
.legend__count { margin-inline-start: auto; font-variant-numeric: tabular-nums; color: var(--text-faint); }

/* ---------- 5. Search ---------- */
.search { position: relative; flex: none; }

.search__input {
  width: 190px;
  padding-block: 7px;
  padding-inline: 12px 32px;   /* مساحة لأيقونة البحث في نهاية الحقل */
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface-2);
  font-size: .85rem;
  transition: width .2s, border-color .15s, box-shadow .15s;
}
.search__input:focus {
  outline: none;
  width: 240px;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 20%, transparent);
}
.search__icon {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: 11px;
  transform: translateY(-50%);
  color: var(--text-faint);
  font-size: .85rem;
  pointer-events: none;
}

.search__results {
  position: absolute;
  inset-block-start: calc(100% + 6px);
  inset-inline-start: 0;
  width: min(300px, 78vw);
  max-height: 320px;
  overflow-y: auto;
  margin: 0;
  padding: 5px;
  list-style: none;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-lg);
  z-index: 60;
}
.search__results:empty { display: none; }

.search__result {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 7px 9px;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  text-align: start;
  cursor: pointer;
}
.search__result:hover, .search__result[aria-selected="true"] { background: var(--surface-sunk); }

.search__avatar {
  width: 30px; height: 30px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-sunk);
  box-shadow: 0 0 0 2px var(--g);
  flex: none;
}
/* الاسم فوق ونسبه تحته — لا بدّ من عمود، فالعنصران span بطبيعتهما سطريان
   فيتدفّقان كنصّ واحد ولا يعمل القصّ بالنقاط عليهما.
   Name above, lineage below: both are spans, so without a column they run
   together as one line and their ellipsis rules never apply. */
.search__text { min-width: 0; display: flex; flex-direction: column; }
.search__name { font-size: .84rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search__lineage { font-size: .7rem; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search__empty { padding: 12px; text-align: center; color: var(--text-muted); font-size: .82rem; }

/* ---------- 6. Detail / edit panel ---------- */
.panel {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  width: min(360px, 92vw);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-inline-start: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  z-index: 120;   /* فوق الحجاب (veil = 100) حتى تعمل اللوحة والشجرة فارغة / above the veil so the editor works on an empty tree */
  transform: translateX(-100%);
  transition: transform .26s cubic-bezier(.32, .72, 0, 1);
}
:dir(ltr) .panel { transform: translateX(100%); }
.panel[data-open="true"] { transform: none; }
.panel[hidden] { display: none; }

.panel__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 14px;
  border-block-end: 1px solid var(--border);
  flex: none;
}
.panel__title { font-size: .95rem; font-weight: 700; margin-inline-end: auto; }

.panel__body { flex: 1; overflow-y: auto; padding: 16px 14px; }
.panel__foot {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px 14px;
  border-block-start: 1px solid var(--border);
  background: var(--surface-2);
  flex: none;
}
.panel__foot .btn { flex: 1; }

/* «إضافة أب» يأخذ سطره: نادر الظهور (على الجدّ الأعلى وحده) وحشره
   مع الثلاثة يضيّقها جميعاً. flex-basis لا width حتى يبقى الـ gap سليماً. */
#addFatherBtn, #addWifeBtn { flex-basis: 100%; }

/* رأس البطاقة داخل اللوحة / person hero */
.hero { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.hero__photo {
  width: 128px; height: 128px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-sunk);
  box-shadow: 0 0 0 4px var(--g), 0 0 0 7px color-mix(in oklab, var(--g) 20%, transparent);
}
.hero__photo--blank {
  background: color-mix(in oklab, var(--g) 16%, var(--surface-sunk));
}
/* اسم القبيلة قد يكون سطرين — العناوين التي تعرضه تحترم كسرته.
   والباقي (عنوان اللسان، وصف الصفحة، aria-label) يطوي السطر من نفسه.
   The tribe name may run to two lines, so the headings that show it
   honour the break; titles and labels collapse it by themselves. */
.topbar__title,
.page__title,
.auth__title { white-space: pre-line; }

.hero__name {
  font-family: var(--font-head);
  font-size: 1.4rem;
  font-weight: 700;
  white-space: pre-line;   /* الكسرة المكتوبة تُحترم هنا أيضاً */
}
.hero__badges { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.hero__badge { border-color: color-mix(in oklab, var(--g) 40%, var(--border)); color: var(--g); background: color-mix(in oklab, var(--g) 10%, var(--surface)); }

.detail-block { margin-block-start: 20px; }
.detail-block__label {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--text-faint);
  margin-block-end: 6px;
}
.detail-block__value { font-size: .9rem; line-height: 1.75; white-space: pre-wrap; }
/* بلون اللصيقة نفسها، فيُعرف أن الاسمين شيءٌ واحد.
   The tag's own colour, so the two read as one thing. */
.detail-block__value--keeper { color: var(--keeper); font-weight: 700; }

/* «المكلَّف بفرع فلان» — سببٌ للاسم فوقه، لا خبرٌ مستقلّ */
.detail-block__value--soft {
  margin-block-start: 2px;
  font-size: .8rem;
  color: var(--text-muted);
}

/* سلسلة النسب / lineage chain */
.lineage { display: flex; flex-wrap: wrap; gap: 4px 5px; font-size: .88rem; line-height: 1.9; }
.lineage__link {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--gc, var(--text));
  cursor: pointer;
  border-block-end: 1px dotted currentColor;
}
.lineage__link:hover { opacity: .75; }
.lineage__sep { color: var(--text-faint); }

/* قائمة الأبناء / sons list */
.sons { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; }
.sons__item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 6px 8px;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  text-align: start;
  cursor: pointer;
  font-size: .86rem;
}
.sons__item:hover { background: var(--surface-sunk); }

/* البنات عددٌ لا اسم: لا يُضغط ولا يتلوّن كأنّه رابطٌ معطوب.
   The daughters row is a count, not a name — it must not look like a
   link that refuses to open. */
.sons__item--count {
  cursor: default;
  color: var(--text-muted);
}
.sons__item--count:hover { background: none; }
.sons__item--count .sons__avatar { box-shadow: 0 0 0 2px var(--border); }
.sons__avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-sunk);
  box-shadow: 0 0 0 2px var(--g);
  flex: none;
}
.sons__name { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sons__count { font-size: .72rem; color: var(--text-faint); }

/* ---------- 7. Loading veil ---------- */
.veil {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  background: color-mix(in oklab, var(--bg) 78%, transparent);
  backdrop-filter: blur(2px);
  z-index: 100;
  color: var(--text-muted);
  font-size: .88rem;
}
.veil[hidden] { display: none; }

/* ---------- 8. Phones ---------- */
@media (max-width: 720px) {
  .topbar { padding: 8px 12px; gap: 8px; }
  .topbar__title { font-size: .95rem; }
  .topbar__subtitle { display: none; }

  .search__input { width: 130px; }
  .search__input:focus { width: 168px; }

  /* قائمة النتائج مربوطة بحقل بحث ضيّق ومتوسّط، فعرضها الثابت (٣٠٠ بكسل)
     كان يخرج من حافة الشاشة وتُقصّ الأسماء. على الجوال نثبّتها بالنافذة
     نفسها تحت الشريط، بهامش على الجانبين.
     Anchored to a narrow centred input, the fixed 300px menu ran off the
     screen edge and clipped names. On phones pin it to the viewport
     instead, just under the top bar. */
  .search__results {
    position: fixed;
    inset-block-start: 52px;   /* الشريط ٥٥ بكسل والحقل ينتهي عند ٤٦ */
    inset-inline: 10px;
    width: auto;
    max-height: 62dvh;
  }

  /* اللوحة تصبح ورقة سفلية على الجوال / panel becomes a bottom sheet */
  .panel {
    inset-block: auto 0;
    inset-inline: 0;
    width: 100%;
    max-height: 82dvh;
    border-inline-start: none;
    border-block-start: 1px solid var(--border);
    border-start-start-radius: var(--r-xl);
    border-start-end-radius: var(--r-xl);
    transform: translateY(100%);
  }
  :dir(ltr) .panel { transform: translateY(100%); }
  .panel[data-open="true"] { transform: none; }

  .panel::before {
    content: "";
    position: absolute;
    inset-block-start: 7px;
    inset-inline-start: 50%;
    transform: translateX(50%);
    width: 38px; height: 4px;
    border-radius: 999px;
    background: var(--border-strong);
  }
  .panel__head { padding-block-start: 18px; }

  .legend { max-width: 150px; inset-block-start: 8px; inset-inline-start: 8px; font-size: .7rem; }
  .toolbar { inset-block-end: 12px; }
}

/* ---------- 9. التلميحة — النبذة عند المرور ---------- */
/*
   خارج `.viewport` فلا تتمدّد مع التكبير، ومكانها يُضبط من الشيفرة
   بـ`transform` لا بـ`inset` — فالمتصفّح ينقلها على بطاقة الرسم وحدها.
   Outside `.viewport` so the zoom never scales it; positioned from JS with
   `transform` rather than `inset`, which keeps the move on the compositor.
*/
.tip {
  position: absolute;
  /* الزاوية العليا اليسرى كـ`.viewport` تماماً: الإحداثيات تُحسب من
     `getBoundingClientRect` وهي فيزيائية، و`inset-inline-start` في صفحة
     من اليمين لليسار تعني اليمين — فتُقذف التلميحة خارج الشاشة.
     Pinned to the physical top-left like `.viewport`: the coordinates come
     from `getBoundingClientRect` and are physical, whereas
     `inset-inline-start` means *right* on an RTL page. */
  top: 0;
  left: 0;
  z-index: 6;
  max-inline-size: min(300px, 78vw);
  padding: 10px 13px 11px;
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--g, var(--accent));   /* حافّة البدء — يمين الصفحة العربية */
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  text-align: start;
  /* لا تعترض المؤشّر: لو اعترضته لخرج عن البطاقة فاختفت هي نفسها.
     Never in the pointer's way — it would count as leaving the card. */
  pointer-events: none;
  opacity: 0;
  transition: opacity .14s ease-out;
}
.tip--in { opacity: 1; }

.tip__who {
  font-family: var(--font-head);
  font-size: .82rem;
  font-weight: 700;
  color: var(--g, var(--accent-strong));
  margin-block-end: 5px;
}

/*
   النبذة قد تطول، فتُحبس في عشرة أسطر وتُقصّ بالنقاط — والكامل في
   بطاقة الشخص. و`pre-line` يحفظ ما كتبه صاحبها من كسرات الأسطر.
   A long note is clamped to ten lines here; the whole of it lives in the
   person's card. `pre-line` keeps the line breaks its author typed.
*/
.tip__note {
  margin: 0;
  font-size: .88rem;
  line-height: 1.7;
  color: var(--text);
  white-space: pre-line;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 10;
  line-clamp: 10;
}
