/* Nagarik — portal styles.
   Deliberately small and dependency-free. amol365 pulls Tailwind's Play CDN and
   DaisyUI — its own comment calls that "prototyping only; swap for a Vite build
   before production" — which is two render-blocking CDN round-trips before
   anything paints. This audience reads on cheap phones over metered 3G, so the
   whole stylesheet is hand-written and served from the same origin.

   ── The palette, and why it is not the app's exactly ──────────────────────
   The app is a deep blue sea with glass cards at 12% white. That looks right at
   full brightness and loses its structure at low: a card sits 1.1 : 1 against
   the ground, so at a dim backlight the edges vanish and the page becomes one
   dark smudge. Text is never the problem there — white on the sea is 11 : 1
   whatever the brightness. Layers are.

   So this is the same sea with the layers pulled apart:

     ground   #08334F   flat, not a gradient — a gradient makes a card's
                        separation depend on where it sits on the page
     card     #12466A   1.32 : 1 against the ground, against the app's 1.10
     hairline 22% white a 1px line survives a dim panel; a 3% fill difference
                        does not, and borders are what the eye finds first
     muted    #C9DCEA   7.07 on a card, against the app's 4.47

   Nothing here is darker than the app. Going darker crushes sooner at low
   brightness, which is the opposite of the fix. */

