/* HelloDoctor Network. Hand-written, mobile-first. No framework, no build step.
   Target: usable on a 2 GB Android over 3G. */
:root{
  --bg:#f6f7f8; --card:#fff; --ink:#14231f; --muted:#5f6f6b; --line:#e3e8e6;
  /* ⭐⭐ social21 ITEM 1 — THE BRAND PAIR, measured from the owner's own logo:
     blue #3F88CD, teal #42AAB7. ⛔ ONLY THE VARIABLES MOVE — every button, chip
     and link already reads them, so the cascade does the restyle and no component
     is touched. A per-component sweep would be a hundred edits and a hundred
     chances to miss one. */
  --brand:#3F88CD; --brand-dk:#2F6DA8; --brand-2:#42AAB7; --bad:#b3261e; --warn:#8a6100; --ok:#42AAB7;
  --r:12px; --pad:16px;
  /* ⭐ social25 ITEM 4d — THE GAP BETWEEN DEPARTMENT PANELS ON /instant.
     ⛔ ONE TOKEN, ⛔ not a margin on each section: three per-section margins is
     how the fourth department ships with a different gap. Read once, below. */
  --dept-gap:28px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font:16px/1.6 system-ui,-apple-system,"Segoe UI",Roboto,"Noto Sans Bengali",sans-serif;
  font-display:swap;
}
img{max-width:100%;height:auto}
a{color:var(--brand-dk)}
h1,h2{line-height:1.3;margin:0 0 .5em}
h1{font-size:1.5rem}h2{font-size:1.15rem}
p{margin:0 0 .8em}

/* header / footer */
.hdr{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:10px var(--pad);background:var(--card);border-bottom:1px solid var(--line);
  position:sticky;top:0;z-index:500}
/* ⭐ social21 LO2 — THE LOGO BOX RESERVES ITS SIZE. The <img> already carries
   width/height, and this pins the rendered height so the header cannot resize when
   the PNG decodes. ⛔ No layout shift, by construction rather than by luck. */
.brand{display:inline-flex;align-items:center;text-decoration:none;height:32px}
.brand img{height:32px;width:auto;display:block}
/* ⚠⚠ social47 ITEM 2 — **`flex-wrap:wrap` IS A 360px FIX, ⛔ not a tidy-up.** The
   doctor's bar gained «বুকিং» and now carries four items beside the wordmark
   (বুকিং · প্রোফাইল · 📱 অ্যাপ · লগআউট). On a 360px screen that row is wider than
   the space left after the 112px wordmark, and without this it would either
   overflow the viewport or squeeze the logo. ⭐ Caught by BD9, which asserts the
   RULE rather than a rendered pixel — this harness has no browser.
   ⛔ The gap shrinks with it: 14px between four items is 42px of pure air on the
   narrowest phone, and it is the first thing to give. */
.nav{display:flex;align-items:center;flex-wrap:wrap;gap:6px 12px;font-size:.92rem}
.nav a{text-decoration:none;color:var(--muted)}
.nav a.on{color:var(--brand-dk);font-weight:600}
.ftr{padding:24px var(--pad) 40px;color:var(--muted);font-size:.85rem;text-align:center}

/* layout */
.wrap{max-width:680px;margin:0 auto;padding:var(--pad)}
.wrap.narrow{max-width:520px}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:var(--pad);margin:0 0 16px}
.sec-h{margin:20px 0 10px;font-size:1.05rem;color:var(--muted)}
.center{text-align:center}
.tiny{font-size:.82rem;color:var(--muted);margin:0}
.tiny.ok{color:var(--ok)}
.opt{color:var(--muted);font-weight:400;font-size:.85em}
/* ⭐⭐ social42 ITEM 1 — THE MASKED-CONTACT TOKEN. The owner asked for «sundor kore
   hide» — so it is QUIET: the same muted colour the rest of the sheet uses for
   secondary text, one size down, and ⛔ NO box, badge, strike-through or warning
   colour. A loud token would read as an error in the middle of an address and make
   an ordinary doctor think his profile is broken.
   ⚠ `white-space:nowrap` only so the word never breaks across two lines mid-address.
   ⛔ THERE IS NOTHING TO REVEAL HERE. This styles a word the server sent INSTEAD of
   the digits; the digits are not in the page, so ⛔ no CSS rule and ⛔ no devtools
   inspection can bring them back. It is not a blur and it is not a spoiler. */
.masked{color:var(--muted);font-size:.92em;white-space:nowrap}
.req{color:var(--bad)}
.page-h1{margin-top:8px}
.lede{color:var(--muted)}

/* landing */
.hero{padding:24px 0 8px}
.hero h1{font-size:1.7rem}
.choices{display:grid;gap:12px;margin:12px 0 20px}
.choice{display:block;padding:20px;border-radius:var(--r);text-decoration:none;
  border:2px solid var(--line);background:var(--card);color:var(--ink)}