:root {
  --sea-deep: #08334F;
  --sea-mid: #0B5688;
  --sea-shallow: #0C639A;

  --bg: var(--sea-deep);
  --card: #12466A;
  --card-hi: #16507A;
  --ink: #FFFFFF;
  --muted: #C9DCEA;
  --line: rgba(255, 255, 255, 0.22);
  --line-soft: rgba(255, 255, 255, 0.12);

  --violet: #8B7BFF;
  --amber: #FFB020;
  --blue: #7DD3FC;
  --blue-dark: #06283D;
  --orange: var(--amber);
  --surface: var(--card);
  --danger: #FCA5A5;

  --radius: 16px;
  --radius-lg: 22px;
  --shadow: 0 14px 44px rgba(2, 10, 20, 0.42);

  /* The glass edge. This is the part that does the work: a bright 1px line
     along the top, plus a diagonal sheen. A dim backlight eats a 3% difference
     in fill long before it eats a 42%-white hairline — which is why the fill
     underneath these panels stays opaque and only the edge is borrowed. */
  --edge-hi: rgba(255, 255, 255, 0.42);
  --sheen: rgba(255, 255, 255, 0.16);
  --glass-fill: rgba(255, 255, 255, 0.06);
  --glass-solid: rgba(11, 51, 79, 0.86);
  --grad-to: #9FD8FF;
  --menu: #1C5C86;
  --chip-fill: rgba(12, 55, 84, 0.93);
  --bezel: linear-gradient(160deg, #2C5170, #123449);
  /* Panel glass. --panel-solid is what shows without backdrop-filter, where a
     translucent fill would be a window rather than a card. */
  --panel: rgba(255, 255, 255, 0.12);
  --panel-solid: #12466A;
}

/* Light mode keeps working, tuned to the app's pale sea so the two agree.
   Applied from two directions: the system preference when nobody has chosen,
   and data-theme when they have. The :not([data-theme="dark"]) guard is what
   lets an explicit choice win. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #E8F1F9;
    --card: #FFFFFF;
    --card-hi: #F4F9FD;
    --ink: #0B2338;
    --muted: #3D5A73;
    --line: #B9D2E5;
    --line-soft: #D6E6F2;
    --violet: #5B4BD6;
    --amber: #A65B00;
    --blue: #0A5480;
    --blue-dark: #CFE4F4;
    --danger: #B91C1C;
    --shadow: 0 14px 40px rgba(11, 35, 56, 0.13);
    /* A white top-edge on a white card is nothing. Light mode carries the
       material on its border and shadow instead. */
    --edge-hi: transparent;
    --sheen: rgba(255, 255, 255, 0.75);
    --glass-fill: rgba(255, 255, 255, 0.55);
    --glass-solid: rgba(240, 247, 252, 0.90);
    --grad-to: #2C5FBF;
    --menu: #FFFFFF;
    --chip-fill: rgba(255, 255, 255, 0.94);
    --bezel: linear-gradient(160deg, #FFFFFF, #D8E7F3);
    /* Denser than the dark side: white at 55% over a pale ground washes out
       and the black text loses the surface it stands on. */
    --panel: rgba(255, 255, 255, 0.88);
    --panel-solid: #FFFFFF;
  }
}
:root[data-theme="light"] {
  --bg: #E8F1F9;
  --card: #FFFFFF;
  --card-hi: #F4F9FD;
  --ink: #0B2338;
  --muted: #3D5A73;
  --line: #B9D2E5;
  --line-soft: #D6E6F2;
  --violet: #5B4BD6;
  --amber: #A65B00;
  --blue: #0A5480;
  --blue-dark: #CFE4F4;
  --danger: #B91C1C;
  --shadow: 0 14px 40px rgba(11, 35, 56, 0.13);
  /* A white top-edge on a white card is nothing. Light mode carries the
     material on its border and shadow instead. */
  --edge-hi: transparent;
  --sheen: rgba(255, 255, 255, 0.75);
  --glass-fill: rgba(255, 255, 255, 0.55);
  --glass-solid: rgba(240, 247, 252, 0.90);
    --grad-to: #2C5FBF;
    --menu: #FFFFFF;
    --chip-fill: rgba(255, 255, 255, 0.94);
    --bezel: linear-gradient(160deg, #FFFFFF, #D8E7F3);
    /* Denser than the dark side: white at 55% over a pale ground washes out
       and the black text loses the surface it stands on. */
    --panel: rgba(255, 255, 255, 0.88);
    --panel-solid: #FFFFFF;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  /* Noto Sans Bengali first: without it, Bangla falls back to whatever the
     device has and যুক্তাক্ষর conjuncts break. */
  font-family: "Hind Siliguri", "Noto Sans Bengali", system-ui, -apple-system, sans-serif;
  font-size: 17px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  /* clip, not hidden: `hidden` on the body makes it a scroll container, which
     would stop the sticky header sticking to the viewport. A backstop against
     any full-bleed layer measured in vw — with a scrollbar counted in, 100vw
     is a few pixels wider than the page. */
  overflow-x: clip;
}

main { max-width: 1080px; margin: 0 auto; padding: 8px 20px 64px; }

img { max-width: 100%; height: auto; }

/* ── Backdrop ────────────────────────────────────────────────────────────── */
/* Three layers under everything: a radial ground, blurred colour blobs, and a
   grain. The glass panels above have nothing to be translucent *of* without
   them — a translucent panel over a flat colour is just a tinted box.

   The blobs do not animate. Three 40vw elements at blur(130px) drifting on a
   loop is a permanent GPU cost, and the audience for this page is on cheap
   Androids. The material is in the blur; the motion was never the point. */
.bg {
  position: fixed; inset: 0; z-index: -2; overflow: hidden;
  background: radial-gradient(130% 100% at 50% -20%,
              #0E4A6E 0%, #08334F 55%, #05263B 100%);
}
.blob {
  position: absolute; border-radius: 50%;
  filter: blur(130px);
  /* Its own layer, so it is rasterised once instead of on every scroll. */
  will-change: transform; transform: translateZ(0);
}
.blob.b1 { width: 40vw; height: 40vw; background: #0C639A; opacity: .40; top: -14vw; left: -10vw; }
.blob.b2 { width: 38vw; height: 38vw; background: #5B4BD6; opacity: .22; bottom: -18vw; right: -12vw; }
.blob.b3 { width: 34vw; height: 34vw; background: #0A5480; opacity: .30; top: 42vw; left: 34vw; }

/* ── The app's blocks ────────────────────────────────────────────────────── */
/* Ported from _SeaShapesPainter: rounded squares at a slight tilt, radius 22%
   of their own size. The app paints four per screen at 5% white; this is one
   long scroll, so there are six, and they are a shade fainter — the site
   already carries a radial ground, three blobs and a grain, and four layers
   of depth is the point at which "premium" turns into "busy".

   The wrapper is taller than the viewport so the parallax has somewhere to
   drift to; .bg clips whatever leaves. */
.blocks {
  position: absolute; left: 0; right: 0; top: -30vh; bottom: -30vh;
  transform: translateY(calc(var(--sy, 0) * -0.05px));
  will-change: transform;
}
.block {
  position: absolute; display: block;
  border-radius: 22%;
  background: rgba(255, 255, 255, 0.020);
}
/* Kept out of the centre column where the screenshots and copy live. */
.k1 { left: 76vw; top: 34vh; width: 30vw; height: 30vw; transform: rotate(11deg); }
.k2 { left: 2vw;  top: 62vh; width: 22vw; height: 22vw; transform: rotate(18deg); }
.k3 { left: 68vw; top: 96vh; width: 19vw; height: 19vw; transform: rotate(7deg); }
.k4 { left: 10vw; top: 40vh; width: 13vw; height: 13vw; transform: rotate(14deg); }
.k5 { left: 82vw; top: 70vh; width: 16vw; height: 16vw; transform: rotate(-9deg); }
.k6 { left: 6vw;  top: 88vh; width: 11vw; height: 11vw; transform: rotate(-15deg); }

/* On a pale ground a white block is nothing, so light mode goes the other
   way and sits a shade darker than the sea. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .block { background: rgba(11, 35, 56, 0.045); }
}
:root[data-theme="light"] .block { background: rgba(11, 35, 56, 0.045); }

.grain {
  position: fixed; inset: 0; z-index: -1; pointer-events: none; opacity: .05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .bg {
    background: radial-gradient(130% 100% at 50% -20%, #FFFFFF 0%, #E8F1F9 55%, #D9E9F6 100%);
  }
  :root:not([data-theme="dark"]) .blob.b1 { background: #9CCBEC; opacity: .55; }
  :root:not([data-theme="dark"]) .blob.b2 { background: #B7ADF5; opacity: .40; }
  :root:not([data-theme="dark"]) .blob.b3 { background: #BFDCF2; opacity: .45; }
  :root:not([data-theme="dark"]) .grain { opacity: .03; }
}
:root[data-theme="light"] .bg {
  background: radial-gradient(130% 100% at 50% -20%, #FFFFFF 0%, #E8F1F9 55%, #D9E9F6 100%);
}
:root[data-theme="light"] .blob.b1 { background: #9CCBEC; opacity: .55; }
:root[data-theme="light"] .blob.b2 { background: #B7ADF5; opacity: .40; }
:root[data-theme="light"] .blob.b3 { background: #BFDCF2; opacity: .45; }
:root[data-theme="light"] .grain { opacity: .03; }

/* ── The glass edge ──────────────────────────────────────────────────────── */
/* Applied to every panel. The fill stays opaque — that is the contrast — and
   only the lit edge and the sheen are borrowed. */
.card, .feature, .trust div, .notice, .table-wrap, details:not(.profile) {
  position: relative;
  box-shadow: var(--shadow),
              inset 0 1px 0 var(--edge-hi),
              inset 0 0 26px rgba(255, 255, 255, 0.02);
}
/* No overflow:hidden anywhere — the header's profile menu escapes its panel,
   and clipping it would hide the whole dropdown. inherit on the radius is
   enough to keep the sheen inside the corners. */
.card::before, .feature::before, .trust div::before,
.notice::before, details:not(.profile)::before {
  content: ""; position: absolute; inset: 0;
  border-radius: inherit; pointer-events: none;
  background: linear-gradient(160deg, var(--sheen), rgba(255, 255, 255, 0) 42%);
}
/* Everything inside has to sit above the sheen. */
.card > *, .feature > *, .trust div > *, .notice > *,
details:not(.profile) > * { position: relative; }

/* A panel that lifts on hover reads as a surface rather than a printed box. */
.feature, .trust div {
  transition: transform .3s ease, border-color .3s ease;
}
.feature:hover, .trust div:hover {
  transform: translateY(-6px); border-color: var(--line);
}

/* ── Header ──────────────────────────────────────────────────────────────── */
/* A pill that floats inside the column, not a band across the window. The
   sticky offset is on the outer element so the pill keeps its 14px of air
   against the top of the viewport as the page scrolls under it. */
.topbar {
  position: sticky; top: 14px; z-index: 20;
  max-width: 1120px; margin: 14px auto 0; padding: 0 20px;
  color: var(--ink);
}
.topbar-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 10px 12px 10px 18px;
  border-radius: 18px;
  border: 1px solid var(--line);
  /* Opaque-ish by default: without backdrop-filter a 6% white fill is a
     window, and the page scrolls through the header. */
  background: var(--glass-solid);
  box-shadow: var(--shadow),
              inset 0 1px 0 var(--edge-hi),
              inset 0 0 26px rgba(255, 255, 255, 0.02);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .topbar-inner {
    background: var(--glass-fill);
    -webkit-backdrop-filter: blur(20px) saturate(130%);
    backdrop-filter: blur(20px) saturate(130%);
  }
}
.topbar a { color: var(--ink); text-decoration: none; }

/* `.topbar a` is more specific than `.button`, so without this the header's
   filled button took the header's ink colour — invisible in dark mode, where
   ink is already white, and dark-on-violet the moment the page went light.
   Ghost buttons are excluded: theirs is meant to be ink. */
.topbar .button:not(.ghost) { color: #fff; }

.brand {
  font-weight: 700; font-size: 20px;
  display: inline-flex; align-items: center; gap: 10px;
}
.brand img { width: 32px; height: 32px; display: block; }

/* The mark is a pale, glossy N drawn to sit on the dark sea. On a light
   header it disappears and only its orange tick survives, so in light mode it
   keeps a piece of that sea with it rather than being redrawn. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .brand img {
    background: var(--sea-deep);
    padding: 3px; border-radius: 9px;
  }
}
:root[data-theme="light"] .brand img {
  background: var(--sea-deep);
  padding: 3px; border-radius: 9px;
}
.topbar nav a {
  margin-left: 20px; opacity: .85; font-size: 16px;
  padding-bottom: 2px; border-bottom: 2px solid transparent;
}
.topbar nav a:hover { opacity: 1; }
.topbar nav a.on { opacity: 1; border-bottom-color: var(--amber); text-decoration: none; }

.nav-button { display: none; font-size: 22px; cursor: pointer; padding: 2px 8px; }

/* The nav collapses behind a checkbox rather than JavaScript, so it works
   before — and without — any script running. */
@media (max-width: 620px) {
  .nav-button { display: block; }
  .topbar nav { display: none; flex-basis: 100%; padding: 6px 6px 2px; }
  .nav-toggle:checked ~ nav { display: block; }
  .topbar nav a { display: block; margin: 0 0 10px; border-bottom: none; }
}

/* FR-11.1 — the disclaimer rides above every page, not only the footer.
   Someone arriving on the fee page from a shared link sees it before a number. */
/* ── The disclaimer chip ─────────────────────────────────────────────────── */
/* Was a strip across the top of the page. It is a floating notice now: out of
   the reading column, out of the profile menu's way, and closeable.
   `data-notice` is set before the first paint, so a visitor who has already
   dismissed it never sees it appear and disappear. */
.notice-chip {
  position: fixed; left: 20px; bottom: 20px; z-index: 40;
  max-width: 430px;
  display: flex; align-items: flex-start; gap: 12px;
  padding: 13px 8px 13px 16px;
  border-radius: 16px;
  border: 1px solid var(--line);
  background: var(--glass-solid);
  box-shadow: 0 18px 44px rgba(2, 10, 20, 0.45),
              inset 0 1px 0 var(--edge-hi);
  color: var(--muted); font-size: 13.5px; line-height: 1.55;
}
/* Denser than the header's glass. The header sits over the top of the page,
   where there is usually only backdrop behind it; this floats over whatever
   happens to be scrolling past, and a 6% fill over a paragraph is unreadable
   for both of them. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .notice-chip {
    background: var(--chip-fill);
    -webkit-backdrop-filter: blur(22px) saturate(140%);
    backdrop-filter: blur(22px) saturate(140%);
  }
}
.notice-chip p { margin: 0; }
.notice-dot {
  flex: none; width: 8px; height: 8px; margin-top: 7px;
  border-radius: 50%; background: var(--amber);
  box-shadow: 0 0 12px var(--amber);
}
.chip-close {
  flex: none; background: none; border: 0; cursor: pointer;
  color: var(--muted); font-size: 22px; line-height: 1;
  /* 40px so it clears a thumb; the glyph inside is small. */
  width: 40px; height: 40px; margin: -8px 0; border-radius: 10px;
  display: grid; place-items: center;
  transition: background .2s ease, color .2s ease;
}
.chip-close:hover { background: var(--card-hi); color: var(--ink); }

:root[data-notice="seen"] .notice-chip { display: none; }

/* Entrance and exit. Only under .js — without it the chip is simply present,
   which is the state a compliance notice should fail into. */
.js .notice-chip { animation: chip-in .5s cubic-bezier(.2, .7, .3, 1) .6s backwards; }
@keyframes chip-in { from { opacity: 0; transform: translateY(14px); } }
.notice-chip.gone {
  opacity: 0; transform: translateY(10px);
  transition: opacity .3s ease, transform .3s ease;
}

/* ── Type ────────────────────────────────────────────────────────────────── */
h1 {
  font-size: clamp(30px, 4.6vw, 46px);
  line-height: 1.3; margin: 8px 0 16px; font-weight: 800;
  letter-spacing: -0.01em;
}
/* Guarded, and only ever between two colours that both pass on their own: a
   browser without background-clip:text would paint `color: transparent` and
   the headline would simply not be there. */
@supports (-webkit-background-clip: text) or (background-clip: text) {
  .hero h1 {
    background: linear-gradient(115deg, var(--ink) 12%, var(--grad-to) 92%);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
}
h2 { font-size: clamp(22px, 2.6vw, 30px); margin: 0 0 10px; font-weight: 700; }
h3 { font-size: 19px; margin: 0 0 6px; font-weight: 700; }
.lede { color: var(--muted); font-size: clamp(17px, 1.8vw, 20px); }

/* A pill with a live dot rather than a line of tracked-out caps — Bangla has
   no case for uppercase to work on, and wide tracking only prises its conjunct
   clusters apart. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 14px; font-weight: 600;
  padding: 7px 16px 7px 13px; border-radius: 999px;
  background: var(--glass-fill);
  border: 1px solid var(--line);
  color: var(--muted); margin-bottom: 18px;
}
.eyebrow::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--amber);
  box-shadow: 0 0 12px var(--amber);
  animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity: .35; } }

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.cta { display: flex; flex-wrap: wrap; gap: 12px; margin: 24px 0; }
.button {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 14px 24px; border-radius: 999px;
  background: var(--violet); color: #fff; text-decoration: none;
  font-weight: 700; font-size: 17px;
  border: 1px solid transparent;
  transition: transform .12s ease, filter .12s ease;
}
.button:hover { filter: brightness(1.08); transform: translateY(-1px); }
/* The status button disables itself while it waits on the gateway. Filled and
   violet, it would otherwise look pressable throughout. */
.button:disabled { opacity: .55; cursor: default; }
.button:disabled:hover { filter: none; transform: none; }
.button.ghost {
  background: transparent; color: var(--ink); border-color: var(--line);
}
.button.ghost:hover { background: var(--card); }

/* ── Surfaces ────────────────────────────────────────────────────────────── */
.card {
  background: var(--panel-solid);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 26px;
  box-shadow: var(--shadow);
}
.card h2 { margin-top: 0; font-size: 22px; }
/* The card is a link target from /download and the nav, so it must not land
   under the sticky header. */
#register { scroll-margin-top: 90px; }

.notice {
  border: 1px solid var(--line);
  border-left: 4px solid var(--amber);
  border-radius: var(--radius);
  padding: 16px 18px; margin: 20px 0; background: var(--panel-solid);
}
.notice h2 { margin: 0 0 6px; font-size: 18px; color: var(--ink); }
.notice p { margin: 0 0 6px; }

section { padding: 44px 0; }
section + section { border-top: 1px solid var(--line-soft); }

/* ── Hero ────────────────────────────────────────────────────────────────── */
.hero {
  display: grid; gap: 32px; align-items: center;
  padding: 40px 0 48px;
  position: relative;
}
/* Two columns only when there is genuinely room. Below that the card sits
   under the headline rather than being squeezed beside it. */
@media (min-width: 900px) {
  .hero { grid-template-columns: 1.05fr 0.95fr; gap: 56px; }
}

/* ── Trust strip ─────────────────────────────────────────────────────────── */
.trust {
  display: grid; gap: 14px; padding: 0 0 8px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.trust div {
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  padding: 14px 16px; background: var(--panel-solid);
}
.trust strong { display: block; font-size: 16px; }
.trust span { font-size: 14px; color: var(--muted); }

/* ── Feature cards ───────────────────────────────────────────────────────── */
.feature-grid {
  display: grid; gap: 20px; margin-top: 28px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.feature {
  background: var(--panel-solid); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 26px 24px 28px;
  box-shadow: var(--shadow);
}
.feature img {
  width: 132px; height: 132px; object-fit: contain;
  margin: 0 0 14px; display: block;
}
.feature p { margin: 0; color: var(--muted); }

/* ── Phone frames ────────────────────────────────────────────────────────── */
/* Drawn in CSS rather than baked into the PNG: the asset stays small, the
   bezel follows the theme, and a re-shot screenshot drops straight in. */
.phone {
  width: 270px; margin: 0 auto; padding: 9px;
  border-radius: 36px;
  background: var(--bezel);
  border: 1px solid var(--line);
  box-shadow: 0 30px 70px rgba(2, 10, 20, 0.55),
              inset 0 1px 0 rgba(255, 255, 255, 0.38);
}
.phone img { display: block; width: 100%; border-radius: 28px; }
.phone.sm { width: 100%; max-width: 210px; padding: 7px; border-radius: 30px; }
.phone.sm img { border-radius: 24px; }

/* ── The three promises ──────────────────────────────────────────────────── */
.pitch-grid {
  display: grid; gap: 20px; margin-top: 28px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.pitch-card {
  position: relative;
  background: var(--panel-solid);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 26px 24px 28px;
  box-shadow: var(--shadow), inset 0 1px 0 var(--edge-hi);
  transition: transform .3s ease, border-color .3s ease;
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pitch-card {
    background: var(--panel);
    -webkit-backdrop-filter: blur(18px) saturate(125%);
    backdrop-filter: blur(18px) saturate(125%);
  }
}
.pitch-card:hover { transform: translateY(-6px); }
.pitch-card h3 { font-size: 20px; margin: 16px 0 8px; }
.pitch-card p { margin: 0; color: var(--muted); }

/* 48px, not 18. On a card this wide the old circle read as punctuation. */
.pitch-ico {
  display: grid; place-items: center;
  width: 52px; height: 52px; border-radius: 15px;
  background: var(--card-hi);
  border: 1px solid var(--line-soft);
  color: var(--ink);
}
.pitch-ico svg { width: 26px; height: 26px; }

/* The one that is the product.
   A violet edge and a slow breath on the tile — and deliberately not a scan
   sweep, because the band below already runs one and the same trick twice in
   a row reads as a template rather than an argument. */
.pitch-card.lead { border-color: var(--violet); }
.pitch-card.lead .pitch-ico {
  color: #fff;
  background: var(--violet);
  border-color: transparent;
  animation: breathe 3s ease-in-out infinite;
}
@keyframes breathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(139, 123, 255, 0.45); }
  50%      { box-shadow: 0 0 0 12px rgba(139, 123, 255, 0); }
}

/* max-width:none, or the measure rule for prose (68ch on section > p) keeps
   this flex row narrow and "centred" lands left of centre. */
.pitch-cta { justify-content: center; margin-top: 28px; max-width: none; }

/* ── The scanner band ────────────────────────────────────────────────────── */
.scanner-band {
  display: grid; gap: 34px; align-items: center; padding: 8px 0;
}
@media (min-width: 900px) {
  .scanner-band { grid-template-columns: 0.85fr 1.15fr; gap: 56px; }
}
.scan-shot .phone { position: relative; overflow: hidden; }
.scan-copy h2 { margin-bottom: 12px; }
.scan-copy > p { color: var(--muted); margin: 0 0 16px; }

/* One keyframe over the real screen. It dramatises what the app does; it does
   not fake a verdict the app has not produced. */
.scan-line {
  position: absolute; left: 9px; right: 9px; top: 0; height: 88px;
  border-radius: 28px; pointer-events: none;
  background: linear-gradient(180deg,
      rgba(125, 211, 252, 0) 0%,
      rgba(125, 211, 252, 0.20) 45%,
      rgba(125, 211, 252, 0.55) 50%,
      rgba(125, 211, 252, 0.20) 55%,
      rgba(125, 211, 252, 0) 100%);
  animation: scan 3.2s cubic-bezier(.5, 0, .5, 1) infinite;
}
@keyframes scan {
  0%        { transform: translateY(-88px); opacity: 0; }
  12%, 88%  { opacity: 1; }
  100%      { transform: translateY(904px); opacity: 0; }
}
/* A sweep that never stops is the one animation on this page a reader could
   reasonably ask to be rid of. */
@media (prefers-reduced-motion: reduce) { .scan-line { display: none; } }

/* ── Showcase rows ───────────────────────────────────────────────────────── */
/* The screenshot is the argument; the copy beside it says what to look at. */
.showcase {
  display: grid; gap: 34px; align-items: center; padding: 40px 0;
}
.showcase + .showcase { border-top: 1px solid var(--line-soft); }
@media (min-width: 900px) {
  .showcase { grid-template-columns: 1fr 1fr; gap: 64px; }
  /* Alternating sides, so three rows do not read as one long column. */
  .showcase.flip .show-shot { order: -1; }
}
.show-ico { width: 64px; height: 64px; object-fit: contain; margin-bottom: 10px; }
.show-copy h3 { font-size: 24px; margin-bottom: 10px; }
.show-copy > p { color: var(--muted); margin: 0 0 16px; }
.show-copy .check-list { margin: 0; }
.show-copy .check-list li { font-size: 15.5px; }

/* ── Gallery ─────────────────────────────────────────────────────────────── */
/* Five across at full width — four plus an orphan on its own row reads as a
   layout that ran out rather than a set. */
.gallery {
  display: grid; gap: 20px; margin-top: 30px;
  grid-template-columns: repeat(auto-fit, minmax(185px, 1fr));
}
.gallery figure { margin: 0; }
.gallery figcaption {
  text-align: center; margin-top: 14px;
  font-size: 14px; color: var(--muted);
}

@media (max-width: 620px) {
  .phone { width: 240px; }
  .phone.sm { width: 190px; }
  .showcase { padding: 28px 0; gap: 26px; }
}

/* ── Panel glass ─────────────────────────────────────────────────────────── */
/* Real translucency, so the blobs and the blocks drift behind the cards
   rather than stopping at their edges. Only where there is a backdrop-filter
   to blur with: without one a 12% fill is a window and the page scrolls
   through the card, so those browsers keep the opaque fill above.

   .table-wrap is deliberately not in here. A long column of numbers over
   moving shapes is harder to read, and the fee page is the one people print
   and carry into an office. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card, .notice, details:not(.profile) {
    background: var(--panel);
    -webkit-backdrop-filter: blur(18px) saturate(125%);
    backdrop-filter: blur(18px) saturate(125%);
  }
  /* The small repeated chips take the fill without the blur. At this size the
     refraction is imperceptible against soft blobs, and it halves the number
     of blurred surfaces the cheapest phones have to composite on scroll. */
  .trust div, .feature { background: var(--panel); }
}

/* ── Steps ───────────────────────────────────────────────────────────────── */
.steps { counter-reset: step; list-style: none; padding: 0; margin: 24px 0 0; }
.steps li {
  counter-increment: step; position: relative;
  padding: 16px 0 16px 56px; margin: 0;
  border-bottom: 1px solid var(--line-soft);
}
.steps li:last-child { border-bottom: none; }
.steps li::before {
  content: counter(step);
  position: absolute; left: 0; top: 14px;
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--violet); color: #fff; font-weight: 700;
}

/* ── Roadmap ─────────────────────────────────────────────────────────────── */
/* Mirrors the app's service strip. Deliberately a plain list rather than five
   more cards: the page has already shown what is built, and a roadmap that
   looks as finished as the product oversells it. */
.roadmap { list-style: none; padding: 0; margin: 26px 0 0; max-width: 620px; }
.roadmap li {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 15px 0;
  border-bottom: 1px solid var(--line-soft);
}
.roadmap li:last-child { border-bottom: none; }
.roadmap strong { font-weight: 600; }
.roadmap .tag {
  flex: none; font-size: 13px; font-weight: 600;
  padding: 4px 12px; border-radius: 999px;
  color: var(--muted); border: 1px solid var(--line-soft);
}
.roadmap .tag.now {
  color: #fff; background: var(--violet); border-color: transparent;
}

/* ── Tables ──────────────────────────────────────────────────────────────── */
/* The scroll is on the wrapper. Putting `display: block; overflow-x: auto` on
   the table itself does make it scroll, but it also stops the table filling
   its column — it shrinks to its content and sits narrow in a wide page. */
.table-wrap {
  overflow-x: auto;
  margin: 24px 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--card);
  box-shadow: var(--shadow);
}
.fees { width: 100%; border-collapse: collapse; }
.fees th, .fees td {
  text-align: right; padding: 16px 22px;
  border-bottom: 1px solid var(--line-soft); vertical-align: top;
}
.fees tbody tr:last-child th, .fees tbody tr:last-child td { border-bottom: none; }
.fees th:first-child, .fees td:first-child { text-align: left; }
.fees thead th {
  color: var(--muted); font-weight: 600; font-size: 15px;
  background: var(--card-hi); border-bottom-color: var(--line);
}
.fees tbody tr:hover { background: var(--card-hi); }
.fees .num {
  white-space: nowrap; font-variant-numeric: tabular-nums;
  font-weight: 700; font-size: 19px;
}
.fees td .note { margin-top: 4px; }

/* The gazette caveat repeats on most rows. In full amber, twelve of them read
   as twelve warnings rather than one footnote; the marker carries the flag and
   the text goes quiet. */
.fees .caveat {
  color: var(--muted); position: relative; padding-left: 18px; margin-top: 6px;
}
.fees .caveat::before {
  content: "*"; position: absolute; left: 4px; top: 1px;
  color: var(--amber); font-weight: 700;
}

/* The provenance line under the table — the reason to trust the numbers, so it
   is set as a footnote to them rather than as loose page text. */
.verified, .source {
  font-size: 14px; color: var(--muted); max-width: 70ch;
}
.verified { margin: 0 0 4px; }

/* ── Small print ─────────────────────────────────────────────────────────── */
.note, .caveat { display: block; font-size: 14px; color: var(--muted); margin-top: 6px; }
.caveat { color: var(--amber); }

.features { padding-left: 20px; }
.features li { margin-bottom: 8px; }

/* A neutral marker, not a tick. The same class carries the "what we never
   collect" list on the privacy page, and a tick beside "জাতীয় পরিচয়পত্রের
   নম্বর" reads as a promise to collect it. */
.check-list { list-style: none; padding-left: 0; }
.check-list li { position: relative; padding-left: 24px; margin-bottom: 10px; }
.check-list li::before {
  content: ""; position: absolute; left: 4px; top: .72em;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--amber);
}

/* ── Subscribe form ──────────────────────────────────────────────────────── */
.subscribe { display: flex; flex-direction: column; gap: 6px; margin: 20px 0 0; }
.subscribe label { font-size: 14px; color: var(--muted); }
.subscribe input {
  padding: 14px 16px; font-size: 18px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--card-hi); color: var(--ink);
  font-family: inherit;
}
.subscribe input::placeholder { color: var(--muted); opacity: .7; }
.subscribe input:focus {
  outline: none; border-color: var(--violet);
  box-shadow: 0 0 0 3px rgba(139, 123, 255, 0.45);
}
.subscribe input:read-only { background: var(--bg); color: var(--muted); }
.subscribe button {
  margin-top: 12px; border: none; cursor: pointer;
  font-family: inherit; font-size: 17px; justify-content: center;
}
.subscribe button:disabled { opacity: .55; cursor: default; }
.form-error { color: var(--danger); font-size: 15px; }

.scan-link code {
  display: block; word-break: break-all; font-size: 13px;
  background: var(--card-hi); padding: 12px 14px; border-radius: 10px;
  border: 1px solid var(--line-soft);
}

/* ── FAQ ─────────────────────────────────────────────────────────────────── */
/* :not(.profile) throughout — the header's profile menu is a <details> too,
   and it is a dropdown, not a card with a +/− on it. */
details:not(.profile) {
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  padding: 14px 18px; margin-bottom: 10px; background: var(--panel-solid);
}
details:not(.profile)[open] { border-color: var(--line); }
details:not(.profile) summary {
  cursor: pointer; font-weight: 600; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
details summary::-webkit-details-marker { display: none; }
details:not(.profile) summary::after {
  content: "+"; color: var(--amber); font-weight: 700; font-size: 20px;
}
details:not(.profile)[open] summary::after { content: "−"; }
details:not(.profile) p { margin: 10px 0 0; color: var(--muted); }
details:not(.profile) a { color: var(--blue); }

/* ── Footer ──────────────────────────────────────────────────────────────── */
.footer {
  border-top: 1px solid var(--line-soft);
  padding: 32px 20px 48px; max-width: 1080px; margin: 0 auto;
}
/* Brand and what the thing is, then where to go — the disclaimer and the
   copyright sit under both as the record rather than as the content. */
.footer-top { display: grid; gap: 30px; padding-bottom: 28px; }
@media (min-width: 700px) {
  .footer-top { grid-template-columns: 1.5fr 1fr; gap: 56px; }
}
.footer-brand .brand {
  color: var(--ink); text-decoration: none;
  font-size: 20px; margin-bottom: 12px;
}
.footer-brand p {
  margin: 0; color: var(--muted);
  font-size: 14.5px; line-height: 1.7; max-width: 52ch;
}
/* Two columns of three, filled top-to-bottom rather than across, so each
   column reads as a list instead of a table. */
.footer-links {
  display: grid; gap: 12px 20px;
  grid-auto-flow: column;
  grid-template-rows: repeat(3, auto);
  justify-content: start;
}
/* Underlined, and at full ink rather than muted. They were styled as quiet
   text with the underline removed, which is the one thing that tells anybody
   a word can be pressed — a footer full of unmarked links reads as a caption. */
.footer-links a {
  color: var(--ink); font-size: 14.5px;
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  width: fit-content;
}
.footer-links a:hover { text-decoration-color: currentColor; }

.disclaimer {
  font-size: 14px; color: var(--muted);
  padding-top: 22px; border-top: 1px solid var(--line-soft);
}

/* Set below the links and quieter than them — it is a notice, not navigation. */
.copyright {
  font-size: 13px; color: var(--muted);
  margin: 16px 0 0; padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}
.copyright a { color: var(--muted); }
.copyright a:hover { color: var(--blue); }

/* ── Long-form pages ─────────────────────────────────────────────────────── */
main h2 { scroll-margin-top: 90px; }
main p a, main li a { color: var(--blue); }

/* A measure, so the privacy and terms pages are readable.
   At 1080px a Bangla line runs past 120 characters; the eye loses the start of
   the next line and people stop reading. Only prose is constrained — grids,
   the fee table and the hero lay themselves out. */
main > p, main > ul, main > ol, main > h2, main > h3, main > .notice,
section > p, section > ul, section > ol {
  max-width: 68ch;
}
main > h2 { margin-top: 40px; }
main > h1 + p.lede { margin-top: 0; }

/* Centred sections keep their measure but stay centred. */
.final-cta h2, .final-cta p { margin-inline: auto; }

/* A card standing on its own — the account page's four — rather than one in a
   grid. A 1080px-wide card with two lines in it does not read as a card. */
main > .card { max-width: 680px; }

/* Someone who has turned motion down does not want a page that lifts and
   fades under their cursor. */
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  .button:hover { transform: none; }
}

/* ── Header actions ──────────────────────────────────────────────────────── */
.nav-actions { display: flex; align-items: center; gap: 10px; }

.icon-button {
  background: none; border: 1px solid var(--line-soft); color: var(--ink);
  cursor: pointer; font-size: 18px; line-height: 1;
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  transition: background .12s ease, border-color .12s ease;
}
.icon-button:hover { background: var(--card); border-color: var(--line); }

.button.small { padding: 10px 18px; font-size: 16px; }

.link-button {
  background: none; border: none; cursor: pointer; padding: 6px 8px;
  font: inherit; font-size: 15px; color: var(--ink);
  border-radius: 8px;
}
.link-button:hover { background: var(--card); }
.link-button.danger, a.danger, .button.danger { color: var(--danger); }
.button.ghost.danger { border-color: var(--danger); }

/* ── Profile menu ────────────────────────────────────────────────────────── */
/* <details> rather than a JS dropdown: it opens with a keyboard, closes with
   Escape, and works if the script fails. */
.profile { position: relative; }
.profile summary {
  list-style: none; cursor: pointer; color: var(--ink);
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--line-soft);
}
.profile summary::-webkit-details-marker { display: none; }
.profile summary:hover { background: var(--card); border-color: var(--line); }
.profile-name {
  max-width: 9rem; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 15px;
}