.choice-title{display:block;font-size:1.25rem;font-weight:700;margin-bottom:4px}
.choice-sub{display:block;color:var(--muted);font-size:.9rem}
.choice-dr{border-color:var(--brand);background:#f0faf8}
.choice-pt{border-color:#cfd8d5}

/* forms */
.form .field{margin-bottom:14px}
label{display:block;font-weight:600;font-size:.92rem;margin-bottom:5px}
input,select,textarea{
  width:100%;padding:11px 12px;font:inherit;color:inherit;background:#fff;
  border:1px solid #c8d2cf;border-radius:9px}
/* ⭐⭐⭐ social15 ITEM 2 — THE DAY BOX SAT ABOVE ITS LABEL, AND THE CAUSE IS THE
   RULE DIRECTLY ABOVE THIS ONE.
   `input,select,textarea{width:100%;padding:11px 12px}` is written for text
   boxes and applies to EVERY input — including a checkbox. So each day's box
   stretched to the full width of its `.daybox` flex line and took the whole row,
   pushing «শনি» onto the next line: exactly what the owner's screenshot shows.
   ⛔ NOT a broken flex container and ⛔ NOT a label wrapping as a block —
   `.daybox` is already `display:inline-flex;align-items:center`, and it was
   correct all along. The checkbox was simply 100% wide inside it.
   ⭐ THE RESET IS GLOBAL because there are exactly THREE checkboxes in this app
   and all three are day pickers (schedulefields, /me, the admin editor) — so one
   rule fixes every one and there is no other checkbox for it to affect.
   ⚠ `padding` and `border-radius` are reset too: an 11px-padded checkbox is a
   different shape from the one the browser draws, which is the other half of what
   made that row look wrong. */
input[type="checkbox"],input[type="radio"]{
  width:auto;flex:0 0 auto;padding:0;border-radius:0;margin:0}
input:focus,select:focus,textarea:focus{outline:2px solid var(--brand);border-color:var(--brand)}
input.locked{background:#eef2f1;color:var(--muted)}
textarea{resize:vertical}
.inline{display:inline}
.inline-form{display:flex;gap:8px}
.inline-form input{flex:1}

/* buttons */
.btn{display:inline-block;padding:11px 16px;border-radius:9px;border:1px solid var(--line);
  background:#fff;color:var(--ink);font:inherit;font-weight:600;text-decoration:none;
  cursor:pointer;text-align:center}
.btn-primary{background:var(--brand);border-color:var(--brand);color:#fff}
.btn-primary:hover{background:var(--brand-dk)}
.btn-ghost{background:#fff;color:var(--brand-dk);border-color:#bcd6d1}
.btn-block{display:block;width:100%}
.btn-sm{padding:7px 11px;font-size:.86rem}
.linkish{background:none;border:0;color:var(--muted);font:inherit;cursor:pointer;padding:0;
  text-decoration:underline}

/* alerts */
.alert{padding:12px 14px;border-radius:9px;margin:0 0 14px;font-size:.93rem}
.alert-bad{background:#fdeceb;color:var(--bad);border:1px solid #f4c7c3}
.alert-warn{background:#fdf5e2;color:var(--warn);border:1px solid #f0dfae}
.alert-info{background:#eaf5f3;color:var(--brand-dk);border:1px solid #bfdfd9}
.alert-ok{background:#e9f6f0;color:var(--ok);border:1px solid #b9e2d2}

/* strip */
.strip{display:flex;align-items:center;justify-content:space-between;gap:12px;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:12px var(--pad);margin-bottom:16px}

/* posts */
.post{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:14px var(--pad);margin:0 0 12px}
.post-hd{display:flex;gap:10px;align-items:flex-start;margin-bottom:8px}
.avatar{width:44px;height:44px;border-radius:50%;object-fit:cover;flex:0 0 44px;
  background:#dfe8e6;display:inline-flex;align-items:center;justify-content:center;
  font-weight:700;color:var(--brand-dk)}
.avatar-lg{width:88px;height:88px;flex-basis:88px;font-size:2rem}
.post-who{min-width:0}
.who-name{font-weight:700;text-decoration:none;color:var(--ink)}
.who-sub{margin-top:2px}
.post-body{white-space:pre-wrap;word-wrap:break-word;overflow-wrap:anywhere}
/* ⚠⚠ social40 ITEM 5 — `flex-wrap:wrap` IS NEW AND IT IS A REAL GAP THIS PASS
   OPENED. The row gained the eye AND a revealable «<N> জন দেখেছেন» line, and a
   nowrap flex row with six children on a 360px screen pushes the last of them
   off the edge. ⛔ Not a cosmetic addition: VU3 measures it. */
.post-ft{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:10px;
  border-top:1px solid var(--line);padding-top:8px}
.likebtn,.followbtn{background:none;border:1px solid var(--line);border-radius:20px;
  padding:5px 12px;font:inherit;font-size:.86rem;color:var(--muted);cursor:pointer}
.likebtn.on{color:var(--bad);border-color:#f0c4c0;background:#fdeceb}
.followbtn.on{color:var(--brand-dk);border-color:#bfdfd9;background:#eaf5f3}

/* badges */
.badge{display:inline-block;font-size:.75rem;padding:2px 8px;border-radius:20px;font-weight:600}
.badge-ok{background:#e2f3ec;color:#0a5e42}
/* ⭐⭐ social16 ITEM 7 — THE QUIET TICK. The word «যাচাইকৃত» is retired from the
   surface; what stays is a small teal seal beside the name. ⛔ The aria-label
   keeps the WORD, so nothing was removed for a screen reader — only for the eye.
   ⭐ A circle, not a pill: it sits beside a name rather than competing with it. */
.seal{display:inline-flex;align-items:center;justify-content:center;
  width:1.05em;height:1.05em;border-radius:50%;background:#0a8f6a;color:#fff;
  font-size:.78em;line-height:1;vertical-align:.08em;margin-inline-start:.28em;
  flex:0 0 auto}
.seal svg{width:.62em;height:.62em;fill:none;stroke:currentColor;stroke-width:3.4;
  stroke-linecap:round;stroke-linejoin:round}
/* ⭐⭐ social16 ITEM 1 — THE অভিজ্ঞতা স্কোর ROW.
   ⛔ No image file and no icon font: the star is an inline SVG path, so it costs
   no request, cannot 404, and takes its colour from here.
   ⭐ Five slots are ALWAYS drawn — the unearned ones as faint outlines — so a
   two-star doctor and a five-star doctor read as different SCORES rather than
   as different widgets. */
.starrow{display:flex;align-items:center;gap:.35em;margin:.15rem 0 0;
  font-size:.82rem;color:var(--muted)}
.starrow-label{white-space:nowrap}
.stars{display:inline-flex;gap:.08em;align-items:center}
.star{display:block}
.star-on{fill:#e8a316}
/* ⛔ The empty slot is an OUTLINE, not a lighter gold: a pale gold star reads as
   a half-earned one. */
.star-off{fill:none;stroke:#c9cdd4;stroke-width:1.6}

.badge-pend{background:#f1f3f2;color:var(--muted)}
.chip{background:#eef2f1;border-radius:10px;padding:1px 7px;font-size:.75rem}
.chip-bad{background:#fdeceb;color:var(--bad)}

/* profile */
.profile-hd{display:flex;gap:14px;align-items:center;margin-bottom:12px}
.dr-name{margin:0 0 4px;font-size:1.35rem}
.degrees{color:var(--muted);font-size:.92rem}
.meta{display:flex;flex-wrap:wrap;gap:18px;margin:12px 0;padding:12px 0;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.meta div{margin:0}
.meta dt{font-size:.78rem;color:var(--muted)}
.meta dd{margin:0;font-weight:600}

/* map */
.map{height:220px;border-radius:9px;border:1px solid var(--line);background:#e9eeec}
.maprow{display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap}

/* admin */
.row{display:flex;gap:12px;justify-content:space-between;align-items:flex-start;
  padding:12px 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.row:last-child{border-bottom:0}
.row-acts{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.counts{display:flex;gap:18px;flex-wrap:wrap}
.counts div{display:flex;flex-direction:column}
.big{font-size:1.4rem;font-weight:700}
.linkbox{font-size:.75rem;padding:6px 8px;margin-top:4px}
.clip{max-height:3.2em;overflow:hidden;margin:4px 0 0;font-size:.9rem}
.empty{color:var(--muted);text-align:center}

/* install bar */
.installbar{position:sticky;bottom:10px;display:flex;gap:12px;align-items:center;
  justify-content:space-between;background:var(--card);border:1px solid var(--brand);
  border-radius:var(--r);padding:12px var(--pad);margin-top:16px;font-size:.92rem}
.installbar[hidden]{display:none}

@media (min-width:560px){ .choices{grid-template-columns:1fr 1fr} }

/* ── social03 ITEM 6 — the clickable photo, and the verification row ──
   ⛔ Deliberately tiny: the anchor does the work, not the CSS. */
.photo-link{cursor:pointer;display:inline-block;line-height:0}
.verify-subject{display:flex;gap:12px;align-items:flex-start;min-width:0}
.verify-photo{width:160px;height:160px;border-radius:8px;object-fit:cover;flex:0 0 auto;background:#dfe8e6}
.verify-photo-blank{display:inline-flex;align-items:center;justify-content:center;
  font-size:3rem;font-weight:700;color:var(--muted)}
.verify-facts{min-width:0}
.bmdc-copy{display:flex;gap:6px;align-items:center;margin-top:6px;flex-wrap:wrap}
.bmdc-copy .linkbox{max-width:180px}

/* ── social05 — install, comments, message preview ──
   ⛔ Deliberately small; the markup does the work. */
.btn-install{font-size:1.15rem;padding:16px}
.steps{margin:8px 0 0 20px;line-height:1.9}
#manualSteps.collapsed ol{display:none}
#manualSteps.collapsed{opacity:.75}
.installbar{display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  position:sticky;bottom:0;background:var(--card);border-top:1px solid var(--brand);padding:10px 12px}
.comments{border-top:1px solid #e6ecea;margin-top:10px;padding-top:10px}
.comment-list{list-style:none;margin:0 0 10px;padding:0;display:grid;gap:10px}
.comment{background:#f6f9f8;border-radius:8px;padding:8px 10px}
.comment-hidden{opacity:.55}
.comment-body{white-space:pre-wrap;word-break:break-word;margin-top:2px}
.comment-acts{display:flex;gap:10px;margin-top:4px}
.comment-form textarea{width:100%;box-sizing:border-box}
.warn{color:#8a5a00;background:#fff6e5;border-radius:6px;padding:6px 8px;margin:6px 0}
/* ⭐ social08 ITEM 5 — the message preview ran off the right edge of its card.
   `overflow-wrap:anywhere` is what breaks a long URL (the messages carry
   https://hellodoctor.net/... on its own line); `word-break:break-word` alone
   does not, which is why it overflowed.
   ⛔ WRAPPING ONLY: the text is not trimmed, no line breaks are inserted, and
   render() is untouched — social05's M4 asserts the preview stays BYTE-IDENTICAL
   to what is sent, and it still does.
   ⛔ overflow-x:hidden, so nothing can produce a horizontal scrollbar. */
.preview{white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere;
  max-width:100%;overflow-x:hidden;background:#f6f9f8;
  border:1px solid #e6ecea;border-radius:8px;padding:10px;font-size:.95rem}
.center{text-align:center}

/* ── social06 — the photo preview and the admin photo flags ── */
.photo-preview{display:flex;align-items:center;gap:10px;margin-top:8px}
/* ⛔ social07 — an AUTHOR display rule beats the UA's [hidden]{display:none}, so
   `hidden` alone did NOT hide this wrapper and a src-less <img> inside it drew a
   broken-image icon on the signup page. The <img> is gone from the HTML; this
   rule is the second net, so no future class can un-hide the wrapper either. */
.photo-preview[hidden]{display:none}
.photo-preview img{width:72px;height:72px;object-fit:cover;border-radius:8px;border:1px solid #e6ecea}
.photo-flag{display:inline-block;background:#fff6e5;color:#8a5a00;border-radius:6px;
  padding:2px 8px;font-size:.85rem;white-space:nowrap}
.photo-counts{font-size:.9rem;color:#5a6a67}
.verify-photo-failed{background:#fff6e5;color:#8a5a00}

/* ── social08 — the comment icon · social12 ITEM 8 — moved INTO the action row ──
   ⛔ `.post-acts` is DELETED, not emptied: it was a second flex block after
   `.post-ft`, and two flex blocks stack however they are styled. That structure
   was the whole "comment icon sits under the like icon" defect.
   ⭐ `.actbtn` is the SHARED shape — one rule for all three controls, so they
   cannot drift into three sizes. ⛔ `text-decoration:none` stays declared on the
   anchor: it was never the cause, and removing it now would create the bug the
   owner reported for real. */
.actbtn,.likebtn,.followbtn{font:inherit;font-size:.86rem;padding:5px 12px;
  border-radius:20px;border:1px solid var(--line);color:var(--muted);
  background:none;cursor:pointer}
.commentbtn{display:inline-flex;gap:6px;align-items:center;text-decoration:none}
.commentbtn:hover,.commentbtn.on{background:#eef5f3;color:#3a6b63}
/* ⚠⚠ social40 ITEM 5 — `margin-left:auto` IS GONE, AND THE OLD RULE IS THE RECORD:
     "⭐ FAR RIGHT, by pushing the free space in front of it. ⛔ Not `float`, which
      would leave the flex row and stop wrapping sanely on a 360px screen."
     .viewcount{margin-left:auto; …}
   ⭐ The owner has moved the eye to the FAR LEFT — before Like — so the property
   that put it last is removed rather than merely overridden further down. ⛔ A
   stylesheet that says «push me right» while another rule pulls it left is a
   stylesheet whose next reader has to run the cascade in his head.
   ⚠ `white-space:nowrap` STAYS: «👁 ৪২» must not break between the eye and its
   number, and the revealed sentence beside it wraps on its own rule. */
.viewcount{display:inline-flex;gap:5px;align-items:center;
  font-size:.86rem;color:var(--muted);white-space:nowrap}
/* ⭐ 360px is the narrowest real phone here. The row WRAPS rather than
   overflowing, and the eye keeps its right edge on whichever line it lands on. */
@media (max-width:380px){
  .actbtn,.likebtn,.followbtn{padding:5px 9px;font-size:.82rem}
  .post-ft{gap:6px}
}

/* ── social10 — the chamber block, the day picker and the time range ──
   ⛔ Plain CSS, no framework, no new asset. Every control below is a real form
   control that works with JavaScript switched off. */
.chamber{list-style:none;margin:.6rem 0 0;padding:0;display:flex;flex-direction:column;gap:.35rem}
.chamber li{font-size:.95rem;line-height:1.5;overflow-wrap:anywhere}
.chamber strong{font-weight:600}
.label-as-legend{display:block;font-weight:600;margin-bottom:.35rem}
.daypick{display:flex;flex-wrap:wrap;gap:.4rem}
.daybox{display:inline-flex;align-items:center;gap:.3rem;border:1px solid #d7e2de;border-radius:999px;
        padding:.35rem .7rem;background:#fff;cursor:pointer;font-size:.9rem}
.daybox input{margin:0}
.timerow{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.timerow select{flex:1 1 8rem;min-width:8rem}
/* ⭐ The avatar link carries no visual change — the photo already looks tappable.
   ⛔ No underline, no colour: this is the same image, now a door. */
.who-photo{display:inline-flex;text-decoration:none;border:0}

/* ── social11 — the public home strip, the district picker, the two sittings ── */
.joinstrip{display:flex;flex-wrap:wrap;gap:.6rem;align-items:center;justify-content:space-between;
  background:#eef5f3;border:1px solid #d7e2de;border-radius:12px;padding:.7rem .9rem;margin:.6rem 0}
.joinstrip-lede{font-weight:600}
.joinstrip-acts{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap}
.districtpick{display:flex;gap:.5rem;align-items:center}
.districtpick select{flex:1 1 auto;min-width:0}
/* ⭐ social12 ITEM 10 — the জেলা LABEL and the OPTIONS at ONE size. The label was
   `.tiny` while the <select> rendered at the control's own size, so «জেলা» sat
   visibly smaller than «ঢাকা» next to it. ⛔ Equalised UPWARD: shrinking the
   dropdown a person has to read would be the wrong half to change. */
.districtpick .pick-label{font-size:1rem;color:var(--muted,#667)}
.districtpick select{font-size:1rem}

/* ⭐ social12 ITEM 3 — the dashboard counts are links now; they must not look
   like body links. ⛔ Colour and underline off, the number keeps its own size. */
.countlink{display:block;text-decoration:none;color:inherit}
.countlink:hover .big{text-decoration:underline}
.wa-fallback{margin-top:12px}
.profileviews{margin-top:6px}

/* ══════════ social13 ITEM 1 — THE এলাকা SUGGESTION PANEL ══════════
   ⭐⭐ THE MOBILE OVERFLOW THE OWNER SAW WAS THE NATIVE <datalist> POPUP, which
   is BROWSER CHROME — page CSS cannot reach it at all, and Android Chrome sizes
   it to the WIDEST OPTION while desktop Chrome sizes it to the input. That is
   why the same page looked correct on one and ran off the side on the other, and
   why there is no CSS fix for it: app.js removes the `list` attribute and drives
   the panel below instead, which the page owns.

   ⛔ WHY THIS CANNOT OVERFLOW, by construction rather than by a chosen width:
     · `.areawrap` is position:relative and is a child of `.field`, which sits
       inside `.wrap{max-width:680px}` — so its width is already the form's.
     · the panel is `left:0;right:0`, so it is EXACTLY that width. ⛔ Never a
       fixed px width, ⛔ never `width:max-content`, which is the datalist's own
       behaviour and the whole defect.
     · `box-sizing:border-box` (the global rule) keeps padding and border inside
       that width.
     · `overflow-wrap:anywhere` breaks a long locality name instead of widening
       the row; `overflow-x:hidden` means nothing inside can produce a sideways
       scrollbar either.
   ⭐ `max-height` + `overflow-y:auto` keep it short: a panel taller than the
   screen is the same defect on the other axis. */
.areawrap{position:relative}
.areasugg{
  position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:30;
  margin:0;padding:0;list-style:none;
  max-width:100%;box-sizing:border-box;
  max-height:14rem;overflow-y:auto;overflow-x:hidden;
  background:#fff;border:1px solid #c8d2cf;border-radius:9px;
  box-shadow:0 6px 18px rgba(0,0,0,.12)}
.areasugg li{padding:10px 12px;cursor:pointer;font-size:.95rem;line-height:1.4;
  overflow-wrap:anywhere;border-bottom:1px solid #f0f4f3}
.areasugg li:last-child{border-bottom:none}
.areasugg li:hover{background:#eef4f2}
/* ⛔ social07's lesson, applied before it can bite: an AUTHOR display rule beats
   the user agent's [hidden]{display:none}. This element declares none, so
   `hidden` already works — the rule is the second net, so no future
   `.areasugg{display:block}` can un-hide an empty panel over the form. */
.areasugg[hidden]{display:none}

/* ══════════ social13 ITEM 6d — THE CARD'S THREE LINES ══════════
   ⭐ নাম keeps its size; ডিগ্রি, বিশেষত্ব and the location sit one step smaller
   and are all BOLD (the owner's ruling). ⛔ `.who-sub` keeps `.tiny` nowhere near
   it — a line a patient is meant to read is not a footnote. */
.who-degree,.who-sub{font-size:.88rem;font-weight:600;line-height:1.45}
.who-degree{color:var(--ink,#1b2b27);margin-top:1px}
.who-sub{color:var(--ink,#1b2b27);display:flex;flex-wrap:wrap;gap:.15rem .75rem}
.who-sub .who-loc{color:var(--muted,#667)}

/* ══════════ social13 ITEM 6a/6b/6c — THE NEW FORM ROWS ══════════
   ⛔ Every row below wraps rather than scrolls: `min-width:0` on a flex child is
   what lets it shrink below its content, and without it a select refuses to
   narrow and pushes the row past the viewport on a 360px phone. */
/* ⚠ social15 — `.bmdcrow` is GONE: the BMDC field is one `.bmdcbox` now. */
.namerow,.degreerow{display:flex;gap:.5rem;align-items:center}
.namerow select{flex:0 0 auto;width:auto;min-width:0}
.namerow input,.degreerow input{flex:1 1 auto;min-width:0}
.degreerow select{flex:0 0 auto;width:auto;min-width:0}
/* ⭐⭐⭐ social15 ITEM 4 — THE «A-» LIVES INSIDE THE BOX (his ss3).
   ⛔ social13's shape is kept as the record: the «A» was its OWN bordered box
   beside the input, which reads as a separate field — and on a phone it read as a
   LABEL SITTING ABOVE one. ⇒ ONE bordered wrapper styled exactly as an input, with
   the prefix and the digits sharing its inside.
   ⭐ The «A-» is still TEXT, ⛔ not an input: it cannot be focused, typed into,
   backspaced or submitted, which is the whole point of a fixed prefix.
   ⭐ `:focus-within` moves the focus ring to the WRAPPER, so the composite still
   looks and behaves like one control to a keyboard user. */
.bmdcbox{display:flex;align-items:center;gap:.15rem;
  padding:0 12px;background:#fff;border:1px solid #c8d2cf;border-radius:9px}
.bmdcbox:focus-within{outline:2px solid var(--brand);border-color:var(--brand)}
.bmdcfix{flex:0 0 auto;color:var(--muted,#667);font-weight:600;user-select:none}
/* ⛔ The inner input carries NO border, NO radius and NO background of its own —
   the wrapper is the box now, and a second border inside it is the old two-field
   look in a smaller costume. ⛔ Its focus outline is suppressed because the
   wrapper draws one. */
.bmdcbox input{flex:1 1 auto;min-width:0;width:100%;
  border:0;border-radius:0;background:transparent;padding:11px 0}
.bmdcbox input:focus{outline:0}

/* ⚠ THE HEADING THIS BLOCK CARRIED UNTIL social41 read «Days DOWN the left, times
   to their RIGHT (the owner's layout). On a narrow phone the two columns wrap onto
   separate rows rather than overflowing.» ⛔ It is kept as the record and ⛔ no
   longer describes the product: the owner replaced that layout in ITEM 2. */
/* ⚠⚠ social41 ITEM 2 — THE FIVE RULES BELOW ARE RETIRED, and they are the record
   of the layout the owner has replaced. They were:
     .schedrow{display:flex;gap:.75rem;align-items:flex-start;flex-wrap:wrap}
     .daypick-col{flex-direction:column;flex-wrap:nowrap;flex:0 0 auto}
     .schedtimes{flex:1 1 12rem;min-width:0}
     .schedtimes .timerow{flex-wrap:wrap}
     .schedtimes select{flex:1 1 7rem;min-width:0}
   ⭐ `.daypick-col` turned chamber 1's day list into a COLUMN while chamber 2 used
   the plain wrapping `.daypick` row — two styles for one control. Chamber 1 now
   uses `.daypick`, so these five have no selector left to match and are DELETED
   rather than left as dead weight the next reader has to test against.
   ⛔ `.daypick` itself (line ~305) is untouched and is now the only day-row rule.
   ⚠ `.timerow` and `.timerow select` (line ~313) already wrap; the two `.schedtimes`
   overrides existed only to make the narrow right-hand column behave, and that
   column is gone. */

/* ⭐ social16 ITEM 6 — an extra chamber's field-set. ⛔ `[hidden]` is honoured
   explicitly: this stylesheet sets `display` on other selectors, and a later
   rule winning over the attribute is how a "hidden" set renders anyway. */
.chamberset[hidden]{display:none}
.chamberset{border:1px solid var(--line);border-radius:10px;padding:.6rem .7rem;
  margin-top:.5rem}
.chamberset > input{margin-bottom:.4rem}

/* ⭐ social17 ITEM 2 — the booking door on a feed card, in the SAME .actbtn family
   as like/comment/follow so a future change to one is a change to all. */
.serialbtn{margin-inline-start:auto}
/* ⛔ A cancelled row is GREYED, ⛔ never hidden: a serial that vanished is a
   serial the patient cannot tell he cancelled. */
.muted{opacity:.55}

/* ⭐ social17 ITEM 2c — the staff serial board. ⛔ Scrolls inside its own
   container; the page body never scrolls sideways on a phone. */
.board{width:100%;border-collapse:collapse;font-size:.9rem}
.board th,.board td{padding:.4rem .5rem;border-bottom:1px solid var(--line);
  text-align:start;vertical-align:top;white-space:nowrap}
.board th{font-weight:600;color:var(--muted);font-size:.82rem}

/* ⭐⭐ social18 ITEM 2 — «নতুন যাচাইকৃত ডাক্তার». ⛔ Scrolls inside its own rail;
   the page body never scrolls sideways on a phone. */
.newdoc{margin:.6rem 0}
.newdoc-rail{display:flex;gap:.6rem;overflow-x:auto;padding-bottom:.3rem;
  -webkit-overflow-scrolling:touch}
.newdoc-card{flex:0 0 auto;width:5.6rem;display:flex;flex-direction:column;
  align-items:center;gap:.2rem;text-align:center;text-decoration:none;
  color:inherit}
.newdoc-card .avatar{width:3.2rem;height:3.2rem;border-radius:50%;object-fit:cover}
.newdoc-name{font-size:.82rem;font-weight:600;line-height:1.25}
/* ⛔ A DIFFERENT colour from the verification seal — «নতুন» is a date, the seal is
   a credential, and a reader must not take one for the other. */
.badge-new{background:#fff3d6;color:#8a5a00}

/* ⭐⭐ social19 ITEM 2 — THE BOTTOM NAV.
   ⛔ `position:fixed` with a safe-area inset, and the BODY carries matching
   padding — a fixed bar with no padding beneath the content covers the last thing
   on the page, which on the dashboard is the composer's own submit button. */
.botnav{position:fixed;left:0;right:0;bottom:0;z-index:40;display:flex;
  background:var(--card,#fff);border-top:1px solid var(--line);
  padding-bottom:env(safe-area-inset-bottom,0)}
/* ⭐⭐ social21 ITEM 2 — THE THREE READ AS BUTTONS.
   A bordered pill and one size up (.78rem → .95rem, ~1.22×). ⛔ The pill is on the
   ITEM, ⛔ not on the bar, so the tap target is the whole cell and the border only
   draws where a finger lands.
   ⚠ `min-height:44px` is the tap-target floor, ⛔ not decoration: below it a thumb
   misses on a phone, and this is the one control on every page. */
.botnav a, .botnav button.navlock{
  flex:1 1 0;min-width:0;display:flex;align-items:center;
  justify-content:center;gap:.25rem;margin:.3rem .2rem;padding:.45rem .35rem;
  min-height:44px;text-decoration:none;background:transparent;
  color:var(--muted);font-size:.95rem;font-weight:700;line-height:1.2;
  text-align:center;border:1.5px solid var(--line);border-radius:999px;
  font-family:inherit;cursor:pointer}
/* ⛔ A LOCKED TAB IS VISIBLY LOCKED. Same size and place, ⛔ never a link that 403s. */
.botnav button.navlock{opacity:.55}
.botnav a.on{color:#fff;background:var(--brand);border-color:var(--brand)}
/* ⛔ ONE ROW AT 360px: the labels are long Bangla phrases, so they ellipsis
   rather than wrap — a wrapped bar doubles in height and eats the viewport. */
.botnav-t{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  max-width:100%}
/* ⭐ The middle tab is the short word, so the two outer ones get the room. */
/* ⭐ The middle tab is the short word হোম, so the two outer ones get the room.
   ⚠ `:nth-child(2)` still holds: whichever third door renders, হোম is second. */
.botnav a:nth-child(2){flex:0 0 4.6rem}
/* ⚠ social21: the ACTIVE pill is now a filled brand chip — see the rule above.
   ⛔ The old top-border rule is gone rather than left to fight the new one. */
/* ⭐ THE CLEARANCE. Without it the bar sits on top of the last element. */
body{padding-bottom:4.2rem}

/* ⭐ social19 ITEM 3 — a marketplace row. ⛔ Grid, so the action column keeps its
   width and a long Bangla name cannot push the button off a 360px screen. */
.mkt{display:grid;grid-template-columns:auto 1fr auto;gap:.6rem;align-items:center;
  padding:.6rem 0;border-bottom:1px solid var(--line)}
.mkt-photo .avatar{width:3.5rem;height:3.5rem;border-radius:50%;object-fit:cover}
.mkt-body{min-width:0}
.mkt-act{flex:0 0 auto;text-align:end}
.filterbar{display:flex;gap:.4rem;margin:.5rem 0;flex-wrap:wrap}
.filterbar select{flex:1 1 8rem;min-width:0}

/* ⭐⭐ social21 ITEM 4 — THE POST PHOTO. ⛔ A HEIGHT CAP, so one picture cannot own
   the screen and push every other post below the fold. `object-fit:cover` keeps the
   aspect honest inside that cap rather than squashing a portrait photo. */
.post-img{display:block;width:100%;height:auto;max-height:340px;object-fit:cover;
  border-radius:10px;margin:.5rem 0 0;background:var(--line)}

/* ⭐⭐ social21 ITEM 7 — THE INSTALL BANNER.
   ⛔ IT SITS **ABOVE** THE BOTTOM NAV, never on it: `bottom` clears the bar's own
   height plus the iPhone home bar, so it can never cover the three doors or the
   composer's send button at 360px (PS4). */
.pwabar{position:fixed;left:.5rem;right:.5rem;z-index:45;
  /* ⭐ social22 — RAISED to clear the chat button that now sits between it and
   * the bottom nav: 56px of nav + a gap + 48px of button + a gap. ⛔ Edited HERE
   * rather than overridden further down: two rules for one offset is how they
   * drift, and the one that loses is the one nobody is reading. */
  bottom:calc(56px + env(safe-area-inset-bottom,0px) + .5rem + 48px + .5rem)}
.pwabar-in{display:flex;align-items:center;gap:.6rem;background:var(--card);
  border:1px solid var(--line);border-left:4px solid var(--brand);
  border-radius:12px;padding:.55rem .6rem;box-shadow:0 6px 18px rgba(0,0,0,.12)}
.pwabar-t{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;line-height:1.25}
.pwabar-t strong{font-size:.92rem}
.pwabar-x{flex:0 0 auto;background:transparent;border:0;font-size:1.1rem;
  color:var(--muted);cursor:pointer;min-width:44px;min-height:44px}
@media (max-width:360px){ .pwabar-t span{display:none} }

/* ⭐ social21 — the composer's second row: attach on the left, publish on the right. */
.composer-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.composer-row .btn{margin-left:auto}
.attach{display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;border:1px solid var(--line);border-radius:10px;
  cursor:pointer;font-size:1.1rem;background:var(--card)}
/* ⛔ The real input is hidden but FOCUSABLE-BY-LABEL, ⛔ not display:none, which
   removes it from the form on some browsers. */
.attach-input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.attach-name{max-width:9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.counter{margin:.25rem 0 0;color:var(--muted)}
.counter.over{color:var(--bad);font-weight:700}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ⭐⭐⭐ social22 ITEM 1 — THE FLOATING CHAT BUTTON AND ITS SHEET.
 * ⭐ THE STACK, AND EVERY OFFSET IS DERIVED FROM THE ONE ABOVE IT so none can
 * cover another: botnav z40 at bottom 0 (56px tall) · the chat button z46 one
 * gap above it · the install banner z45 one gap above THAT.
 * ⚠ THE BANNER IS RAISED **UNCONDITIONALLY**, and that is a stated cost: on a
 * DOCTOR's page there is no chat button, so the banner floats one empty row
 * higher than it needs to. ⛔ The alternative was a body class or `:has()` —
 * a JS-set class would make the layout depend on a script that may not have run,
 * and the whole point of this button is that it costs nothing before a tap.
 * ⇒ a cosmetic gap on one audience beats a collision that depends on timing. */
.chatfab{position:fixed;right:.75rem;z-index:46;
  bottom:calc(56px + env(safe-area-inset-bottom,0px) + .5rem);
  display:inline-flex;align-items:center;gap:.4rem;
  min-height:48px;padding:.6rem .9rem;border:0;border-radius:999px;
  background:var(--brand-2);color:#fff;font-size:.95rem;font-weight:600;
  box-shadow:0 6px 18px rgba(0,0,0,.22);cursor:pointer}
.chatfab:active{background:var(--brand)}
.chatfab-i{flex:0 0 auto}
.chatfab-t{white-space:nowrap}

/* ⭐⭐ THE SHEET. ⛔ A BOTTOM SHEET, ⛔ not a new tab and ⛔ not a navigation — the
 * visitor never loses the page he was reading, which is the whole difference
 * between asking a question and leaving. */
.chatsheet{position:fixed;inset:0;z-index:60;display:flex;align-items:flex-end;
  justify-content:center;background:rgba(0,0,0,.38)}
.chatsheet[hidden]{display:none}
.chatsheet-card{display:flex;flex-direction:column;width:100%;max-width:520px;
  /* ⭐⭐ 100dvh, ⛔ NOT 100vh. With the on-screen keyboard up, `vh` still measures
   * the WHOLE screen, so the composer sits underneath the keyboard and the
   * visitor types into a box he cannot see. `dvh` is the visible viewport. */
  max-height:min(88dvh,88vh);background:var(--card,#fff);
  border-radius:14px 14px 0 0;box-shadow:0 -8px 28px rgba(0,0,0,.25);
  padding-bottom:env(safe-area-inset-bottom,0px)}
.chatsheet-h{display:flex;align-items:center;gap:.5rem;padding:.7rem .8rem;
  border-bottom:1px solid var(--line);background:var(--brand);color:#fff;
  border-radius:14px 14px 0 0}
.chatsheet-h strong{flex:1 1 auto;min-width:0;font-size:.95rem;line-height:1.3}
.chatsheet-x{flex:0 0 auto;background:transparent;border:0;color:#fff;
  font-size:1.1rem;min-width:44px;min-height:44px;cursor:pointer}
.chatsheet-body{flex:1 1 auto;overflow-y:auto;padding:.7rem .8rem;
  display:flex;flex-direction:column;gap:.5rem}
.chatline{max-width:88%;padding:.5rem .7rem;border-radius:12px;line-height:1.45;
  white-space:pre-wrap;word-break:break-word}
.chatline p{margin:0}
.chatline.clinic{align-self:flex-start;background:#eef4fb;color:#111827}
.chatline.patient{align-self:flex-end;background:var(--brand);color:#fff}
.chatline-t{display:block;margin-top:.2rem;font-size:.72rem;opacity:.75}
.chatsheet-f{display:flex;align-items:flex-end;gap:.5rem;padding:.6rem .8rem 0}
.chatsheet-f textarea{flex:1 1 auto;min-width:0;resize:none;max-height:7rem}
.chatsheet-go{flex:0 0 auto;min-height:44px}
.chatsheet-note{margin:.4rem .8rem .7rem;color:var(--muted)}
/* ⛔ THE HONEYPOT IS OFF-SCREEN, ⛔ not `display:none`: some scripts read the DOM
 * and skip a field that is displayed none, which is exactly the script this
 * field exists to catch. */
.chat-hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}
@media (max-width:360px){ .chatfab-t{display:none} .chatfab{padding:.7rem} }

/* ═══════════ ⭐⭐ social25 ITEM 4 — THE তাৎক্ষণিক ডাক্তার ROSTER CARD ═══════════
   ONE card for both roles (views/partials/rostercard.ejs). It extends `.mkt`, so
   the grid, the row rule and the min-width:0 body all come from there — ⛔ what is
   added here is only what differs. */

/* ⭐ ITEM 4c — the photo one step larger: 3.5rem → 4.4rem (~1.25×).
   ⛔ SCOPED TO `.roster-card`, so the marketplace rows and the admin roster list —
   which are also `.mkt` — keep the size they had. */
.roster-card .mkt-photo .avatar{width:4.4rem;height:4.4rem;flex-basis:4.4rem}
/* ⭐ The name and the role chip on ONE line, and the chip never pushed off a 320px
   screen: the name may wrap, the chip may not shrink. */
.roster-top{display:flex;flex-wrap:wrap;align-items:center;gap:.35rem .5rem}
.roster-top .who-name{min-width:0;overflow-wrap:anywhere}
.roster-top .badge{flex:0 0 auto}
/* ⛔ `align-items:start` overrides `.mkt`'s centring: a four-line card centred
   against its photo leaves the name floating in the middle of the row. */
.roster-card{align-items:start}
/* ⭐ ITEM 4d — the gap BETWEEN panels, from the one token. ⛔ `+` so the first
   section keeps its own heading spacing and only the joins grow. */
.dept-sec + .dept-sec{margin-top:var(--dept-gap)}
/* ⭐ ITEM 4e — the two fee lines. A list, ⛔ not one long sentence: at 320px the two
   labels are long enough to wrap into an unreadable block. */
.feelist{list-style:none;margin:.15rem 0 .6rem;padding:0}
.feelist li{margin:.1rem 0}
/* ⭐ The in-place roster editor on /admin/instant. */
.mkt-edit{padding:.6rem 0;border-bottom:1px solid var(--line)}

/* ═══════════ ⭐⭐ social26 ITEM 4 — THE CONSULTANT IS THE DEPARTMENT'S LEAD ═══════════
   ⛔ ONE component with two variants (views/partials/rostercard.ejs). Everything
   structural — the grid, the wrapping name row, min-width:0 — is inherited from
   `.mkt` and `.roster-card` above; ⛔ what is added here is ONLY the size step, so
   a layout fix made for one variant cannot miss the other. */

/* ⭐ The photo, one step above the member's 4.4rem (×1.25). The <img> tag carries
   the matching 88px so the box is reserved before the image lands. */
.roster-card.is-lead .mkt-photo .avatar{width:5.5rem;height:5.5rem;flex-basis:5.5rem}
/* ⭐ The name one size larger. ⛔ Still inside `.roster-top`, so it still wraps and
   the chip still cannot be pushed off a 320px screen. */
.roster-card.is-lead .who-name{font-size:1.12rem;line-height:1.3}
/* ⭐ A roomier পরিচিতি — the head's block is the one a patient reads, so it gets
   the larger type and the looser line. */
.roster-card.is-lead .mkt-body .tiny{font-size:.9rem;line-height:1.55}
/* ⭐⭐ THE SEPARATION BEFORE THE MBBS ROW. A heavier rule and real space beneath,
   so the lead reads as the head of what follows rather than as the first of a list.
   ⛔ `.roster-card` already draws a 1px bottom rule; this REPLACES it for the lead
   rather than adding a second line under it. */
.roster-card.is-lead{border-bottom:2px solid var(--brand-2);padding-bottom:.9rem;margin-bottom:.55rem}

/* ⭐ social27 ITEM 3 — «পাসওয়ার্ড ভুলে গেছেন?» is RECOVERY, so it sits apart from the
   primary action rather than beside it. ⛔ Not hidden: a forgotten 4-digit PIN is
   the one thing that locks a paying patient out and there is no OTP to rescue him. */
.pin-recover{margin-top:.7rem}

/* ⭐⭐⭐ social29 ITEM 1 — THE ROOM IS THE CHAT.
   ⚠ social27's note here said it was «the chat's WAITING ROOM, not a second chat —
   the real one is Cleo's page». ⛔ THAT IS INVERTED BY THE OWNER'S RULING: this IS
   the website's own chat, and it no longer hands anybody to Cleo's page, which
   renders the phone-keyed WhatsApp thread. The old sentence is kept here as the
   record of what changed and why (LB68).
   ⛔ Deliberately plain: two sides, a box, a button. Mobile-first — the thread grows
   with the page rather than scrolling inside a fixed box, so a long reply is read
   by scrolling the page like everything else on this site. */
.room-thread{margin:.8rem 0;display:flex;flex-direction:column;gap:.45rem}
/* ⭐⭐⭐ social44 ITEM B1 — `white-space:pre-wrap` MOVED OFF THE CONTAINER.
   ⚠⚠ THE RULE THIS REPLACES, kept verbatim as the record:
     .room-msg{…;padding:.55rem .7rem;margin:0;white-space:pre-wrap;overflow-wrap:anywhere;max-width:88%}
   ⛔ On the CONTAINER, pre-wrap turned every newline and indent the EJS partial
   emitted BETWEEN the spans into a literal blank line inside the patient's bubble
   — MEASURED: 8 of them for a one-word «Hi», 14 for a photo line. That is the tall
   thin box with the time floating far below it that the owner photographed, and he
   reproduced it in INCOGNITO, so it was never a stale cache.
   ⇒ THE LINE BREAKS THAT BELONG TO THE PATIENT ARE HIS OWN, and they live in
   `.room-text`. The template's are not content and must never render.
   ⛔ NO min-height anywhere: the bubble hugs whatever it holds. */
.room-msg{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:.55rem .7rem;margin:0;overflow-wrap:anywhere;max-width:88%}
/* ⭐ HIS words, and his line breaks. `display:block` so the time below it starts a
   new line exactly as it did before — the bubble's shape is unchanged, only its
   whitespace handling is. */
.room-text{display:block;white-space:pre-wrap;overflow-wrap:anywhere}
/* ⭐ The patient right, the clinic left. ⛔ The patient is never told WHICH human. */
.room-patient{align-self:flex-end}
.room-clinic{align-self:flex-start;background:var(--bg)}
.room-at{display:block;opacity:.6;margin-top:.2rem}
/* ⭐⭐⭐ social56 ITEM 7 — THE JOIN BUTTON, AND IT IS A TAP TARGET.
   The owner's ruling: a call line is a compact CLICKABLE BUTTON reading «ভিডিও কলে
   যোগ দিন», and ⛔ the raw url is never visible text (lib/consult-thread.js takes it
   out of the line before any template sees it).
   ⚠ 360px: `min-height:44px` is the WCAG 2.5.5 / iOS target and `.btn-sm` alone was
   under it; `max-width:100%` and the wrap keep a two-word Bangla label inside a
   narrow bubble instead of stretching it. ⛔ NO WIDTH FLOOR — the bubble decides how
   wide it is, and DC8/VL8's «no width above 360px anywhere in this sheet» scan reads
   this file. */
.room-call{display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;margin-top:.4rem;max-width:100%;white-space:normal;
  overflow-wrap:anywhere;word-break:break-word}
/* ⭐⭐ social56 ITEM 3/5 — THE COMPOSER'S STATE LINE, and ⛔ never a layout jump: it
   is server-rendered `hidden` and only its text changes, so revealing it adds one
   short line under the picker rather than moving the thread. */
.room-status{margin:.25rem 0 .4rem;min-height:1.1em;opacity:.9}
.room-attach-hint{margin:.15rem 0 .35rem;opacity:.75}
/* ⛔ AND A DISABLED «পাঠান» LOOKS DISABLED. A button that is dead but bright is the
   frozen control the owner reported; a button that is dead and says so is a state. */
.room-say button[type=submit][disabled]{opacity:.6;cursor:progress}
/* ⭐ social56 ITEM 4 — the console's pager, the same shape /admin/patients uses.
   ⚠ 360px: 44px of vertical room so two arrows are separately tappable on a phone. */
.dc-pager{margin:.75rem 0;display:flex;gap:1rem;justify-content:center}
.dc-pager a{min-height:44px;display:inline-flex;align-items:center}
.room-say textarea{width:100%;margin:.25rem 0 .5rem}
/* ⭐⭐⭐ social31 ITEM B2 — THE ATTACH CONTROL AND WHAT IT PRODUCES.
   ⛔ THE NATIVE FILE INPUT IS KEPT AND ONLY WRAPPED. A styled <span> with the real
   input hidden is the usual trick and it costs the keyboard and the screen reader
   the control entirely; here the <label> gives the whole row a tap target and the
   input keeps its own semantics. ⚠ 360px: it is its own row above the button, so a
   long Bangla label never squeezes «পাঠান» off the screen. */
.room-attach{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;
  margin:0 0 .6rem;font-size:.9rem;cursor:pointer}
.room-attach input[type=file]{max-width:100%;min-width:0;flex:1 1 12rem;font-size:.85rem}
.room-attach>span{flex:0 0 auto;opacity:.8}
/* ⭐ The thumbnail is CAPPED, ⛔ not full-bleed: a portrait photo at full width
   pushes the rest of the thread off the first screen. It is an anchor, so the tap
   that a photo invites opens the full-size file. */
.room-media{display:block;margin-top:.4rem}
.room-media img{display:block;max-width:100%;max-height:14rem;width:auto;height:auto;
  border-radius:var(--r);border:1px solid var(--line)}
/* ⭐ social54 — `max-width:100%` JOINS social31's rule rather than a SECOND
   `.room-file` block overriding it. ⚠ The first draft added one, and VL8 read the
   EARLIER of the two — a duplicate selector is drift the moment it exists.
   ⛔ `overflow-wrap:anywhere` STAYS: a long filename WRAPS, which keeps the whole
   name readable; truncating it with an ellipsis would hide the extension, and the
   extension is the one part a patient needs to recognise. */
.room-file{display:inline-block;max-width:100%;margin-top:.4rem;overflow-wrap:anywhere}
/* ⭐⭐⭐ social31 ITEM B1 — THE HONEST LINE. ⛔ It must READ as a warning and not as
   decoration, so it is the one place in a message bubble that carries a colour of
   its own. ⚠ `--bad` is the token the site's own alert-bad already uses, so a theme
   change cannot leave this the only stale colour on the page. */
.room-undelivered{display:block;margin-top:.25rem;color:var(--bad);opacity:1}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social38 ITEM A2 — THE BOOKING FORM'S CHAMBER RADIOS.

   ⚠⚠ THE INPUT RULE AT THE TOP OF THIS FILE IS WHY THIS BLOCK EXISTS, and it is
   the SAME trap social15 ITEM 2 documented for the day boxes:
   `input,select,textarea{width:100%}` is written for text boxes and applies to a
   RADIO as well — so an unstyled radio stretches to the whole row and shoves its
   own label onto the next line. ⛔ The fix is scoped to this control, ⛔ not a
   change to the global rule, which forty other boxes depend on.

   ⭐ THE LABEL WRAPS AND THE RADIO DOES NOT. «পপুলার ডায়াগনস্টিক সেন্টার — হাউস
   ৩৭, রোড ৪, ধানমন্ডি» is a realistic option and it does not fit on one line at
   320px. `align-items:flex-start` keeps the dot beside the FIRST line of a
   two-line address instead of centring it against the block.
   ⛔ NO max-width AND NO ellipsis: the address is the recognition handle (the
   owner's own reason), and a truncated address recognises nothing.
   ══════════════════════════════════════════════════════════════════════════════ */
.chamberpick{border:0;padding:0;margin:0 0 14px}
.chamberpick legend{padding:0;font-weight:600;font-size:.92rem;margin-bottom:.35rem}
.radiorow{display:flex;align-items:flex-start;gap:.55rem;font-weight:400;
  border:1px solid #d7e2de;border-radius:9px;background:#fff;
  padding:.6rem .7rem;margin-bottom:.4rem;cursor:pointer;line-height:1.45}
/* ⛔ `width:auto` and `flex:none` — the two halves of undoing the global rule. */
.radiorow input[type="radio"]{width:auto;flex:none;margin:.25rem 0 0;padding:0}
.radiorow span{overflow-wrap:anywhere}
/* ⭐ The consent line is the last thing read before submit, so it sits ON the
   button rather than floating above the form. ⛔ Not `.muted`: it is a statement
   about where his data goes and it has to be legible. */
.consent{margin:.2rem 0 .9rem}
/* ⭐ «অপেক্ষমাণ» / «✅ নিশ্চিত হয়েছে» — the one line on the status page that
   changes. ⛔ No colour of its own: the tick already carries the meaning, and a
   green «confirmed» beside a grey «waiting» invites reading the grey as an error. */
.statusline{font-weight:600;margin:.6rem 0}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social40 ITEM 5 — THE EYE IS A CONTROL NOW, AND IT KEEPS ITS OLD LOOK.
   ⚠ It became a <button>, and a <button> arrives with a browser's own border,
   background, padding and font. ⛔ Every one of those is stripped, because the
   owner asked for the count to MOVE, ⛔ not to change appearance. What is added is
   only what a control needs and a <span> did not: a pointer and a tap target.
   ⚠ `.post-ft` is a flex row, so «first in the DOM» is «far left» — ⛔ no `order`
   property, which would put the visual order and the DOM order out of step for a
   screen reader.
   ══════════════════════════════════════════════════════════════════════════════ */
.post-ft .viewcount{
  border:0;background:none;padding:.15rem .1rem;margin:0;font:inherit;color:inherit;
  line-height:1;cursor:pointer;width:auto;flex:none}
.post-ft .viewcount:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* ⭐ The revealed line sits inline beside the eye and wraps with the row. */
.post-ft .viewsline{align-self:center;overflow-wrap:anywhere}
/* ⭐ social40 ITEM 1b — the two staff buttons sit on one row and wrap on a phone. */
.actrow{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center}

/* ⭐ social45 — the gateway's two lines. ⛔ Deliberately quiet: the ✅ is the whole
   signal, and a green banner in a medical chat reads as a medical result. */
.paid-ok{color:#1c7c40}
.paystart{margin:.6rem 0 .2rem}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social52 ITEM 2 — THE DOCTOR CONSOLE'S LIST, AT 360px.

   ⛔⛔ ONE FLEX ROW THAT CANNOT WRAP AND CANNOT OVERFLOW, which is the whole 360px
   property and is asserted as a DECLARED RULE (DC8) rather than as a rendered box —
   there is no browser in the suite, and claiming a measured layout would be
   claiming something nothing here can see (MB1/RM5's own honest label).
   ⭐ THE THREE PARTS: a name+meta column that SHRINKS (min-width:0 + ellipsis, or a
   long Bangla name pushes the time off the screen), and a right column that does
   NOT — the unread badge and the time are the two things a doctor scans down.
   ⚠ `min-width:0` IS LOAD-BEARING: a flex item's default `min-width:auto` refuses
   to shrink below its content, so without it a long name makes the ROW wider than
   the viewport and the whole page scrolls sideways — the one thing MB1 forbids.
   ══════════════════════════════════════════════════════════════════════════════ */
.dc-row{display:flex;align-items:center;justify-content:space-between;gap:.6rem;
  padding:.7rem .2rem;border-bottom:1px solid var(--line,#e6e9ee);
  color:inherit;text-decoration:none}
.dc-row:last-child{border-bottom:0}
/* ⭐ THE SHRINKING HALF. ⛔ `min-width:0` — see above. */
.dc-main{display:flex;flex-direction:column;gap:.15rem;min-width:0;flex:1 1 auto}
.dc-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dc-meta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ⭐⭐ social69 ITEM 1 — the account holder's line, when the patient is somebody
   else. ⛔ NO NEW GEOMETRY: it is a `.dc-meta` inside the same `.dc-main` column, so
   it ellipsises exactly like the two lines it sits between and ⛔ nothing can widen
   the row. ⭐ Muted, because it is context and ⛔ not the patient's name. */
.dc-account{color:var(--muted,#667)}
/* ⛔ THE FIXED HALF — `flex:none`, so the badge and the time are never squeezed to
   nothing by a long name. */
.dc-side{display:flex;align-items:center;gap:.5rem;flex:none}
.dc-at{white-space:nowrap}
/* ⭐⭐ THE NEEDS-REPLY MARKER IS A BAR AND A WEIGHT, ⛔ not a colour alone: a doctor
   with any degree of colour-blindness must still see which rows are waiting, and a
   list where the only signal is hue is a list he cannot triage. */
/* ⭐⭐ social59 ITEM 5 — the UNSEEN mark. ⛔ `flex:none` so it can never squeeze the
   name into a wrap: `.dc-main` is `min-width:0; flex:1 1 auto` and absorbs it, and
   `.dc-name` keeps its own ellipsis. ⛔ No new colour — `var(--brand)` is the one
   `.dc-wait` already uses. */
.dc-dot{flex:none;width:.5rem;height:.5rem;border-radius:50%;background:var(--brand)}
.dc-wait{border-left:3px solid var(--brand);padding-left:.5rem}
.dc-wait .dc-name{font-weight:700}
/* ⭐ The unread count. ⛔ It renders only when it is non-zero (the template decides),
   so this rule never draws an empty pill. */
.dc-badge{display:inline-block;min-width:1.35rem;padding:.05rem .35rem;border-radius:999px;
  background:var(--brand);color:#fff;font-size:.78rem;line-height:1.5;text-align:center}
.dc-head{overflow-wrap:anywhere}
/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social73 ITEM 2 — **THE ৪৯৯ MARK. LOUD, AND IN THE SITE'S OWN TOKENS.**

   THE OWNER'S OWN REASON FOR THE VOLUME: the consultant and the MBBS doctor SHARE
   the `doc1` login, so ⛔ there is no wrong seat to hide the row from — the MARK is
   the only protection this system has. ⇒ ⛔ NOT a corner badge and ⛔ not a hue: a
   full-width band with its own border and a bold first line, so it survives a tired
   eye, a bright screen and colour-blindness alike.
   ⛔ NO NEW COLOUR SYSTEM. The three values are `.alert-warn`'s own triple
   (background #fdf5e2, border #f0dfae, text `--warn`) — the site's existing «read
   this before you act» vocabulary, ⛔ not a fourth palette.
   ⚠ `overflow-wrap:anywhere` AND NO `white-space:nowrap`: this block lives inside
   `.dc-main` (`min-width:0`), so a long consultant name WRAPS rather than widening
   the row — MB1's «⛔ nothing scrolls sideways» at 360px, which KN-10 measures.
   ⛔ `.dc-tier-row` ADDS NO GEOMETRY — a left bar and a paler ground on the row
   itself, exactly `.dc-wait`'s shape, so the two can sit on one row without fighting
   (`.dc-wait` sets its own border-left; the last declaration wins, and either bar
   says «look here», which is the honest outcome of both being true).
   ══════════════════════════════════════════════════════════════════════════════ */
.dc-tier{display:block;background:#fdf5e2;color:var(--warn);border:1px solid #f0dfae;
  border-radius:.4rem;padding:.28rem .45rem;margin:0 0 .25rem;
  font-size:.86rem;line-height:1.35;overflow-wrap:anywhere;white-space:normal}
.dc-tier strong{display:block;font-weight:700}
.dc-tier-dr{display:block}
.dc-tier-head{margin:.4rem 0 .6rem;font-size:.95rem}
.dc-tier-row{border-left:4px solid var(--warn);padding-left:.5rem;background:#fffdf6}
/* ⭐ social73 ITEM 3 — WHO WROTE A CLINIC LINE. ⛔ Its own block above the words, so
   a doctor scanning a thread can tell his own line from a staff member's at a glance.
   ⛔ No new colour — `--muted` is the token every quiet line on this site uses. */
.room-who{display:block;color:var(--muted,#5b6472);font-weight:600}
/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social63 ITEM 3 — THE BLURRED DOOR AND THE REASON UNDER IT.
   ⛔⛔ NEITHER IS A LOCK. `.dc-blur` dims «পরামর্শে যান» on a booking staff have not
   approved yet and `[disabled]` greys the two decision buttons; the SERVER is what
   refuses both (routes/booking.js answers 403, every পরামর্শ door asks
   `booking.isApproved`). BA-12 removes these rules and drives the doors anyway.
   ⛔ NO NEW COLOUR AND NO NEW VARIANT: `--muted` is the token every quiet line on
   this site already uses, and the element keeps its `.btn-ghost` shape so the door
   looks like the door it will become. `cursor:default` because ⛔ nothing here is
   pressable — a pointer over a dead control is the product lying with a cursor.
   ══════════════════════════════════════════════════════════════════════════════ */
.dc-blur{opacity:.45;filter:blur(.4px);color:var(--muted,#5b6472);cursor:default;
  -webkit-user-select:none;user-select:none}
/* ⭐ THE REASON, directly under the row it explains — ⛔ never a tooltip: a tooltip
   is a thing a thumb cannot open, and «why is this greyed out» must be answerable
   on the page itself. */
.dc-why{color:var(--muted,#5b6472);margin:-.45rem 0 .6rem;padding-left:.2rem}
/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social60 — THE END-CONSULTATION CONTROL AND THE QUIET SECTION.
   ⛔ NO NEW COLOUR SYSTEM AND ⛔ NO NEW BUTTON VARIANT: `--bad` is the token
   `.alert-bad`, `.chip-bad` and `.room-undelivered` already use, so an irreversible
   control reads as one in exactly the site's own vocabulary. ⭐ It stays a
   `.btn-ghost` — the shape says «quiet», the colour says «this one ends something».
   ⚠ THE SEPARATION IS THE POINT: the composer's «পাঠান» is a filled primary block
   directly above, and a doctor's thumb must not find this by accident. The margin is
   what buys that at 360px.
   ⛔ `.dc-ended` ADDS NO ROW STYLE. Its children are `.dc-row` links, byte for byte
   the live list's, so a doctor learns one shape; the section is quieter only in its
   heading. ══════════════════════════════════════════════════════════════════════ */
.dc-end{margin-top:1.5rem}
.dc-end button{color:var(--bad);border-color:#f4c7c3}
.dc-ended h2{color:var(--muted,#5b6472);font-weight:600;margin:0 0 .25rem}
/* ⛔ The logout form must not become a block that pushes the strip's title around. */
.strip form.inline{margin:0}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social53 ITEM 2 — THE CONSOLE'S POKE STRIP.

   ⛔⛔ IT IS IN THE PAGE FLOW, ⛔ NOT FIXED AND ⛔ NOT AN OVERLAY. `.pwabar` above is
   `position:fixed` because it is a passing banner over a patient's feed; this one
   sits between the phone notice and the list, so the list scrolls normally beneath
   it and ⛔ nothing is ever covered. «Never a wall» is this rule, not a promise.

   ⭐ 360px: a WRAPPING flex with a shrinking button. The CTA is a long Bangla phrase
   («নোটিফিকেশন চালু করুন»), so on the narrowest phone it takes its own line and the
   ✕ stays beside it — ⛔ no horizontal scroll, and ⛔ NO width or min-width floor
   anywhere in this block (DC8/WN8 scan the whole sheet for one above 360px).
   ══════════════════════════════════════════════════════════════════════════════ */
.dcpush{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;
  margin:.4rem 0 .6rem;padding:.55rem .6rem;border-radius:.5rem;
  background:var(--card,#fff);border:1px solid var(--line,#e6e9ee)}
/* ⭐ The button shrinks rather than pushing the row wider; its label may ellipsize
   on a very narrow phone and the ✕ is still reachable. */
.dcpush-go{flex:auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;text-align:center}
.dcpush-x{flex:none;background:transparent;border:0;font-size:1.1rem;
  line-height:1;padding:.25rem .35rem;color:var(--muted,#667);cursor:pointer}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social54 — THE CLOSE CONTROL, THE CALL BUTTONS, THE VIDEO AND THE DOOR.
   ⛔ NO WIDTH OR MIN-WIDTH FLOOR ANYWHERE IN THIS BLOCK — the 360px scan reads the
   whole sheet and a floor here would fail it for every page, not just these.
   ══════════════════════════════════════════════════════════════════════════════ */
/* ⭐ The room's «✕» rides at the top-right of the page flow — ⛔ not fixed, so it
   never covers a bubble and never blocks the thread. */
.room-x{float:right;margin:0 0 .2rem .5rem}
.room-x-btn{background:transparent;border:0;font-size:1.15rem;line-height:1;
  padding:.3rem .45rem;color:var(--muted,#667);cursor:pointer}
/* ⭐ The two call buttons WRAP rather than overflow: their Bangla labels are long
   («ভিডিও কল লিংক পাঠান»), so on the narrowest phone they take a line each. */
.dc-call{display:flex;flex-wrap:wrap;gap:.4rem;margin:.5rem 0}
.dc-call .inline{display:inline;margin:0}
/* ⭐ A video never overflows its bubble and never dictates the page width. */
/* ⭐⭐ social69 ITEM 2 — the video fits a 360px phone and RESERVES A SLOT before it
   loads, so ⛔ the thread does not jump when metadata arrives.
   ⚠ HONEST LIMIT, and it is in the report: this repo does not store a video's
   dimensions, so the reservation is a FIXED FLOOR rather than the file's own ratio.
   A `min-height` cannot be wrong the way a guessed `aspect-ratio` can — it reserves
   space and then gets out of the way once the real height is known. */
.room-video{display:block;max-width:100%;height:auto;min-height:9rem;border-radius:.4rem;margin:.35rem 0}
/* ⭐ THE «NO PLAYER» SENTENCE — drawn by the BROWSER only when it can play none of
   the sources. ⛔ Never styled to look like a control: it is a sentence. */
.room-noplayer{display:block;color:var(--muted,#667);font-size:.85rem;padding:.4rem 0}
/* ⭐ The way back into an open consult, on /instant. */
.openconsult{margin:.6rem 0}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social64 LP-1e / LP-2c — THE LEGAL PAGES AND THE COMPLIANCE FOOTER.
   ⛔ NO WIDTH, MIN-WIDTH OR WHITE-SPACE:NOWRAP FLOOR ANYWHERE IN THIS BLOCK. The
   360px scan reads the WHOLE sheet, and the pack's contact tables are the exact
   shape that would have introduced one — so they are `dl`s that STACK on a phone
   and only become two columns where two columns fit.
   ══════════════════════════════════════════════════════════════════════════════ */
.legaldoc{line-height:1.6}
.legaldoc .page-h1{margin:0 0 .35rem}
.legaldoc .lede{color:var(--muted,#667);margin:0 0 .6rem}
.legal-date{color:var(--muted,#667);font-size:.85rem;margin:0 0 1rem}
.legal-h2{font-size:1rem;margin:1.3rem 0 .4rem}
.legaldoc p{margin:.55rem 0}
.legal-list{margin:.45rem 0 .8rem;padding-left:1.15rem}
.legal-list li{margin:.3rem 0}
/* ⭐ The pack's boxed notices — the emergency warning, the return-policy note, the
   seven-business-day timeline. They are the sentences a reviewer looks for first. */
.legal-callout{margin:.8rem 0;padding:.65rem .75rem;border-radius:.5rem;
  background:var(--card,#fff);border:1px solid var(--line,#e6e9ee)}
.legal-callout p{margin:.3rem 0}
.legal-callout-h{font-weight:600}
/* ⭐⭐ A CONTACT TABLE THAT IS NOT A TABLE. Stacked label-over-value at 360px;
   ⛔ never a row that forces the page wider than the phone. */
.legal-rows{margin:.6rem 0;display:block}
.legal-rows dt{font-weight:600;margin:.6rem 0 .1rem;color:var(--muted,#667);font-size:.85rem}
.legal-rows dd{margin:0;overflow-wrap:anywhere}
@media (min-width:520px){
  .legal-rows{display:grid;grid-template-columns:minmax(0,11rem) minmax(0,1fr);
    column-gap:.9rem;row-gap:.35rem;align-items:baseline}
  .legal-rows dt{margin:0}
}
/* ══════════════════════════════════════════════════════════════════════════════
   ⭐ THE FOOTER. It WRAPS — every row is flex-wrap or plain flow, and the link
   list breaks onto as many lines as the phone needs. ⛔ It never widens the page.
   ══════════════════════════════════════════════════════════════════════════════ */
.legalftr{padding:18px var(--pad) 28px;color:var(--muted,#667);font-size:.8rem;
  text-align:center;border-top:1px solid var(--line,#e6e9ee)}
.legalftr-links{display:flex;flex-wrap:wrap;justify-content:center;
  align-items:center;gap:.3rem .45rem;margin:0 0 .6rem}
.legalftr-links a{color:inherit;text-decoration:underline}
.legalftr-links .sep{opacity:.45}
.legalftr p{margin:.15rem 0;overflow-wrap:anywhere}
.legalftr-co{font-weight:600}
/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social68 EP ITEM 5 — THE PAYMENT BANNER'S SLOT.
   ⭐ CAPPED AT THE SITE'S OWN COLUMN (`--wrap-max`, 680px — the same width every
   page's content uses), so on a desktop the wide artwork sits in the same column as
   everything above it instead of stretching across a 27-inch monitor.
   ⛔ `max-width:100%` KEEPS IT INSIDE A 360px PHONE and `height:auto` keeps the
   ratio — so it ⛔ never widens the page, which is MB1's standing law.
   ⭐ THE `width`/`height` ATTRIBUTES ON THE MARKUP RESERVE THE SPACE. With
   `height:auto` the browser uses the attribute ratio to hold the box before the
   bytes arrive, so a lazily-loaded banner ⛔ does not shift the copyright line.
   ⚠ `picture` IS `display:contents` — it is a selection wrapper with no box of its
   own, and giving it one would put a second layout between the slot and the image.
   ══════════════════════════════════════════════════════════════════════════════ */
.legalftr-pay{margin:.6rem 0 .4rem;min-height:0}
.legalftr-pay picture{display:contents}
.legalftr-pay img{display:block;margin:0 auto;max-width:min(100%, 680px);height:auto}
.legalftr-copy{margin-top:.6rem}

/* ═══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social65 ITEM 1+2 — **THE ACCEPTANCE BLOCK: FINE PRINT, A REAL GAP, AND A
   BUTTON THAT LOOKS BLOCKED WITHOUT BEING DEAF.**

   ⚠⚠ THERE WAS NO `.policytick` RULE AT ALL until this pass, and that absence IS
   half of what the owner photographed. With no rule of its own the terms line fell
   through to the global `label{font-weight:600;font-size:.92rem}` — ⇒ it rendered
   BOLD and at nearly body size, which is why a legal footnote read as a heading.

   ⭐ THE SIZE COMES FROM `.tiny`, PUT ON THE **SPAN** BY THE PARTIAL (.82rem, muted)
   — the site's own fine-print token, ⛔ not a new class and ⛔ not a px literal. The
   step is .92rem → .82rem, and .82rem is the size every «তিনি ৭ দিনে…» note on this
   site already prints at.
   ⭐⭐ THE CHECKBOX IS UNTOUCHED, BY CONSTRUCTION AND ⛔ NOT BY A COUNTER-RULE. The
   <label> keeps its .92rem, the input keeps `font:inherit` from the global control
   rule, and only the <span> steps down. ⇒ there is no declaration anywhere that can
   shrink the box — ⛔ nothing here sets its width, its height or its font, so its tap
   target is the browser's own, exactly as it was before this pass. ⛔ Sizing the
   LABEL would have shrunk it on WebKit, where a checkbox scales with its font; TF-6
   prints the before and the after.

   ⭐ THE GAP THE OWNER ASKED FOR — «`নতুন ফোন বা ব্রাউজারে…`-r sathe terms link PRAY
   LEGE GECHE — ekhane ektu GAP dite hobe.» That hint is `<p class="tiny">`, whose
   `margin:0` put it flat against a block that had no margin either. ⇒ `var(--pad)`,
   ⛔ not a magic number: the page's OWN spacing token, the one `.wrap` and `.card`
   already pad by. One rule, and the gap lands identically on all five surfaces.
   `font-weight:400` restores what `.tiny` renders at everywhere else on this site —
   the global `label` bold was inherited by accident, never chosen.
   ═══════════════════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social65 ITEM 1 — **`.err` HAD NO RULE EITHER, AND THAT IS THE OTHER HALF OF
   «AGER MOTO RED ERROR».**

   ⚠⚠ FOUND WHILE MAPPING THE PAY PRESS, and it is a defect in its own right: eleven
   templates print a refusal as `<p class="err">…</p>` — /instant, /serial/:slug, the
   booking page, the consent step, both logins, three admin screens — and this
   stylesheet declared ⛔ NOTHING for that class. ⇒ every server-side refusal on this
   site has been rendering as ORDINARY BLACK BODY TEXT: the words were there and the
   colour that says «this is an error» never was.
   ⭐ THAT IS THE PATH A SCRIPTLESS BROWSER TAKES. With JavaScript off the press goes
   to the server, routes/instant.js answers «বিভাগ ও ফি — দুটোই বেছে নিন।», and until
   this rule that sentence arrived looking like a paragraph.
   ⛔ COLOUR ONLY, ⛔ not a box: `.alert-bad`'s panel on eleven existing pages would
   move layout the owner did not ask to have moved. `--bad` is the token `.alert-bad`,
   `.chip-bad` and `.room-undelivered` already read — ⛔ no new colour was chosen.
   ⭐ `font-weight:600` is the emphasis idiom this repo already uses for the line that
   matters; ⛔ no size is set, so an error stays at the page's own body size. */
.err{color:var(--bad);font-weight:600}

.policytick{margin:var(--pad) 0}
.policytick label{font-weight:400;margin-bottom:0}
/* ⛔ The links stay UNDERLINED at the smaller size — no `text-decoration:none` is
   declared here or inherited, and `--brand-dk` keeps them off the muted body colour.
   A policy name a reviewer cannot pick out of a grey line is a policy name he will
   report as missing. */
.policytick a{color:var(--brand-dk)}

/* ⭐⭐ THE RED LINE, AND `:empty` IS WHAT HIDES IT. ⛔ Not `hidden` toggled by script
   (app.js only ever ADDS `hidden`) and ⛔ not a class: an element that is invisible
   BECAUSE it has nothing to say cannot be left stuck open by a script that died, and
   `textContent = ''` is then the whole of «take the error back». */
/* ⛔ NO margin of its own: it carries `.alert`, whose `margin:0 0 14px` is already
   this site's spacing under a message box. A second number here would be a second
   opinion about the same gap. */
.gate-msg:empty{display:none}

/* ⭐⭐ «IT LOOKS BLOCKED.» The dim treatment the pay button never had — `opacity:.6`
   is `.room-say button[type=submit][disabled]`'s own number, the idiom this site
   already uses for a control that is not ready. ⛔ ON `aria-disabled` AND ⛔ NEVER ON
   `[disabled]`: the button must keep receiving the click that produces the sentence.
   ⛔ `cursor` is left alone — `not-allowed` over a control that IS allowed to be
   pressed would be the same lie the disabled attribute told. */
.btn[aria-disabled="true"]{opacity:.6}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social66 HS ITEM 4 — THE «অন্য সময়» DISCLOSURE, ON THE STAFF CONSOLE.
   ⛔⛔ IT IS NOT A THIRD ROW SHAPE. `.dc-row` is `display:flex` and the form is a
   THIRD child beside `.dc-main` and `.dc-side`, so without a rule it would fight
   the two of them for one line on a 360px phone. ⇒ the row wraps and the
   disclosure claims the whole of the second line — ⛔ the only geometry change,
   and ⛔ no new colour, no new button variant and no new token.
   ⭐ `flex-basis:100%` rather than a width: it takes the line it is on and nothing
   more, whatever the two halves above it did.
   ⚠ 360px: the two selects and the button WRAP inside it, and each select is
   `max-width:100%`, so ⛔ nothing here can push the page sideways (MB1's law).
   ══════════════════════════════════════════════════════════════════════════════ */
.dc-row{flex-wrap:wrap}
.dc-move{flex:0 0 100%;margin:.25rem 0 0}
.dc-move summary{cursor:pointer;color:var(--brand-dk)}
.dc-move form{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem;margin-top:.4rem}
.dc-move select{max-width:100%;min-width:0}
/* ⭐ THE «this was moved» LINE takes its own line too — it is a sentence about the
   row, ⛔ not a chip beside the hour. */
.dc-row .dc-why{flex:0 0 100%;margin:.15rem 0 0}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social66 HS ITEM 5 — THE হিসাব ঘর'S FILTER.
   ⛔ NO NEW TABLE CLASS: the board itself is `.board` inside `overflow-x:auto`,
   the SAME pair /admin/sales and /admin/unclaimed already carry, so the page body
   never scrolls sideways on a phone and a staff member learns ONE table shape.
   ⭐ Only the filter needs geometry, and it is one wrapping row of fields.
   ══════════════════════════════════════════════════════════════════════════════ */
.moneyfilter{display:flex;flex-wrap:wrap;align-items:flex-end;gap:.6rem}
.moneyfilter .field{flex:1 1 8rem;min-width:0;margin:0}
.moneyfilter select,.moneyfilter input{max-width:100%;min-width:0}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social68 EP ITEM 3 — THE LEGAL EDITOR'S TEXTAREA.
   ⛔ NO `cols` AND ⛔ NO PIXEL WIDTH: a textarea's default width is its `cols`
   attribute, which is a character count and overflows a 360px phone the moment the
   font is anything but tiny. `width:100%` inside `.card`'s own padding is the whole
   fix, and `box-sizing` is already border-box site-wide.
   ⭐ `resize:vertical` — he can make it taller to read a long clause; ⛔ never
   horizontally, which is the one direction that would widen the page.
   ⚠ A MONOSPACE FACE ON PURPOSE: this is a plain-text document whose PARSER cares
   about leading spaces (an indented line is a callout, a three-space gutter is a
   table row). In a proportional font he cannot see the indentation he is editing.
   ══════════════════════════════════════════════════════════════════════════════ */
.legaledit textarea{width:100%;max-width:100%;min-width:0;resize:vertical;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:.85rem;line-height:1.45;white-space:pre;overflow-wrap:normal;overflow-x:auto}
/* ⭐ The «সর্বশেষ হালনাগাদ» line sits directly under the effective date and reads as
   its quieter sibling. ⛔ No new colour token. */
.legal-updated{color:var(--muted,#667);font-size:.85rem;margin:.7rem 0 0;text-align:center}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social76 — THE প্রশ্ন COMPOSER AND ITS CARD.
   ⛔ NO NEW CARD CLASS: a question renders as `article.post`, the feed's own card,
   so padding, border, body type and the action row are the site's. `.qpost` and
   `.qanswer` exist only to be reachable by a check and carry ⛔ no geometry.
   ⭐ `.qfields` is `.moneyfilter`'s own proven geometry under its own name — a
   wrapping flex row with `min-width:0`, so at 360px the four controls stack and
   ⛔ nothing forces the page wider. ⛔ No width, ⛔ no min-width, ⛔ no px anywhere.
   ══════════════════════════════════════════════════════════════════════════════ */
.qfields{display:flex;flex-wrap:wrap;align-items:flex-end;gap:.6rem}
.qfields .field{flex:1 1 7rem;min-width:0;margin:0 0 14px}
.qfields select,.qfields input{max-width:100%;min-width:0}
/* ⭐ The banner inside a card sits tight to the text it is about. ⛔ Its colours are
   `.alert-bad`'s — the site's own red token, ⛔ no new colour was chosen. */
.qflag{margin:0 0 12px}
/* ⭐ The system-written closing line reads as what it is: quieter than the doctor's
   own words, and never mistakable for them. ⛔ It is appended at RENDER and is not
   in the stored body (lib/question.js `closingLinesBn`). */
.qclosing{margin:.5rem 0 .35rem}
/* ⭐ The withdrawal control sits at the far right of the card's action row — the
   same `margin-left:auto` the eye/like row already uses to push its last item over.
   ⛔ IN CSS, ⛔ never an inline `style=`: this site sends a strict CSP with a nonce
   and no `'unsafe-inline'` for styles, so an inline attribute is a control that
   would silently lose its position on the owner's own phone. */
.qpost .post-ft .qwithdraw{margin-left:auto}
/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social79 ITEM 3 — **THE BAR DOWN THE LEFT OF A রোগীর প্রশ্ন CARD.**

   THE OWNER, 2026-08-26: «Pt-er post jeguli dashboard-e kore, segulir margin-ta
   amader logo-r green ba blue ba khoyeri … sei color-er dag.» And, ruling on the
   shape: «BA-PASHE EKTA DAG dilei mone hoy valo, noyto cokher jonno somossa hote
   pare.» ⇒ ⭐ LEFT ONLY, ⛔ never a border all the way round.

   ═══ ⭐⭐ WHY THIS COLOUR, MEASURED RATHER THAN PICKED ═══
   The two logo files were read pixel by pixel (public/img/hellodoctor-logo-600.png,
   hellodoctor-mark-512.png) and they carry EXACTLY TWO colours: #4088d0 and #40a8b8
   — which are `--brand` and `--brand-2` to within the PNG's own 8-bit rounding.
   ⚠⚠ THERE IS ⛔ NO GREEN AND ⛔ NO খয়েরি IN THE LOGO. He named three; his logo has
   two, and the teal is the one a reader calls «the green one».
     candidate            contrast vs the card (#fff)   why not
     --brand   #3F88CD         3.74:1   ⛔ hue 209°; the blue tick is #1D9BF0 at 204°
     --brand-dk #2F6DA8        5.42:1   ⛔ the same blue family, one step darker
     .seal green #0a8f6a       4.08:1   ⛔ that is the VERIFIED-DOCTOR tick's own fill
     --bad     #b3261e         6.54:1   ⛔ the red-flag banner's own token (.alert-bad)
     --warn    #8a6100         5.54:1   ⛔ the amber alert's own token
     ⭐ --brand-2 #42AAB7      2.74:1   ✓ in the logo · 17° off the blue tick · quiet
   ⚠ 2.74:1 IS BELOW WCAG 1.4.11's 3:1, AND THAT IS THE CHOICE RATHER THAN AN
   OVERSIGHT: the bar carries ⛔ no information — the card already says «প্রশ্ন» in a
   chip and names the asker as a handle — so it is decoration, and his own words were
   «noyto cokher jonno somossa hote pare». The deep green at 7.8:1 is the shouting he
   asked me not to do. ⭐ The number is in the report so he can overrule it.

   ⭐ ONE DECLARATION, READING AN EXISTING TOKEN. ⛔ No new hex was invented and ⛔ no
   hex is spelled here at all: `--brand-2` is declared once, in `:root`, and every
   surface the question card renders on (the feed, the dashboard, /q/:id and the
   doctor's first room) inherits this from the one place — so a fourth surface gets
   it free, which is the same discipline `.seal-blue` shipped under in social78.
   ⛔ NOT on a doctor's post and ⛔ not on a brand post: `.qpost` is on the question
   card and on nothing else in views/.
   ⚠ `.post` already declares `border:1px solid var(--line)`, so this OVERRIDES the
   left edge rather than adding to it — the card's total width does ⛔ not change and
   ⛔ nothing can be pushed sideways at 360px. It costs 3 CSS px of content width.
   ══════════════════════════════════════════════════════════════════════════════ */
.qpost{border-left:4px solid var(--brand-2)}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ social79 ITEM 1 — **THE CALL LIST, STACKED BY DEFAULT.**

   ⚠⚠ 360px IS NOT OPTIONAL HERE: this is the page the owner and his staff will use ON
   A PHONE, standing up, while dialling. ⛔ A table that scrolls sideways hides the very
   column they came for.
   ⭐ THERE IS ⛔ NO MEDIA QUERY AND ⛔ NO BREAKPOINT. Each row is a `flex-wrap:wrap`
   container whose three parts have `min-width:0` and no width at all — so at 360px they
   stack because there is no room, and on a laptop they sit on one line because there is.
   The narrow screen is the DEFAULT state of the rule, ⛔ not a special case of it, which
   is the same geometry `.qfields` (itself `.moneyfilter`'s) has been proved on twice.
   ⛔ NO `px` WIDTH ANYWHERE, so nothing here can force the page wider than the viewport.

   ⭐ `.callrow-open` vs `.callrow-done` carry ⛔ NO geometry and ⛔ no new colour: the
   done rows simply sit quieter, which is the visual half of «uncalled first». The ORDER
   is the server's (lib/call-list.js `orderRows`); this only agrees with it.
   ══════════════════════════════════════════════════════════════════════════════ */
.callcounts{display:flex;flex-wrap:wrap;gap:8px 20px;list-style:none;margin:0 0 12px;padding:0}
.callcounts strong{font-size:1.2rem}
.calllist{list-style:none;margin:0;padding:0}
.callrow{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;
  background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  padding:10px var(--pad);margin:0 0 8px}
/* ⭐ `flex:1 1 12rem` + `min-width:0` — the pair that lets a long Bangla name wrap
   inside its own box instead of pushing the row past the viewport. */
.callwho{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px;flex:1 1 12rem;min-width:0}
.callwho .who-name{overflow-wrap:anywhere}
.callphone{font-variant-numeric:tabular-nums;white-space:nowrap}
.callmeta{display:flex;flex-wrap:wrap;gap:2px 12px;flex:1 1 10rem;min-width:0;margin:0}
.callby{overflow-wrap:anywhere}
.callmark{display:flex;flex-wrap:wrap;align-items:center;gap:6px;flex:0 1 auto;min-width:0}
.callmark select{max-width:100%;min-width:0}
.callrow-done{opacity:.72}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social77 ITEM 3b — «ভিডিও/অডিও কল শুরু করা যাবে … থেকে।»
   ⛔ NO NEW COLOUR AND NO NEW BOX: on the thread it is `.alert.alert-info`, the
   site's own quiet blue; on a list row it is `.tiny`, the site's own fine print.
   `.callopens` only gives it room to breathe on its own line — a sentence about a
   time must not sit mid-row between a price and a button.
   ══════════════════════════════════════════════════════════════════════════════ */
.callopens{display:block;margin:.3rem 0 0}

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ social78 ITEM 1 — THE BLUE TICK.
   THE OWNER: «seta tick dile GREEN tick ta BLUE hoye jabe — Meta-r verified-er moto.»
   ⛔ THE SAME GLYPH, RE-COLOURED BY ONE CLASS — ⛔ no second image, ⛔ no second SVG
   path, ⛔ no extra request. `.seal` already owns the size, the stroke and the round
   plate, and its own white text colour already drives the tick through currentColor.
   ⇒ ⭐ ONE DECLARATION IS THE WHOLE CHANGE: the two ticks are the same shape in the
   same place and only the background says which.
   ⭐ THE BLUE IS META'S OWN VERIFIED HUE (#1D9BF0), which is what «Meta-r verified-er
   moto» means to anybody who has seen one. ⛔ Not a new brand token: it is a
   deliberate borrow of a convention the owner named, and it lives on this one class.
   ══════════════════════════════════════════════════════════════════════════════ */
.seal.seal-blue{background:#1D9BF0}
/* ⭐ social78 ITEM 4 — the unpaid landing's block. ⛔ NO new colour and ⛔ no new box:
   `.alert.alert-warn` is the site's own amber, which is the right register for «it did
   not happen» — ⛔ not `.alert-bad`, which this product uses for a refusal the reader
   caused. `.payfailed` only gives the retry link room beneath the two sentences. */
.payfailed p{margin:.35rem 0 0}