/* The menu is not a <details> FAQ card, so it opts out of that block's frame. */
.profile[open] > summary { background: var(--card); border-color: var(--line); }
/* A menu has to detach from whatever it lands on. Over the dark backdrop a
   card-coloured panel sits only a few percent away from it, so this one is
   lifted a step and given the same lit edge as the panels, plus a shadow deep
   enough to read as floating rather than as a patch of page. */
.profile ul {
  position: absolute; right: 0; top: calc(100% + 10px);
  min-width: 210px; margin: 0; padding: 6px;
  list-style: none; background: var(--menu); color: var(--ink);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 20px 50px rgba(2, 10, 20, 0.55),
              inset 0 1px 0 var(--edge-hi);
  z-index: 30;
}
.profile ul li { margin: 0; }
.profile ul a, .profile ul .link-button {
  display: block; width: 100%; text-align: right;
  padding: 10px 12px; border-radius: 10px;
  color: var(--ink); text-decoration: none; font-size: 16px;
}
.profile ul a:hover, .profile ul .link-button:hover { background: var(--card-hi); }
.profile ul .danger { color: var(--danger); }

/* Unsubscribe sits in the header when there is room and inside the profile
   menu when there is not — present either way, duplicated neither way. */
.narrow-only { display: none; }
@media (max-width: 900px) {
  .wide-only { display: none; }
  .narrow-only { display: block; }
}

/* ── Charging disclosure ─────────────────────────────────────────────────── */
/* Not small print. Someone about to be billed daily should not have to look
   for the price. */
.charge {
  background: var(--card-hi);
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--amber);
  padding: 12px 14px;
  margin: 16px 0 0;
  font-size: 15px;
  border-radius: 0 12px 12px 0;
}

/* ── Account ─────────────────────────────────────────────────────────────── */
.card + .card { margin-top: 18px; }
.profile-card { display: flex; align-items: center; gap: 16px; }
.avatar {
  font-size: 28px; width: 60px; height: 60px; flex: none;
  border-radius: 50%; display: grid; place-items: center;
  background: var(--card-hi); border: 1px solid var(--line);
}
.card h3 { font-size: 17px; margin: 20px 0 4px; }

.badge {
  display: inline-block; padding: 5px 14px; border-radius: 999px;
  background: var(--card-hi); color: var(--ink); font-size: 15px;
  border: 1px solid var(--line); font-weight: 600;
}
.badge.ok   { background: #14532D; color: #BBF7D0; border-color: #2F7D44; }
.badge.warn { background: #78350F; color: #FDE68A; border-color: #A16207; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .badge.ok   { background: #DCFCE7; color: #14532D; border-color: #86EFAC; }
  :root:not([data-theme="dark"]) .badge.warn { background: #FEF3C7; color: #78350F; border-color: #FCD34D; }
}
:root[data-theme="light"] .badge.ok   { background: #DCFCE7; color: #14532D; border-color: #86EFAC; }
:root[data-theme="light"] .badge.warn { background: #FEF3C7; color: #78350F; border-color: #FCD34D; }

/* ── Final call to action ────────────────────────────────────────────────── */
.final-cta { text-align: center; }
.final-cta .cta { justify-content: center; }
.final-cta .charge { text-align: right; }

/* ── Focus, for keyboard and screen-reader users ─────────────────────────── */
a:focus-visible,
button:focus-visible,
input:focus-visible,
summary:focus-visible,
.nav-button:focus-visible {
  outline: 3px solid var(--amber);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Wrap long addresses and links rather than pushing the page sideways. */
main a { overflow-wrap: anywhere; }

/* ── Print: the fee table is the thing people take to an office ──────────── */
@media print {
  .topbar, .notice-chip, .cta, .nav-button, .subscribe,
  .profile, .nav-actions, .final-cta, .hero::before { display: none; }
  body { font-size: 12pt; color: #000; background: #fff; }
  /* Anything the reveal has not scrolled to yet is still at opacity 0, and a
     printer does not scroll. The fee table is the page people carry into an
     office — printing it blank would be the worst possible failure here. */
  .reveal { opacity: 1 !important; transform: none !important; }
  .bg, .grain { display: none !important; }
  main { max-width: none; }
  .card, .feature, .trust div, details { border-color: #999; box-shadow: none; background: #fff; }
  .fees th, .fees td { border-bottom: 1px solid #999; }
  a[href]::after { content: ""; }
}

/* ── Motion ──────────────────────────────────────────────────────────────── */
/* Every rule here is gated on .js, and `.reveal` is added by script rather
   than written into the markup. That is deliberate: a page whose JavaScript
   fails, or a reader who has asked for reduced motion, must get content that
   is simply visible — not content stuck at opacity 0 waiting for a transition
   the reduced-motion rule below has already disabled with !important. */
.reveal {
  opacity: 0; transform: translateY(12px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.2, .7, .3, 1);
}
.reveal.in { opacity: 1; transform: none; }

/* The hero does not wait to be scrolled to — it is already on screen, so it
   arrives on load instead, one element at a time. */
.js .hero-copy > *,
.js .hero > .card {
  animation: rise .6s cubic-bezier(.2, .7, .3, 1) backwards;
}
.js .hero-copy > *:nth-child(1) { animation-delay: .05s; }
.js .hero-copy > *:nth-child(2) { animation-delay: .12s; }
.js .hero-copy > *:nth-child(3) { animation-delay: .19s; }
.js .hero-copy > *:nth-child(4) { animation-delay: .26s; }
.js .hero-copy > *:nth-child(5) { animation-delay: .33s; }
.js .hero > .card { animation-delay: .22s; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }

/* The header tightens once the page has moved under it. */
.topbar-inner {
  transition: padding .25s ease, box-shadow .25s ease, border-radius .25s ease;
}
:root[data-scrolled] .topbar-inner {
  padding-top: 6px; padding-bottom: 6px; border-radius: 15px;
  box-shadow: 0 18px 50px rgba(2, 10, 20, 0.52),
              inset 0 1px 0 var(--edge-hi);
}

/* ── Narrow screens ──────────────────────────────────────────────────────── */
@media (max-width: 620px) {
  main { padding: 8px 16px 56px; }
  .topbar { padding: 0 14px; margin-top: 10px; }
  .topbar-inner { padding: 8px 8px 8px 14px; border-radius: 16px; }
  .brand { font-size: 18px; }
  .brand img { width: 28px; height: 28px; }
  .card, .feature { padding: 20px 18px; }
  .hero { padding: 26px 0 34px; }
  section { padding: 34px 0; }
  .steps li { padding: 14px 0 14px 48px; }
  .fees th, .fees td { padding: 14px 16px; }

  /* Full width along the bottom, and clear of the home indicator. */
  .notice-chip {
    left: 12px; right: 12px; bottom: 12px;
    max-width: none; padding: 12px 6px 12px 14px;
    font-size: 13px;
  }
}

/* The header CTA is the first thing to go: at this width it is competing with
   the brand for room, and the subscribe form is two screens' worth away at
   most — the hero carries it. Signed-in headers show the profile menu here
   instead, which stays. */
@media (max-width: 430px) {
  .nav-actions > .button.small { display: none; }
  h1 { font-size: clamp(26px, 7.6vw, 34px); }
  .eyebrow { font-size: 13px; padding: 6px 14px 6px 11px; }
}

/* A phone on its side has about 350px of height. A notice pinned to the
   bottom takes a third of that, so it gives back its padding and its dot. */
@media (max-height: 520px) and (orientation: landscape) {
  .notice-chip { padding: 8px 4px 8px 12px; font-size: 12.5px; }
  .notice-dot { display: none; }
}

/* Coarse pointers get 44px of target whatever the visual size. */
@media (pointer: coarse) {
  .icon-button { width: 44px; height: 44px; }
  .chip-close { width: 44px; height: 44px; }
  .nav-button { padding: 8px 12px; }
}
