/* =============================================================================
   SELF-HOSTED FONTS (DP's call 2026-08-16). These used to come from Google.

   WHY THEY MOVED. PageSpeed Insights measured the homepage at LCP 5.6s with
   about 1,120ms attributed to render-blocking requests. The chain was: the
   phone fetches the page, finds a stylesheet link to fonts.googleapis.com,
   resolves that host, does a TLS handshake, downloads a CSS file, and only THEN
   learns that the actual font files live on a SECOND host, fonts.gstatic.com,
   which needs its own lookup and handshake. Two external round trips stood in
   front of the headline rendering. Now the files sit on this origin, already
   warm from the HTML request, and the <link rel="preload"> in each head starts
   the two hero faces before the stylesheet has even finished parsing.

   WHAT WAS DOWNLOADED AND WHY THESE RANGES. Google's own css2 output was used,
   so these are byte-for-byte the same files it was serving. Plus Jakarta Sans
   is the variable font across 200-800 in both roman and italic (the italic is
   NOT optional: every h1 on this site gradient-clips an <em>). JetBrains Mono is
   variable 400-700, which costs exactly the same as 500-700 did and covers the
   funnel pages too. Caveat ships as two static weights rather than a variable
   file because the variable version costs 23KB more than the 500 and 600 that
   are actually used, and a page only downloads the weight it references.

   ONLY latin AND latin-ext ARE HOSTED. Google was also serving Cyrillic, Greek
   and Vietnamese, which this site will never render. Keeping latin-ext is free:
   unicode-range means the browser downloads a file only when a character in
   that range actually appears on the page.

   font-display:swap matches the previous behaviour exactly, so text is never
   invisible while a face loads. To go back to Google Fonts, delete this block
   and restore the stylesheet link plus the two preconnects in the page heads.
   ============================================================================= */

@font-face{
  font-family:'Plus Jakarta Sans';
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url('fonts/pjs-normal-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Plus Jakarta Sans';
  font-style:italic;
  font-weight:200 800;
  font-display:swap;
  src:url('fonts/pjs-italic-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'JetBrains Mono';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('fonts/jbm-normal-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Caveat';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('fonts/caveat500-normal-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Caveat';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('fonts/caveat600-normal-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Plus Jakarta Sans';
  font-style:italic;
  font-weight:200 800;
  font-display:swap;
  src:url('fonts/pjs-italic-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Plus Jakarta Sans';
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url('fonts/pjs-normal-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'JetBrains Mono';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('fonts/jbm-normal-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Caveat';
  font-style:normal;
  font-weight:500;
  font-display:swap;
  src:url('fonts/caveat500-normal-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Caveat';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('fonts/caveat600-normal-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   Digital Pratik public site design system.

   The card language is the proven DBC v5 / SattvaRig system, ported intact
   (opaque cards built from three cheap static layers, a lit hairline, a plate
   ring, a dot-matrix canvas, one filled card per section). Only the brand
   tokens and the type scale changed. Do not restructure the components.

   BRAND: blue (ported from dubai-dbc-v7 on DP's instruction, 2026-07-29,
   replacing Gold-Noir). Near-black paper + electric blue #5E92E8 on dark (the default),
   white paper + black ink on light, with the SAME yellow filled card in both
   so the brand signature survives the theme flip.

   THEME RULE (standing order 2026-07-26): dark AND light, always. Dark is the
   default. Light genuinely adjusts, it is not an inversion. Yellow is
   unreadable as TEXT on white, so in light mode accent TEXT drops to black and
   yellow stays a fill and a highlight only.

   TYPE (standing order 2026-07-26): Plus Jakarta Sans everywhere, JetBrains
   Mono for numbers and small caps labels, Caveat for handwritten winks. Base
   type is lifted to a comfortable reading size, this is a blog and people
   read it for four minutes at a time.

   PHONE FIRST. Effectively all traffic is on phones. Every rule here is
   written to be right at 375px before it is right on a desktop. The phone-only
   overrides live in ONE block at the very bottom, headed PHONE EXPERIENCE, so
   they are easy to find and tune.

   Smoothness rule: animate transform and opacity only. Respect reduced motion.
   ========================================================================== */

:root{
  /* BLUE THEME, ported from dubai-dbc-v7 on DP's instruction 2026-07-29.
     This replaced Gold-Noir. The whole palette lives in these two blocks, so
     reverting is a matter of putting the old blocks back, not a rewrite.
     Dark is still THE DEFAULT here (DBC runs light by default; this site does
     not, and that difference is deliberate). */
  --bg-0:#070707;
  --bg-1:#0D0D0D;
  --paper:#161616;
  /* cards are OPAQUE. Translucent glass over a gradient hazes everything. */
  --glass:#161616;
  --glass-hi:#1D1D1D;
  --card-grad:linear-gradient(168deg,#1A1A1A 0%,#141414 100%);
  --card-edge:rgba(255,255,255,.08);      /* the lit hairline on the top edge */
  --plate:rgba(94,146,232,.05);           /* the faint plate stacked behind a card */
  --dots:rgba(255,255,255,.07);           /* canvas dot matrix */
  --bar:rgba(7,7,7,.84);                  /* the sticky top bar, the one translucent surface */
  --line:rgba(255,255,255,.11);
  --line-strong:rgba(94,146,232,.32);
  --line-soft:rgba(255,255,255,.06);
  /* ink */
  --text-1:#F8F8F8;
  --text-2:#A5ACB7;
  /* --text-3 carries dates, read times, captions and the footer. It was raised
     off the DBC value to clear AA against the CARD colour, which is the paler
     surface and therefore the worse case. Do not drop it back. */
  --text-3:#8A8F98;
  /* ONE blue family. On dark the accent runs full blue with WHITE ink on
     buttons, which is the flip from Gold-Noir, where the ink was black. */
  --accent:#5E92E8;
  --accent-ink:#FFFFFF;   /* ink that sits ON the accent (buttons) */
  --accent-2:#8FB3EE;
  --accent-deep:#2E6BD3;
  --accent-glow:rgba(46,107,211,.4);
  /* THE BUTTON SURFACE IS NOT --accent, and that split is load bearing.
     --accent #5E92E8 is tuned to be read as LINK TEXT against near-black, where
     it measures about 7:1. Used as a button fill under white lettering it
     measures 3.11:1, which is below the AA minimum, and the sweep caught it on
     every primary button on every page. The deeper blue under white ink
     measures 5.04:1 and is identical in both themes, exactly like the filled
     card. */
  --btn-bg:#2E6BD3;
  --btn-ink:#FFFFFF;
  --accent-soft:rgba(94,146,232,.13);
  --success:#2FBF71;
  --success-soft:rgba(47,191,113,.1);
  --warn:#E3A008;
  --warn-soft:rgba(227,160,8,.12);
  --danger:#F2555C;
  /* the secondary voice: a lighter steel blue of the same family */
  --gold:#8FB3EE;
  --gold-soft:rgba(143,179,238,.1);
  --gold-line:rgba(143,179,238,.38);
  --field-bg:rgba(255,255,255,.05);
  /* the filled card: ONE per section. Deep navy with WHITE ink. Under
     Gold-Noir this was a yellow panel with black ink; the ink flipped with the
     panel and every rule that assumed dark ink on it had to follow. */
  --fill:linear-gradient(158deg,#1E4A96 0%,#133875 52%,#0B2450 100%);
  --fill-glow:0 34px 76px -34px rgba(19,56,117,.7);
  --fill-ink:#FFFFFF;
  --fill-muted:rgba(226,240,255,.78);
  --fill-line:rgba(255,255,255,.18);
  --grad:linear-gradient(100deg,#5E92E8,#8FB3EE);
  /* motion */
  --t-fast:170ms;
  --t-med:340ms;
  --t-slow:680ms;
  --ease:cubic-bezier(0.16,1,0.3,1);
  --radius:20px;
  --radius-sm:14px;
  --shadow:0 22px 50px -20px rgba(0,0,0,.65);
  --shadow-soft:0 14px 34px -18px rgba(0,0,0,.72);
  --shadow-lg:0 34px 74px -26px rgba(0,0,0,.85);
}
[data-theme="light"]{
  /* White air, near-black ink, one electric blue. Unlike the yellow it
     replaced, this blue IS readable as text on white, so --accent stays blue
     here instead of collapsing to black the way Gold-Noir had to. */
  --bg-0:#FFFFFF;
  --bg-1:#F5F5F8;
  --paper:#FFFFFF;
  --glass:#FFFFFF;
  --glass-hi:#F5F7FB;
  --card-grad:linear-gradient(168deg,#FFFFFF 0%,#FFFFFF 100%);
  /* a white highlight is invisible on a white card, so the lit edge becomes a
     faint steel hairline. Same job: it crisps the top of the card. */
  --card-edge:rgba(39,67,103,.14);
  --plate:rgba(39,67,103,.04);
  --dots:rgba(39,67,103,.1);
  --bar:rgba(255,255,255,.88);
  --line:rgba(28,36,49,.12);
  --line-strong:rgba(28,36,49,.26);
  --line-soft:rgba(28,36,49,.07);
  --text-1:#1C1C1C;
  --text-2:#55606E;
  /* raised off the DBC #8B94A1 for the same AA reason as the dark block */
  --text-3:#6E7784;
  --accent:#2E6BD3;
  --accent-ink:#FFFFFF;
  --accent-2:#6FA0EA;
  --accent-deep:#1C4FA8;
  --accent-glow:rgba(46,107,211,.3);
  --btn-bg:#2E6BD3;
  --btn-ink:#FFFFFF;
  --accent-soft:rgba(46,107,211,.08);
  --success:#12A150;
  --success-soft:rgba(18,161,80,.08);
  --warn:#D98A00;
  --warn-soft:rgba(217,138,0,.1);
  --danger:#E5484D;
  --gold:#3D5E93;
  --gold-soft:rgba(61,94,147,.08);
  --gold-line:rgba(61,94,147,.3);
  --field-bg:#FFFFFF;
  /* the filled card stays IDENTICAL in both themes, which is the one rule
     carried over from Gold-Noir unchanged. Only the colour of the panel
     changed, not the principle. */
  --fill:linear-gradient(158deg,#1E4A96 0%,#133875 52%,#0B2450 100%);
  --fill-glow:0 30px 66px -30px rgba(19,56,117,.5);
  --fill-ink:#FFFFFF;
  --fill-muted:rgba(230,242,255,.85);
  --fill-line:rgba(255,255,255,.22);
  /* THE LIGHT GRADIENT IS TIGHTER THAN DBC'S ON PURPOSE. Headings use
     background-clip:text, so the GRADIENT IS THE INK and its palest stop is
     what a reader actually has to read. DBC's #6FA0EA measures 2.66:1 on white,
     under the 3:1 large-text minimum, and the sweep flagged every gradient
     heading on every light page. #4E86DB measures 3.65:1 and still reads as a
     blue gradient. */
  --grad:linear-gradient(100deg,#2E6BD3,#4E86DB);
  --shadow:0 24px 56px -22px rgba(39,67,103,.3);
  --shadow-soft:0 14px 36px -20px rgba(39,67,103,.24);
  --shadow-lg:0 32px 70px -26px rgba(39,67,103,.36);
}

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  background:var(--bg-0);
  color:var(--text-1);
  font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;
  font-size:18.4px;
  font-feature-settings:'tnum';
  line-height:1.6;
  letter-spacing:-.004em;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
  min-height:100vh;
}
img,svg{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer}
::selection{background:var(--accent);color:var(--accent-ink)}

/* ---------- the card recipe ----------
   Three cheap static layers, no glass blur:
   1. a soft 168deg gradient fill
   2. a 1px lit hairline across the top edge, inset from both sides
   3. a faint plate ring stacked behind the card
   Everything that is a card in this stylesheet uses .surface-card. */
.surface-card,
.gcard,.stat,.answer-card,.table-wrap,.faq,.form-card,.info-card,.quote,
.est-card,.band,.calc-shell,.step,.tnode .t-card,.gpt-side,.gpt-main{
  background:var(--card-grad);
  border:1px solid var(--line);
  border-radius:var(--radius);
  box-shadow:0 0 0 6px var(--plate),var(--shadow-soft);
  position:relative;
}
.surface-card::before,
.gcard::before,.stat::before,.answer-card::before,.table-wrap::before,.faq::before,
.form-card::before,.info-card::before,.quote::before,.est-card::before,.band::before,
.calc-shell::before,.step::before,.tnode .t-card::before,.gpt-side::before,.gpt-main::before{
  content:"";position:absolute;top:0;left:22px;right:22px;height:1px;
  background:linear-gradient(90deg,transparent,var(--card-edge),transparent);
  pointer-events:none;z-index:2;
}
/* nested tiles sit inside a section, so they skip the plate ring: stacking
   plates everywhere turns a grid into mush */
.step,.tnode .t-card,.checklist li,.opt,.answer-grid .ans,.result-rows,.gpt-side{
  box-shadow:var(--shadow-soft);
  border-radius:var(--radius-sm);
}

/* THE FILLED CARD. One per section. A solid blue panel carrying that
   section's single most important message. */
.fill-card{
  background:var(--fill);
  border-color:transparent;
  color:var(--fill-ink);
  box-shadow:0 0 0 6px var(--plate),var(--fill-glow);
  overflow:hidden;
}
/* the inner light: a soft top-left highlight plus the same dot matrix as the
   canvas, so it reads as a lit panel and not a flat blue box */
.fill-card::before{
  content:"";position:absolute;inset:0;top:0;left:0;right:0;height:auto;
  background:
    radial-gradient(ellipse 96% 58% at 50% -16%,rgba(255,255,255,.16),transparent 62%),
    radial-gradient(circle,rgba(255,255,255,.10) 1px,transparent 1px);
  background-size:auto,22px 22px;
  opacity:.9;pointer-events:none;
}
.fill-card>*{position:relative;z-index:1}
.fill-card h2,.fill-card h3,.fill-card strong,.fill-card b{color:var(--fill-ink)}
.fill-card p,.fill-card small{color:var(--fill-muted)}
.fill-card .sec-kicker{color:var(--fill-muted)}
.fill-card .sec-kicker::before{background:var(--fill-muted)}
.fill-card h2 em,.fill-card h1 em{background:none;-webkit-text-fill-color:var(--fill-muted);color:var(--fill-muted)}
/* a button on a blue card flips to white, a blue button on blue disappears */
.fill-card .btn{background:rgba(255,255,255,.12);border-color:var(--fill-line);color:var(--fill-ink)}
.fill-card .btn:hover{background:rgba(255,255,255,.2);border-color:rgba(255,255,255,.34);color:var(--fill-ink)}
.fill-card .btn.primary,.fill-card .btn.primary:hover,
.fill-card .btn.gold,.fill-card .btn.gold:hover,
.fill-card .btn-primary,.fill-card .btn-primary:hover{
  background:#FFFFFF;color:#133875;border-color:transparent;
  box-shadow:0 12px 30px -14px rgba(0,0,0,.5);
}

/* ---------- ambient field ----------
   DP, 2026-07-26: ALL the background gradients are gone. The old field had two
   drifting orbs, corner radials and a vertical bg-1 to bg-0 wash, and the wash
   read as a dirty grey fade across the top and bottom of every page, worst in
   light mode where it went beige over the text. Flat paper now. The only thing
   left is the faint dot matrix, which is texture rather than a gradient.
   Do not reintroduce a background gradient here. */
.ambient{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  background:var(--bg-0);
}
[data-theme="light"] .ambient{background:var(--bg-0)}
/* the orbs are retired. The markup still ships the two divs so no page needs
   editing, they simply render nothing. */
.ambient .orb{display:none}
.ambient .grid{position:absolute;inset:0;
  background-image:radial-gradient(var(--dots) 1px,transparent 1px);
  background-size:26px 26px;opacity:.55;
  mask-image:radial-gradient(ellipse 95% 80% at 50% 0%,black 10%,transparent 80%);
  -webkit-mask-image:radial-gradient(ellipse 95% 80% at 50% 0%,black 10%,transparent 80%)}

/* ---------- layout ---------- */
.wrap{width:min(1180px,calc(100% - 32px));margin:0 auto}
main{position:relative;z-index:1}
section{padding:56px 0;position:relative}
@media (min-width:721px){
  .wrap{width:min(1180px,calc(100% - 48px))}
  section{padding:64px 0}
}

/* ---------- top command bar ---------- */
.topbar{position:sticky;top:0;z-index:60;background:var(--bar);
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  border-bottom:1px solid var(--line)}
.topbar-inner{display:flex;align-items:center;gap:14px;padding:11px 0}
.brand{display:flex;align-items:center;gap:11px;min-width:0;flex:none}
/* the real DBC lockup (brand guidelines 2022): mark + Arabic + English in
   one horizontal artwork. SattvaRig runs a text wordmark instead, green on
   light surfaces and white on dark ones, so the dark theme whitens the same
   file with a filter. Height-driven so it scales cleanly on any screen. */
.brand img{height:40px;width:auto;border-radius:0;flex:none}
html:not([data-theme="light"]) .brand img{filter:brightness(0) invert(1)}
@media (max-width:720px){.brand img{height:31px}}
.brand .b-txt{display:flex;flex-direction:column;line-height:1.15;min-width:0}
/* the mark swaps with the theme: white art on dark, navy art on light,
   exactly the guidelines' logo usage rules */
.logo-on-dark{display:block}
.logo-on-light{display:none}
[data-theme="light"] .logo-on-dark{display:none}
[data-theme="light"] .logo-on-light{display:block}
.brand .b-name{font-weight:700;font-size:16.7px;letter-spacing:-.02em;white-space:nowrap}
.brand .b-sub{font-family:"JetBrains Mono",monospace;font-size:10.4px;font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--text-3);white-space:nowrap}
.navlinks{display:flex;align-items:center;gap:4px;margin-left:auto}
.navlinks a{font-size:15.5px;font-weight:600;color:var(--text-2);padding:8px 12px;border-radius:100px;border:1px solid transparent;transition:color var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease);white-space:nowrap}
.navlinks a:hover{color:var(--accent);border-color:var(--line)}
.navlinks a.on{color:var(--text-1);border-color:var(--line);background:var(--glass)}
.topbar-cta{display:flex;align-items:center;gap:9px;flex:none}
.topbar .btn{white-space:nowrap}
.theme-toggle{appearance:none;width:40px;height:40px;border-radius:50%;border:1px solid var(--line);background:var(--glass);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.theme-toggle:hover{transform:scale(1.08);border-color:var(--accent)}
.theme-toggle svg{width:17px;height:17px;color:var(--text-2)}
.theme-toggle:hover svg{color:var(--accent)}
.theme-toggle .i-moon{display:none}
[data-theme="light"] .theme-toggle .i-sun{display:none}
[data-theme="light"] .theme-toggle .i-moon{display:block}
.nav-toggle{display:none;appearance:none;width:40px;height:40px;border-radius:50%;border:1px solid var(--line);background:var(--glass);flex-direction:column;align-items:center;justify-content:center;gap:4px}
.nav-toggle span{display:block;width:16px;height:1.5px;background:var(--text-1);border-radius:2px;transition:transform var(--t-fast) var(--ease),opacity var(--t-fast) var(--ease)}
.nav-toggle.on span:nth-child(1){transform:translateY(5.5px) rotate(45deg)}
.nav-toggle.on span:nth-child(2){opacity:0}
.nav-toggle.on span:nth-child(3){transform:translateY(-5.5px) rotate(-45deg)}
/* tablet: the menu drops from the bar. Phone gets a bottom sheet instead,
   see PHONE EXPERIENCE at the bottom of this file. */
@media (max-width:1080px){
  /* solid panel, anchored to the bottom of the sticky bar. No backdrop-filter
     here: nesting one inside the bar's own filter reads as see-through. */
  .navlinks{position:absolute;top:100%;left:0;right:0;flex-direction:column;align-items:stretch;gap:2px;padding:14px 18px 20px;background:#0A0A0A;border-bottom:1px solid var(--line);box-shadow:var(--shadow);transform:translateY(-12px);opacity:0;pointer-events:none;transition:transform var(--t-med) var(--ease),opacity var(--t-med) var(--ease)}
  [data-theme="light"] .navlinks{background:#FFFFFF}
  .navlinks.open{transform:translateY(0);opacity:1;pointer-events:auto}
  .navlinks a{padding:12px 14px;font-size:16.7px}
  .nav-toggle{display:flex}
  .topbar-cta .btn.nav-quote{display:none}
}

/* ---------- buttons ---------- */
.btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;gap:8px;
  border:1px solid var(--line);background:var(--glass);color:var(--text-1);
  font-family:inherit;font-weight:600;font-size:15px;border-radius:100px;
  padding:12px 20px;min-height:46px;cursor:pointer;text-align:center;
  /* NOT nowrap: a long label ("Price my jurisdiction") then sets a 390px
     min-content floor on its grid track and pushes the whole page sideways at
     375px. Only the header bar, where wrapping looks untidy, keeps nowrap. */
  transition:transform var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),color var(--t-fast) var(--ease);
  box-shadow:var(--shadow-soft);-webkit-tap-highlight-color:transparent}
.btn:hover{border-color:var(--accent);color:var(--accent);transform:translateY(-1px)}
.btn:active{transform:translateY(0) scale(.97)}
.btn .arrow{transition:transform var(--t-fast) var(--ease)}
.btn:hover .arrow{transform:translateX(3px)}
/* The accent flipped per theme (light blue on dark, navy on light), so the
   button ink flips with it: navy ink on the light-blue button, white ink on
   the navy button. --accent-ink carries that. */
.btn.primary{background:var(--btn-bg);color:var(--btn-ink);border-color:var(--btn-bg);box-shadow:0 12px 30px -10px var(--accent-glow)}
.btn.primary:hover{color:var(--btn-ink);transform:translateY(-2px);box-shadow:0 18px 42px -12px var(--accent-glow)}
/* gold is not a brand colour: the old gold CTA now rides the same brand pair */
.btn.gold{background:var(--gold);color:var(--accent-ink);border-color:var(--gold);box-shadow:0 10px 26px -10px var(--accent-glow)}
.btn.gold:hover{color:var(--accent-ink);transform:translateY(-2px)}
.btn.sm{font-size:14.4px;padding:9px 16px;min-height:40px}
.btn.lg{font-size:17.3px;padding:14px 26px;min-height:52px}

/* ---------- shared type ---------- */
h1,h2,h3,h4{font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;letter-spacing:-.03em;line-height:1.1}
/* v5: type reverted to the v3 face on DP's call 2026-07-22. Headings ride the
   body Inter (no serif), the hook word is Outfit light italic with
   the gradient clipped into the text. The brand palette stays as applied. */
h1 em,h2 em,h3 em,.it{
  font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;font-style:italic;font-weight:300;letter-spacing:-.02em;
  background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.mono{font-family:"JetBrains Mono",monospace}
.num{font-family:"JetBrains Mono",monospace;font-variant-numeric:tabular-nums}
.eyebrow{display:inline-flex;align-items:center;gap:9px;font-family:"JetBrains Mono",monospace;font-size:12.1px;font-weight:500;letter-spacing:.2em;color:var(--accent);text-transform:uppercase;border:1px solid var(--line);border-radius:100px;padding:8px 18px;background:var(--glass);box-shadow:var(--shadow-soft)}
.eyebrow.gold{color:var(--gold);border-color:var(--gold-line)}
.eyebrow .dot{width:6px;height:6px;border-radius:50%;background:var(--success);animation:pulse-dot 2.2s var(--ease) infinite}
@keyframes pulse-dot{0%,100%{box-shadow:0 0 0 0 rgba(47,191,113,.45)}50%{box-shadow:0 0 0 7px transparent}}
/* the font strip: mono, uppercase, wide-tracked, with a leading rule */
.sec-kicker{font-family:"JetBrains Mono",monospace;font-size:12.1px;font-weight:500;letter-spacing:.2em;text-transform:uppercase;color:var(--accent);margin-bottom:12px;display:flex;align-items:center;gap:8px}
.sec-kicker::before{content:"";width:18px;height:1px;background:var(--accent);flex:none}
.sec-kicker.gold{color:var(--gold)}
.sec-kicker.gold::before{background:var(--gold)}
.sec-head{margin-bottom:28px;max-width:760px}
.sec-head.center{margin-left:auto;margin-right:auto;text-align:center}
.sec-head.center .sec-kicker{justify-content:center}
.sec-head h2{font-size:clamp(29.9px,3.6vw,43.7px);font-weight:620;letter-spacing:-.032em;line-height:1.12;margin-bottom:12px}
.sec-head p{color:var(--text-2);font-size:17.3px}
.sec-head.center p{margin-left:auto;margin-right:auto}
@media (min-width:721px){.sec-head{margin-bottom:34px}}

/* ---------- reveal ---------- */
.reveal{opacity:0;transform:translateY(16px);transition:opacity var(--t-slow) var(--ease),transform var(--t-slow) var(--ease)}
.reveal.in{opacity:1;transform:translateY(0)}
.reveal.d1{transition-delay:.08s}.reveal.d2{transition-delay:.16s}.reveal.d3{transition-delay:.24s}.reveal.d4{transition-delay:.32s}

/* ---------- hero ---------- */
.hero{padding:36px 0 44px}
.hero-inner{display:grid;grid-template-columns:1fr;gap:30px;align-items:center}
.hero h1{font-size:clamp(36.8px,5.4vw,59.8px);font-weight:600;letter-spacing:-.035em;line-height:1.06;margin:20px 0 14px}
.hero .lead{color:var(--text-2);font-size:19px;max-width:560px}
.hero-ctas{display:flex;gap:11px;flex-wrap:wrap;margin-top:24px}
.hero-trust{display:flex;gap:9px;flex-wrap:wrap;margin-top:22px}
/* DIRECT children only. An unscoped `.hero-trust span` also matched the
   nested .chip-x tail, which then drew its own pill and produced a box
   inside a box. gap is 0 so the tail reads as one continuous line, and
   the dot carries its own right margin instead. */
.hero-trust > span{display:inline-flex;align-items:center;gap:0;font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.06em;color:var(--text-2);border:1px solid var(--line);border-radius:100px;padding:7px 14px;background:var(--glass)}
.hero-trust i{width:5px;height:5px;border-radius:50%;background:var(--success);flex:none;margin-right:7px}
/* phone-only scroll cue between the hero copy and the snapshot card. Desktop
   shows both side by side, so there is nothing to hint at. */
.scroll-cue{display:none}
@keyframes cue-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(6px)}}
@media (min-width:961px){
  .hero{padding:64px 0 52px}
  .hero-inner{grid-template-columns:1.15fr .85fr;gap:44px}
}

/* the live estimate card: the home hero's ONE filled blue card */
.est-card{background:var(--fill);border-color:transparent;color:var(--fill-ink);
  box-shadow:0 0 0 6px var(--plate),var(--fill-glow);padding:22px 22px;overflow:hidden}
.est-card::before{content:"";position:absolute;inset:0;top:0;left:0;right:0;height:auto;
  background:
    radial-gradient(ellipse 70% 60% at 12% -10%,rgba(215,251,227,.34),transparent 62%),
    radial-gradient(circle,rgba(255,255,255,.10) 1px,transparent 1px);
  background-size:auto,22px 22px;opacity:.9;pointer-events:none}
.est-card>*{position:relative;z-index:1}
.est-card .scan{position:absolute;top:0;bottom:0;width:120px;pointer-events:none;background:linear-gradient(100deg,transparent,rgba(255,255,255,.16),transparent);transform:translateX(-160px);opacity:0;z-index:1}
.est-card.in .scan{animation:scan-sweep 1.3s var(--ease) .2s 1 both}
@keyframes scan-sweep{0%{opacity:1;transform:translateX(-160px)}100%{opacity:0;transform:translateX(760px)}}
.est-top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px;padding-bottom:14px;border-bottom:1px solid var(--fill-line)}
.est-top strong{font-size:17.3px;font-weight:650;color:var(--fill-ink)}
.est-badge{font-family:"JetBrains Mono",monospace;font-size:10.4px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:#FFFFFF;border:1px solid var(--fill-line);background:rgba(255,255,255,.14);border-radius:100px;padding:5px 10px;display:inline-flex;align-items:center;gap:6px}
.est-badge i{width:5px;height:5px;border-radius:50%;background:#B9F2D3;animation:pulse-dot 2s var(--ease) infinite}
.est-row{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:9px 0;font-size:15.5px}
.est-row span:first-child{color:var(--fill-muted)}
.est-row span:last-child{font-weight:650;color:var(--fill-ink);text-align:right}
.est-total{display:flex;align-items:baseline;justify-content:space-between;gap:14px;margin-top:14px;padding-top:15px;border-top:1px solid var(--fill-line)}
.est-total span{font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--fill-muted)}
.est-total strong{font-family:"JetBrains Mono",monospace;font-variant-numeric:tabular-nums;font-size:31px;font-weight:700;color:var(--fill-ink);letter-spacing:-.02em}
.est-foot{margin-top:14px;font-size:13.2px;color:var(--fill-muted);line-height:1.5}

/* ---------- marquee ---------- */
.marquee{position:relative;z-index:1;overflow:hidden;border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:var(--card-grad);padding:12px 0}
.marquee-track{display:flex;gap:0;width:max-content;animation:march 38s linear infinite;will-change:transform}
.marquee-track span{font-family:"JetBrains Mono",monospace;font-size:12.1px;letter-spacing:.18em;text-transform:uppercase;color:var(--text-3);padding:0 26px;position:relative;white-space:nowrap}
.marquee-track span::after{content:"";position:absolute;right:0;top:50%;width:4px;height:4px;border-radius:50%;background:var(--accent);opacity:.5;transform:translateY(-50%)}
@keyframes march{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* ---------- inner page hero ---------- */
.page-hero{padding:30px 0 34px}
.page-hero h1{font-size:clamp(32px,4.6vw,52px);font-weight:600;letter-spacing:-.035em;line-height:1.08;margin:16px 0 14px;max-width:900px}
.page-hero .lead{color:var(--text-2);font-size:18.4px;max-width:760px}
.page-hero .hero-ctas{margin-top:24px}
@media (min-width:721px){.page-hero{padding:48px 0 40px}}
/* founder portrait in the page hero (DP, 2026-07-23) */
.founder-photo{width:132px;height:132px;border-radius:50%;object-fit:cover;border:2px solid var(--line-strong);box-shadow:var(--shadow-soft),0 0 0 6px var(--accent-glow);display:block;margin-bottom:18px}

/* ---- founder hero: copy on the left, a big portrait on the right. Stacks on
       a phone with the photo under the copy, so the headline still lands
       first. The source photo is 400x400, so the frame is capped at 400 and
       never upscaled into mush. ---- */
.founder-hero-in{display:grid;gap:28px;align-items:center}
.founder-copy{min-width:0}
.founder-shot{margin:0;position:relative;width:100%;max-width:400px;justify-self:center}
.founder-shot img{display:block;width:100%;height:auto;aspect-ratio:1/1;object-fit:cover;
  border-radius:var(--radius);border:1px solid var(--line);
  box-shadow:var(--shadow),0 0 0 8px var(--plate)}
/* the name plate sits ON the photo, so it wears its own dark glass in both
   themes rather than following the page tokens */
.founder-shot figcaption{position:absolute;left:13px;right:13px;bottom:13px;
  display:flex;flex-direction:column;gap:3px;padding:12px 15px;border-radius:14px;
  background:rgba(6,20,10,.6);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border:1px solid rgba(255,255,255,.15)}
.founder-shot figcaption strong{font-size:15.5px;font-weight:700;letter-spacing:-.012em;color:#fff}
.founder-shot figcaption span{font-family:"JetBrains Mono",monospace;font-size:10.2px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--accent-deep)}
@media (min-width:901px){
  .founder-hero-in{grid-template-columns:minmax(0,1fr) 400px;gap:60px}
  .founder-shot{justify-self:end}
}

/* ---------- breadcrumbs ---------- */
.crumbs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:16px 0 0;font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3)}
.crumbs a{color:var(--text-3);transition:color var(--t-fast) var(--ease)}
.crumbs a:hover{color:var(--accent)}
.crumbs span[aria-current]{color:var(--accent)}
.crumbs .sep{opacity:.5}

/* Grid items default to min-width:auto, so one wide child (the price table,
   whose AED column is nowrap) sets a min-content floor and pushes the whole
   page sideways at 375px. min-width:0 caps the track and lets the table
   scroll inside its own .table-scroll instead. */
.split>*,.grid-2>*,.grid-3>*,.grid-4>*,.steps>*,.track>*,.stats>*,
.answer-grid>*,.opt-grid>*,.form-grid>*,.gpt-wrap>*{min-width:0}

/* ---------- split ---------- */
.split{display:grid;grid-template-columns:1fr;gap:26px;align-items:start}
@media (min-width:901px){.split{grid-template-columns:1fr 1fr;gap:34px}}

/* ---------- checklist ---------- */
.checklist{list-style:none;display:flex;flex-direction:column;gap:11px;margin-top:18px}
.checklist li{display:flex;gap:12px;align-items:flex-start;background:var(--card-grad);border:1px solid var(--line);padding:15px 16px;font-size:15.5px;color:var(--text-2);line-height:1.6;transition:border-color var(--t-fast) var(--ease),transform var(--t-fast) var(--ease)}
.checklist li:hover{border-color:var(--accent);transform:translateX(2px)}
.checklist li strong{color:var(--text-1);font-weight:700}
.checklist .check{flex:none;width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;color:#fff;background:var(--accent);margin-top:2px}

/* ---------- caution note (honest limits, not a scare box) ---------- */
.caution{margin-top:22px;display:flex;gap:14px;align-items:flex-start;background:linear-gradient(150deg,var(--warn-soft),transparent 62%),var(--card-grad);border:1px solid rgba(227,160,8,.34);border-radius:var(--radius-sm);padding:17px 18px}
.caution .c-ico{flex:none;width:36px;height:36px;border-radius:11px;display:flex;align-items:center;justify-content:center;font-size:17px;background:var(--warn-soft);border:1px solid rgba(227,160,8,.34)}
.caution .c-t{font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--warn);margin-bottom:6px}
.caution p{font-size:15.5px;color:var(--text-2);line-height:1.6}
.caution p a{color:var(--accent);font-weight:700}

/* ---------- price table ---------- */
.table-wrap{overflow:hidden}
.table-wrap .tw-head{padding:16px 20px;border-bottom:1px solid var(--line);font-family:"JetBrains Mono",monospace;font-size:12.1px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent)}
.table-scroll{overflow-x:auto}
.price-table{width:100%;border-collapse:collapse;min-width:340px}
.price-table th{text-align:left;font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);font-weight:600;padding:14px 18px;border-bottom:1px solid var(--line)}
.price-table th:last-child,.price-table td:last-child{text-align:right}
.price-table td{padding:14px 18px;font-size:15.5px;color:var(--text-2);border-bottom:1px solid var(--line-soft)}
.price-table td:last-child{font-family:"JetBrains Mono",monospace;font-size:14.4px;color:var(--text-1);font-weight:500;white-space:nowrap}
.price-table tr:last-child td{border-bottom:0}
/* opt-in total row. Do not key this off :last-child, most tables end on a normal row. */
.price-table tr.total td{background:var(--accent-soft);color:var(--text-1);font-weight:700}
.price-table tr.total td:last-child{color:var(--gold)}

/* ---------- numbered steps grid ---------- */
.steps{display:grid;grid-template-columns:1fr;gap:12px}
.step{padding:18px 18px;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.step:hover{transform:translateY(-3px);border-color:var(--accent)}
.step .n{display:inline-block;font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;letter-spacing:.16em;color:var(--accent);margin-bottom:9px}
.step h3{font-size:18.4px;font-weight:650;margin-bottom:6px;letter-spacing:-.02em}
.step p{font-size:14.4px;color:var(--text-2);line-height:1.55}
@media (min-width:561px){.steps,.steps.cols-5,.steps.cols-3{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:1001px){
  .steps{grid-template-columns:repeat(4,minmax(0,1fr))}
  .steps.cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}
  .steps.cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* ---------- answer-first block (SEO / answer-engine surface) ---------- */
.answer-sec{padding-top:48px}
.answer-card{padding:24px 20px}
.answer-lead{font-size:17.8px;line-height:1.72;color:var(--text-2);max-width:900px}
/* short answers are one sentence per paragraph (DP, 2026-07-25), so consecutive
   leads need breathing room or they read as one block again */
.answer-lead+.answer-lead{margin-top:14px}
.answer-lead strong{color:var(--text-1);font-weight:700}
.answer-grid{display:grid;grid-template-columns:1fr;gap:11px;margin-top:22px}
.answer-grid .ans{background:var(--glass-hi);border:1px solid var(--line);padding:15px 16px}
.answer-grid dt{font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin-bottom:6px}
.answer-grid dd{font-size:15.5px;font-weight:650;color:var(--text-1);line-height:1.45}
.answer-note{margin-top:20px;padding-top:16px;border-top:1px solid var(--line-soft);font-size:14.4px;color:var(--text-3);line-height:1.6}
@media (min-width:421px){.answer-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:721px){.answer-sec{padding-top:64px}.answer-card{padding:30px 32px}.answer-lead{font-size:19px}}
@media (min-width:1001px){.answer-grid{grid-template-columns:repeat(4,minmax(0,1fr))}}

/* ---------- cards ---------- */
.grid-2,.grid-3,.grid-4{display:grid;grid-template-columns:1fr;gap:14px}
@media (min-width:621px){.grid-3,.grid-4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:821px){.grid-2{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:961px){.grid-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-4{grid-template-columns:repeat(4,minmax(0,1fr))}}

.gcard{padding:22px 22px 20px;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),box-shadow var(--t-med) var(--ease);display:flex;flex-direction:column}
.gcard:hover{transform:translateY(-3px);border-color:var(--line-strong);box-shadow:0 0 0 6px var(--plate),var(--shadow-lg)}
.gcard .g-ico{width:46px;height:46px;border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:21px;background:var(--accent-soft);border:1px solid var(--line);margin-bottom:14px}
.gcard .g-ico.gold{background:var(--gold-soft);border-color:var(--gold-line)}
.gcard .g-ico.cyan{background:rgba(94,146,232,.12)}
.gcard h3{font-size:21.8px;font-weight:650;letter-spacing:-.025em;margin-bottom:7px;line-height:1.2}
.gcard p{font-size:15.5px;color:var(--text-2);line-height:1.6}
.gcard .g-link{margin-top:auto;padding-top:16px;font-family:"JetBrains Mono",monospace;font-size:12.1px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);display:inline-flex;align-items:center;gap:7px}
.gcard .g-link .arrow{transition:transform var(--t-fast) var(--ease)}
.gcard:hover .g-link .arrow{transform:translateX(3px)}
.gcard .g-price{display:inline-block;margin-top:12px;font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;border-radius:100px;padding:5px 11px;color:var(--gold);border:1px solid var(--gold-line);background:var(--gold-soft)}
/* the section's one filled card, opt in per section with class="gcard fill-card" */
.gcard.fill-card .g-ico{background:rgba(255,255,255,.14);border-color:var(--fill-line)}
.gcard.fill-card .g-link{color:var(--fill-muted)}
.gcard.fill-card .g-price{color:#FFFFFF;border-color:var(--fill-line);background:rgba(255,255,255,.14)}

/* ---------- stats ---------- */
.stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.stat{padding:22px 16px;text-align:center;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.stat:hover{transform:translateY(-3px);border-color:var(--line-strong)}
.stat .num{font-family:"JetBrains Mono",monospace;font-variant-numeric:tabular-nums;font-size:clamp(32px,4vw,46px);font-weight:700;line-height:1.05;background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.stat .label{font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);margin-top:9px;line-height:1.5}
/* the stats row's one filled card */
.stat.fill-card .num{background:none;-webkit-text-fill-color:var(--fill-ink);color:var(--fill-ink)}
.stat.fill-card .label{color:var(--fill-muted)}
@media (min-width:961px){.stats{grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}}

/* ---------- process track ---------- */
.track{position:relative;display:grid;grid-template-columns:1fr;gap:14px}
.track .tline{display:none}
.tnode{position:relative;z-index:1;display:flex;flex-direction:column;opacity:.4;transform:translateY(8px);transition:opacity var(--t-slow) var(--ease),transform var(--t-slow) var(--ease)}
.tnode.lit{opacity:1;transform:translateY(0)}
.tnode .t-pin{width:46px;height:46px;margin:0 auto 13px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:18px;background:var(--glass-hi);border:2px solid var(--line);transition:border-color var(--t-med) var(--ease),box-shadow var(--t-med) var(--ease)}
.tnode.lit .t-pin{border-color:var(--accent);box-shadow:0 0 0 6px var(--accent-glow),0 0 24px var(--accent-glow)}
/* flex:1, not height:100%: the pin above the card sits inside the same grid
   cell, so a 100% tall card overflowed the cell by the pin's height and the
   last step landed on top of the stats row on phones (DP, 2026-07-23) */
.tnode .t-card{padding:16px 16px;flex:1}
.tnode.lit .t-card{border-color:var(--line-strong)}
.tnode .t-step{font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);margin-bottom:6px}
.tnode .t-t{font-weight:650;font-size:18.4px;line-height:1.25;margin-bottom:6px;letter-spacing:-.02em}
.tnode .t-d{font-size:14.4px;color:var(--text-2);line-height:1.55}
@media (min-width:561px){.track{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:1001px){
  .track{grid-template-columns:repeat(5,minmax(0,1fr))}
  .track .tline{display:block;position:absolute;top:22px;left:6%;right:6%;height:2px;background:var(--line-soft);border-radius:2px;z-index:0}
  .track .tline .tfill{display:block;height:100%;width:0%;border-radius:2px;background:var(--grad);box-shadow:0 0 12px var(--accent-glow);transition:width 1.8s var(--ease)}
}

/* ---------- CTA band: the filled blue panel that closes a page ---------- */
.band{padding:34px 22px;text-align:center;overflow:hidden;
  background:var(--fill);border-color:transparent;color:var(--fill-ink);
  box-shadow:0 0 0 6px var(--plate),var(--fill-glow)}
.band::before{content:"";position:absolute;inset:0;top:0;left:0;right:0;height:auto;
  background:
    radial-gradient(ellipse 70% 60% at 12% -10%,rgba(215,251,227,.34),transparent 62%),
    radial-gradient(circle,rgba(255,255,255,.10) 1px,transparent 1px);
  background-size:auto,22px 22px;opacity:.9;pointer-events:none}
.band>*{position:relative;z-index:1}
.band h2{font-size:clamp(27.6px,3.4vw,41.4px);font-weight:620;letter-spacing:-.03em;line-height:1.14;margin-bottom:12px;color:var(--fill-ink)}
.band h2 em{background:none;-webkit-text-fill-color:var(--fill-muted);color:var(--fill-muted)}
.band p{color:var(--fill-muted);font-size:17.3px;max-width:620px;margin:0 auto}
.band .sec-kicker{color:var(--fill-muted);justify-content:center}
.band .sec-kicker::before{background:var(--fill-muted)}
.band .hero-ctas{justify-content:center}
.band .btn{background:rgba(255,255,255,.12);border-color:var(--fill-line);color:var(--fill-ink)}
.band .btn:hover{background:rgba(255,255,255,.2);border-color:rgba(255,255,255,.34);color:var(--fill-ink)}
.band .btn.primary,.band .btn.primary:hover,.band .btn.gold,.band .btn.gold:hover{
  background:#FFFFFF;color:#133875;border-color:transparent;box-shadow:0 12px 30px -14px rgba(0,0,0,.5)}
/* the gold band stays a money panel, not a second blue one: gold trim on the
   normal card surface, so a page never shows two filled blue cards in a row */
.band.gold{background:linear-gradient(150deg,var(--gold-soft),transparent 62%),var(--card-grad);
  border-color:var(--gold-line);color:var(--text-1);box-shadow:0 0 0 6px var(--plate),var(--shadow-soft)}
.band.gold::before{background:none}
.band.gold h2{color:var(--text-1)}
.band.gold h2 em{background:var(--grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}
.band.gold p{color:var(--text-2)}
.band.gold .sec-kicker{color:var(--gold)}
.band.gold .sec-kicker::before{background:var(--gold)}
.band.gold .btn{background:var(--glass);border-color:var(--line);color:var(--text-1)}
.band.gold .btn:hover{border-color:var(--accent);color:var(--accent)}
.band.gold .btn.gold,.band.gold .btn.gold:hover{background:var(--gold);border-color:var(--gold);color:var(--accent-ink)}
@media (min-width:621px){.band{padding:48px 40px}}

/* ---------- testimonials ---------- */
.quote{padding:22px;display:flex;flex-direction:column;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.quote:hover{transform:translateY(-3px);border-color:var(--gold-line)}
.quote .stars{color:var(--gold);letter-spacing:.16em;font-size:14.4px;margin-bottom:12px}
.quote p{font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;font-style:italic;font-weight:300;font-size:20px;line-height:1.45;color:var(--text-1);letter-spacing:-.02em}
.quote .who{display:flex;align-items:center;gap:11px;margin-top:auto;padding-top:18px}
.quote .avatar{width:40px;height:40px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff;background:conic-gradient(from 40deg,var(--accent),var(--accent-2),var(--accent))}
.quote .avatar.gold{background:conic-gradient(from 40deg,var(--gold),var(--accent-deep),var(--gold));color:#0A0A00}
.quote .who strong{display:block;font-size:15.5px;font-weight:700}
.quote .who small{display:block;font-family:"JetBrains Mono",monospace;font-size:10.4px;letter-spacing:.1em;text-transform:uppercase;color:var(--text-3);margin-top:2px}

/* ---------- FAQ ---------- */
.faq{max-width:820px;margin:0 auto;overflow:hidden}
.faq-item{border-bottom:1px solid var(--line-soft)}
.faq-item:last-child{border-bottom:0}
.faq-q{appearance:none;width:100%;display:flex;align-items:center;gap:16px;text-align:left;background:transparent;border:0;color:var(--text-1);font-size:17.3px;font-weight:650;line-height:1.4;letter-spacing:-.02em;padding:18px 20px;min-height:60px;transition:color var(--t-fast) var(--ease)}
.faq-q:hover{color:var(--accent)}
.faq-q .plus{margin-left:auto;flex:none;width:26px;height:26px;border-radius:50%;border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:400;color:var(--accent);transition:transform var(--t-med) var(--ease)}
.faq-q[aria-expanded="true"] .plus{transform:rotate(45deg)}
.faq-a{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--t-med) var(--ease)}
.faq-q[aria-expanded="true"]+.faq-a{grid-template-rows:1fr}
.faq-a>div{overflow:hidden}
.faq-a p{padding:0 20px 20px;font-size:16px;color:var(--text-2);line-height:1.65}
.faq-a p a{color:var(--accent);font-weight:700}
@media (min-width:721px){.faq-q{padding:19px 24px}.faq-a p{padding:0 24px 20px}}

/* ---------- footer ---------- */
/* THE FOOTER, ported from dubai-dbc-v7 on DP's instruction 2026-07-29.
   It is a deep navy slab that ignores the theme: it is identical in dark and
   light, the same way the filled card is, so the page always lands on the same
   note. Because the slab is always dark, everything inside it is written in
   fixed light ink rather than theme tokens, or it would go black on navy the
   moment somebody switched to light. */
.site-foot{position:relative;z-index:1;overflow:hidden;border-top:none;
  background:linear-gradient(168deg,#173F80 0%,#123268 42%,#0C2149 100%);
  color:#EAF1FF;padding:52px 0 26px}
/* the cursor-reactive dash field, drawn by assets/ui.js. Decorative only. */
.foot-fx{position:absolute;inset:0;width:100%;height:100%;display:block;
  pointer-events:none;z-index:0;opacity:.85}
.foot-inner{position:relative;z-index:1}
.site-foot .brand .wm,.site-foot p,.site-foot li a{color:#EAF1FF}
.site-foot h4{color:#8FB3EE}
.site-foot li a{color:rgba(234,241,255,.78)}
.site-foot li a:hover{color:#FFFFFF}
.foot-bottom{border-top-color:rgba(234,241,255,.16);color:rgba(234,241,255,.55)}
.foot-bottom a{color:inherit}
.foot-bottom a:hover{color:#FFFFFF}
.foot-grid{display:grid;grid-template-columns:1fr;gap:26px}
.foot-brand p{font-size:15.5px;color:rgba(234,241,255,.72);line-height:1.65;margin-top:14px;max-width:340px}
.site-foot h4{font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.18em;text-transform:uppercase;color:#8FB3EE;margin-bottom:12px}
.site-foot ul{list-style:none;display:flex;flex-direction:column;gap:2px}
.site-foot li a{font-size:15.5px;color:rgba(234,241,255,.78);display:flex;align-items:center;min-height:44px;transition:color var(--t-fast) var(--ease)}
.site-foot li a:hover{color:#FFFFFF}
.foot-bottom{display:flex;flex-direction:column;gap:8px;margin-top:32px;padding-top:20px;border-top:1px solid rgba(234,241,255,.16);font-family:"JetBrains Mono",monospace;font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:rgba(234,241,255,.62)}
@media (min-width:521px){.foot-grid{grid-template-columns:1fr 1fr;gap:28px}}
@media (min-width:721px){
  .site-foot{padding:56px 0 28px}
  .foot-bottom{flex-direction:row;justify-content:space-between;flex-wrap:wrap;gap:14px}
  .site-foot ul{gap:8px}
  .site-foot li a{min-height:0;display:block}
}
@media (min-width:861px){.foot-grid{grid-template-columns:1.6fr 1fr 1fr 1fr;gap:36px}}

/* =========================================================================
   DBC GPT, an APP not a page.
   DP, 2026-07-22: the old version was a tall marketing page. On a phone you
   landed on a wall of topic buttons, and as soon as you scrolled the chat box
   went up off the screen. It now behaves like a chat app: the shell is exactly
   one viewport tall, only the transcript scrolls, and the composer never moves.
   On a phone the topic list is a bottom sheet behind a Topics button instead
   of a column you have to scroll past.
   ========================================================================= */

/* the chat shell is viewport height minus the page chrome above it, so the
   composer sits on the bottom edge and stays there while the log scrolls */
/* --gpt-chrome is the no-JS fallback. gpt.js measures the real distance from
   the top of the viewport and sets the height exactly, so the composer is on
   screen whatever the headline wraps to. */
.gpt-section{--gpt-chrome:250px}
.gpt-wrap{display:grid;grid-template-columns:1fr;gap:16px;align-items:stretch;
  height:calc(100dvh - var(--gpt-chrome));min-height:400px}
@media (min-width:1001px){
  .gpt-wrap{grid-template-columns:280px minmax(0,1fr)}
}
/* the header above the app stays compact: this is a tool, not a landing page */
.gpt-section{padding-top:0}
.gpt-page-hero{padding:18px 0 14px}
.gpt-page-hero h1{font-size:clamp(25px,3.2vw,36px);margin:10px 0 8px}
.gpt-page-hero .lead{font-size:16.7px}

.gpt-side{padding:16px 14px;display:flex;flex-direction:column;min-height:0;
  overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin}
.gpt-side::-webkit-scrollbar{width:7px}
.gpt-side::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:99px}
.gpt-side h3{font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--accent);margin-bottom:9px}
.gpt-side .gs-group{margin-bottom:18px}
.gpt-side .gs-group:last-child{margin-bottom:0}
.gs-sheet-head{display:none}
.gpt-topic{display:flex;align-items:center;gap:9px;width:100%;text-align:left;appearance:none;background:transparent;border:1px solid transparent;border-radius:11px;padding:10px;color:var(--text-2);font-family:inherit;font-size:15.5px;font-weight:600;line-height:1.35;cursor:pointer;transition:all var(--t-fast) var(--ease);min-height:44px}
.gpt-topic:hover{border-color:var(--line);background:var(--glass-hi);color:var(--accent)}
.gpt-topic .gt-ico{flex:none;font-size:16px}

/* the main column: header pinned, log scrolls, composer pinned */
.gpt-main{display:flex;flex-direction:column;overflow:hidden;min-height:0}
.gpt-head{display:flex;align-items:center;gap:11px;padding:13px 18px;border-bottom:1px solid var(--line);flex:none;position:relative;z-index:2}
.gpt-head .gh-dot{width:8px;height:8px;border-radius:50%;background:var(--success);flex:none;animation:pulse-dot 2.2s var(--ease) infinite}
.gpt-head .gh-t{font-weight:650;font-size:17.3px;letter-spacing:-.02em}
.gpt-head .gh-s{font-family:"JetBrains Mono",monospace;font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3)}
.gpt-head .gh-topics{display:none}
.gpt-head .gh-new{margin-left:auto}

/* the transcript is the only thing on this page that scrolls */
.gpt-log{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  padding:22px 18px 8px;display:flex;flex-direction:column;gap:18px;scroll-behavior:smooth}
.gpt-log::-webkit-scrollbar{width:8px}
.gpt-log::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:99px}
.gpt-msg{display:flex;gap:12px;animation:rise .4s var(--ease) both;max-width:760px;width:100%}
.gpt-msg .gm-av{flex:none;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#fff;background:conic-gradient(from 40deg,var(--accent),var(--accent-2),var(--accent))}
.gpt-msg.me .gm-av{background:var(--glass-hi);border:1px solid var(--line);color:var(--text-2)}
.gpt-msg .gm-body{flex:1;min-width:0;font-size:16.7px;line-height:1.68;color:var(--text-1);padding-top:3px}
.gpt-msg .gm-body p{margin-bottom:11px}
.gpt-msg .gm-body p:last-child{margin-bottom:0}
.gpt-msg .gm-body a{color:var(--accent);font-weight:700;text-decoration:underline;text-underline-offset:2px}
.gpt-msg .gm-body strong{color:var(--text-1);font-weight:700}
/* the visitor's own turn reads as a bubble, the way a chat app looks */
.gpt-msg.me{align-self:flex-end;flex-direction:row-reverse;max-width:620px}
.gpt-msg.me .gm-body{background:var(--accent-soft);border:1px solid var(--line);border-radius:16px 16px 4px 16px;padding:11px 15px;color:var(--text-1);font-weight:500}
.gpt-err{border:1px solid rgba(242,85,92,.4);background:rgba(242,85,92,.08);border-radius:var(--radius-sm);padding:13px 15px;font-size:15.5px;color:var(--text-2);line-height:1.6}
.gpt-err b{color:var(--danger)}
.gpt-typing{display:inline-flex;gap:4px;align-items:center;padding-top:8px}
.gpt-typing i{width:6px;height:6px;border-radius:50%;background:var(--accent);opacity:.4;animation:blink 1.3s var(--ease) infinite}
.gpt-typing i:nth-child(2){animation-delay:.18s}
.gpt-typing i:nth-child(3){animation-delay:.36s}
@keyframes blink{0%,100%{opacity:.25;transform:translateY(0)}50%{opacity:1;transform:translateY(-3px)}}

/* the suggestion chips sit directly above the composer and scroll sideways,
   so people can see there are things to ask without a wall of buttons */
.gpt-starters{flex:none;padding:10px 18px 0;display:flex;gap:8px;overflow-x:auto;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.gpt-starters::-webkit-scrollbar{display:none}
.gpt-starters button{appearance:none;flex:none;white-space:nowrap;border:1px solid var(--line);background:var(--glass-hi);color:var(--text-2);font-family:inherit;font-weight:600;font-size:14.4px;border-radius:100px;padding:9px 15px;cursor:pointer;transition:all var(--t-fast) var(--ease);min-height:42px}
.gpt-starters button:hover{border-color:var(--accent);color:var(--accent)}

/* the composer: one rounded field, always on screen */
.gpt-form{flex:none;padding:12px 18px 6px;display:flex;gap:10px;align-items:flex-end}
.gpt-form textarea{flex:1;appearance:none;background:var(--field-bg);border:1px solid var(--line);border-radius:22px;outline:0;color:var(--text-1);font-family:inherit;font-size:16.7px;padding:13px 18px;resize:none;max-height:130px;line-height:1.5;transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease)}
.gpt-form textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-glow)}
.gpt-form textarea::placeholder{color:var(--text-3)}
.gpt-send{appearance:none;flex:none;width:46px;height:46px;border-radius:50%;border:1px solid var(--accent);background:var(--accent);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--t-fast) var(--ease);box-shadow:0 6px 16px -4px var(--accent-glow)}
.gpt-send:hover:not(:disabled){transform:translateY(-2px)}
.gpt-send:disabled{opacity:.4;cursor:not-allowed;box-shadow:none}
.gpt-note{flex:none;padding:4px 18px 12px;font-size:12.5px;color:var(--text-3);line-height:1.5;text-align:center}


/* ---------- proof strip: authority and free zone logos under the hero ---------- */
.proof-row{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;align-items:stretch}
.proof-row .pl{background:#FFFFFF;border:1px solid var(--line);border-radius:14px;padding:10px 18px;display:flex;align-items:center;justify-content:center;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.proof-row .pl:hover{transform:translateY(-2px);border-color:var(--line-strong)}
.proof-row .pl img{height:30px;width:auto;max-width:150px;object-fit:contain;display:block}
.proof-note{text-align:center;font-family:"JetBrains Mono",monospace;font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);margin-top:14px}
@media (max-width:720px){.proof-row .pl{padding:8px 14px}.proof-row .pl img{height:24px;max-width:120px}}

/* ---------- footer payment methods row ---------- */
.pay-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pay-row span{background:#FFFFFF;border:1px solid var(--line-soft);border-radius:6px;padding:3px 8px;display:inline-flex;align-items:center}
.pay-row img{height:18px;width:auto;display:block}

/* ---------- FAQ encyclopedia ---------- */
.kb-search{position:relative;max-width:640px;margin:0 auto}
.kb-search input{width:100%;appearance:none;background:var(--card-grad);border:1px solid var(--line);border-radius:100px;outline:0;color:var(--text-1);font-family:inherit;font-size:16.7px;font-weight:500;padding:15px 52px 15px 22px;box-shadow:var(--shadow-soft);transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease)}
.kb-search input:focus{border-color:var(--accent);box-shadow:0 0 0 4px var(--accent-glow)}
.kb-search input::placeholder{color:var(--text-3);font-weight:450}
.kb-search .kb-ico{position:absolute;right:20px;top:50%;transform:translateY(-50%);color:var(--text-3);pointer-events:none;display:flex}
.kb-count{text-align:center;font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);margin-top:14px}
.kb-count b{color:var(--accent)}
/* the category row scrolls sideways inside itself, it never wraps */
.kb-cats{display:flex;gap:8px;margin:24px 0 8px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-bottom:2px}
.kb-cats::-webkit-scrollbar{display:none}
.kb-cats button{appearance:none;flex:none;display:inline-flex;align-items:center;gap:8px;border:1px solid var(--line);background:var(--card-grad);color:var(--text-2);font-family:inherit;font-weight:600;font-size:14.4px;border-radius:100px;padding:10px 18px;cursor:pointer;white-space:nowrap;transition:all var(--t-fast) var(--ease);min-height:44px}
.kb-cats button:hover{border-color:var(--accent);color:var(--accent)}
.kb-cats button.on{border-color:var(--accent);color:var(--text-1);box-shadow:0 6px 18px -6px var(--accent-glow)}
.kb-cats button .kb-n{font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--text-3)}
.kb-cats button.on .kb-n{color:var(--accent)}
@media (min-width:721px){.kb-cats{justify-content:center;flex-wrap:wrap;overflow:visible;margin:26px 0 8px}.kb-cats button{flex:0 0 auto}}
.kb-group{margin-top:38px;scroll-margin-top:88px}
.kb-group-head{display:flex;align-items:flex-start;gap:14px;margin-bottom:16px;padding-bottom:14px;border-bottom:1px solid var(--line);flex-wrap:wrap}
.kb-group-head .kb-gi{flex:none;width:46px;height:46px;border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:21px;background:var(--accent-soft);border:1px solid var(--line)}
.kb-group-head h3{font-size:21.8px;font-weight:650;letter-spacing:-.025em;line-height:1.25}
.kb-group-head p{font-size:15.5px;color:var(--text-2);line-height:1.55;margin-top:3px}
.kb-group-head .kb-gn{flex:none;font-family:"JetBrains Mono",monospace;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--text-3);border:1px solid var(--line);border-radius:100px;padding:5px 12px;white-space:nowrap}
@media (min-width:721px){.kb-group-head{flex-wrap:nowrap}.kb-group-head .kb-gn{margin-left:auto}}
.kb-empty{text-align:center;padding:48px 20px;color:var(--text-2)}
.kb-empty b{display:block;font-size:19px;color:var(--text-1);margin-bottom:8px}
.kb-hit{background:rgba(94,146,232,.34);border-radius:3px;padding:0 2px;color:var(--text-1)}

/* screen readers and crawlers get the heading, sighted users do not need it twice */
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ---------- forms ---------- */
.form-card{padding:22px 18px}
/* pair fields two to a row: it turns a six line block into three.
   align-items:end so a label that wraps to two lines ("Phone (with country
   code)") does not push its input below its neighbour's. */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:end}
.form-grid .field.full{grid-column:1/-1}
.field label{display:block;font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-3);margin-bottom:7px}
.field input,.field select,.field textarea{width:100%;appearance:none;background:var(--field-bg);border:1px solid var(--line);border-radius:12px;outline:0;color:var(--text-1);font-family:inherit;font-size:16.7px;font-weight:500;padding:13px 14px;transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease)}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-glow)}
.field input::placeholder,.field textarea::placeholder{color:var(--text-3);font-weight:450}
.field textarea{resize:vertical;min-height:96px;line-height:1.55}
.field select{cursor:pointer;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%234ADE80' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 13px center;background-size:14px;padding-right:38px}
[data-theme="light"] .field select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='0A0A0A' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E")}
.field .note{font-size:13.8px;color:var(--text-3);margin-top:10px;line-height:1.5}
.form-ok{display:none;padding:24px 22px;border-radius:var(--radius);background:var(--success-soft);border:1px solid rgba(47,191,113,.42)}
.form-ok.show{display:block;animation:rise .5s var(--ease) both}
.form-ok strong{font-size:18.4px;font-weight:700;color:var(--success)}
.form-ok p{color:var(--text-2);font-size:15.5px;margin-top:7px;line-height:1.6}
@keyframes rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
@media (min-width:621px){.form-card{padding:26px 26px 24px}.form-grid{gap:14px}}

/* ---------- contact info cards ---------- */
.info-card{display:block;padding:20px;margin-bottom:12px;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.info-card:hover{transform:translateY(-3px);border-color:var(--line-strong)}
.info-card .g-ico{width:44px;height:44px;border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:20px;background:var(--accent-soft);border:1px solid var(--line);margin-bottom:13px}
.info-card .g-ico.wa{background:rgba(37,211,102,.12);border-color:rgba(37,211,102,.4)}
.info-card h3{font-size:18.4px;font-weight:650;margin-bottom:6px;letter-spacing:-.02em}
.info-card p{font-size:15.5px;color:var(--text-2);line-height:1.6}
.info-card .g-link{display:inline-flex;align-items:center;gap:7px;margin-top:12px;font-family:"JetBrains Mono",monospace;font-size:12.1px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}

/* =========================================================================
   Cost calculator UI. The classes are exactly what assets/calculator.js
   emits, so the pricing logic and markup are untouched. Do not rename these.
   ========================================================================= */
.calc-shell{overflow:hidden}
.calc-head{padding:16px 18px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap}
.calc-head .title{font-weight:650;font-size:17.3px;display:flex;align-items:center;gap:10px;letter-spacing:-.02em}
.calc-head .title .pulse-dot{width:8px;height:8px;border-radius:50%;background:var(--success);flex:none;animation:pulse-dot 2.2s var(--ease) infinite}
.calc-progress{display:flex;align-items:center;gap:10px;font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--text-3)}
.calc-bar{width:110px;height:6px;border-radius:100px;background:rgba(255,255,255,.08);overflow:hidden}
[data-theme="light"] .calc-bar{background:rgba(15,23,42,.08)}
.calc-bar i{display:block;height:100%;border-radius:100px;background:var(--grad);transform-origin:left;transform:scaleX(.2);transition:transform .6s var(--ease)}
.calc-xp{font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;letter-spacing:.1em;color:var(--gold);background:var(--gold-soft);border:1px solid var(--gold-line);padding:5px 12px;border-radius:100px}
.calc-xp.bump{animation:xp-bump .5s var(--ease)}
@keyframes xp-bump{0%,100%{transform:scale(1)}40%{transform:scale(1.18)}}
.calc-body{padding:26px 18px 30px;min-height:400px;position:relative}
.calc-q{font-size:clamp(21.8px,2.6vw,29.9px);font-weight:650;letter-spacing:-.03em;line-height:1.2;margin-bottom:8px}
.calc-sub{color:var(--text-2);font-size:16px;margin-bottom:22px}
.opt-grid,.opt-grid.three{display:grid;grid-template-columns:1fr;gap:11px}
@media (min-width:761px){.opt-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.opt-grid.three{grid-template-columns:repeat(3,minmax(0,1fr))}}
.opt{appearance:none;text-align:left;background:var(--card-grad);border:1px solid var(--line);border-radius:var(--radius-sm);padding:16px 17px;cursor:pointer;color:var(--text-1);font-family:inherit;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease);position:relative;min-height:56px}
.opt:hover{transform:translateY(-3px);border-color:var(--accent)}
.opt.selected{border-color:var(--accent);box-shadow:0 6px 18px -6px var(--accent-glow)}
.opt.selected::after{content:"";position:absolute;top:12px;right:12px;width:8px;height:8px;border-radius:50%;background:var(--accent)}
.opt .opt-emoji{font-size:22px;display:block;margin-bottom:9px}
.opt strong{display:block;font-size:16.7px;font-weight:650;margin-bottom:4px;letter-spacing:-.02em}
.opt small{color:var(--text-2);font-size:14.4px;line-height:1.5;display:block}
.stepper{display:flex;align-items:center;justify-content:center;gap:24px;padding:26px 0}
.stepper button{appearance:none;width:52px;height:52px;border-radius:50%;border:1px solid var(--line);background:var(--glass-hi);color:var(--text-1);font-size:22px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.stepper button:hover{transform:scale(1.08);border-color:var(--accent);color:var(--accent)}
.stepper button:active{transform:scale(.94)}
.stepper .count{font-family:"JetBrains Mono",monospace;font-variant-numeric:tabular-nums;font-size:52px;font-weight:700;min-width:90px;text-align:center;letter-spacing:-.03em;background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.stepper .count.tick{animation:xp-bump .35s var(--ease)}
.calc-nav{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:26px}
.calc-back{appearance:none;background:none;border:0;color:var(--text-3);font-family:inherit;font-weight:600;font-size:15.5px;display:inline-flex;gap:8px;align-items:center;cursor:pointer;min-height:44px;transition:color var(--t-fast) var(--ease)}
.calc-back:hover{color:var(--accent)}
.calc-back[disabled]{opacity:0;pointer-events:none}
.calc-result{text-align:center}
.result-badge{display:inline-flex;align-items:center;gap:8px;padding:7px 17px;border-radius:100px;background:var(--gold-soft);border:1px solid var(--gold-line);color:var(--gold);font-family:"JetBrains Mono",monospace;font-weight:600;font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;margin-bottom:20px}
.result-total{font-family:"JetBrains Mono",monospace;font-variant-numeric:tabular-nums;font-size:clamp(40px,6vw,64px);font-weight:700;letter-spacing:-.03em;line-height:1;margin:8px 0 6px;background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.result-total .cur{font-size:.42em;vertical-align:super;margin-right:6px;-webkit-text-fill-color:var(--text-3)}
.result-note{color:var(--text-3);font-size:14.4px;margin-bottom:24px}
.result-rows{max-width:470px;margin:0 auto 24px;text-align:left;background:var(--glass-hi);border:1px solid var(--line);padding:6px 18px}
.result-rows .rr{display:flex;justify-content:space-between;gap:16px;padding:12px 0;border-bottom:1px solid var(--line-soft);font-size:15.5px;opacity:0;transform:translateY(12px)}
.result-rows .rr:last-child{border-bottom:0}
.result-rows .rr.show{animation:rr-in .5s var(--ease) forwards}
@keyframes rr-in{to{opacity:1;transform:translateY(0)}}
.result-rows .rr span:first-child{color:var(--text-2)}
.result-rows .rr span:last-child{font-family:"JetBrains Mono",monospace;font-weight:600;color:var(--text-1);white-space:nowrap}
.result-ctas{display:flex;gap:11px;justify-content:center;flex-wrap:wrap}
.calc-result details{max-width:470px;margin:0 auto 24px;text-align:left;background:var(--glass-hi);border:1px solid var(--line);border-radius:var(--radius-sm);padding:14px 18px}
.calc-result details summary{cursor:pointer;font-weight:650;font-size:15.5px;color:var(--text-1);list-style:none;min-height:32px}
.calc-result details summary::-webkit-details-marker{display:none}
.calc-result details ul{list-style:none;padding:12px 0 4px;display:grid;gap:8px;color:var(--text-2);font-size:14.4px;line-height:1.5}
@media (min-width:621px){.calc-head{padding:18px 24px}.calc-body{padding:32px 26px 34px}.calc-bar{width:140px}}

/* button aliases: calculator.js emits the original class names */
.btn-yellow{background:var(--gold);color:var(--accent-ink);border-color:var(--gold);box-shadow:0 10px 26px -10px var(--accent-glow)}
.btn-yellow:hover{color:var(--accent-ink);transform:translateY(-2px)}
.btn-primary{background:var(--accent);color:var(--accent-ink);border-color:var(--accent);box-shadow:0 12px 30px -10px var(--accent-glow)}
.btn-primary:hover{color:var(--accent-ink);transform:translateY(-2px)}
.btn-outline{background:transparent;border-color:var(--gold-line);color:var(--gold)}
.btn-outline:hover{background:var(--gold-soft);color:var(--gold);border-color:var(--gold)}
.btn-ghost{background:transparent;box-shadow:none;color:var(--text-3);border-color:var(--line)}
.btn-ghost:hover{color:var(--danger);border-color:var(--danger)}
.btn-lg{font-size:17.3px;padding:14px 26px;min-height:52px}
.btn-sm{font-size:14.4px;padding:9px 16px;min-height:40px}

/* ---------- the filled card, last word on ink ----------
   These repeat the .fill-card ink rules on purpose. The component sections
   above (.gcard h3, .info-card p, .stat .num and friends) come later in the
   cascade at equal specificity, so without this block a filled card would
   render dark body text on a blue panel. Keep this block at the bottom. */
.gcard.fill-card h3,.info-card.fill-card h3,.stat.fill-card .num,
.gcard.fill-card strong,.info-card.fill-card strong{color:var(--fill-ink)}
.gcard.fill-card p,.info-card.fill-card p,.gcard.fill-card small,
.stat.fill-card .label,.info-card.fill-card .g-link{color:var(--fill-muted)}
.gcard.fill-card .g-link,.info-card.fill-card .g-link{color:var(--fill-muted)}
.stat.fill-card .num{background:none;-webkit-text-fill-color:var(--fill-ink)}
.gcard.fill-card:hover,.info-card.fill-card:hover,.stat.fill-card:hover{
  border-color:transparent;box-shadow:0 0 0 6px var(--plate),var(--fill-glow)}
.info-card.fill-card .g-ico,.gcard.fill-card .g-ico,
.info-card.fill-card .g-ico.wa{background:rgba(255,255,255,.16);border-color:var(--fill-line)}

/* a price table as the section's filled card (offshore's jurisdictions).
   Every hairline and every ink colour has to survive the blue. */
.table-wrap.fill-card .tw-head{color:var(--fill-muted);border-bottom-color:var(--fill-line)}
.table-wrap.fill-card .price-table th{color:var(--fill-muted);border-bottom-color:var(--fill-line)}
.table-wrap.fill-card .price-table td{color:var(--fill-muted);border-bottom-color:rgba(255,255,255,.1)}
.table-wrap.fill-card .price-table td:last-child{color:var(--fill-ink)}
.table-wrap.fill-card .price-table tr.total td{background:rgba(255,255,255,.12);color:var(--fill-ink)}
.table-wrap.fill-card .price-table tr.total td:last-child{color:var(--fill-muted)}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}
  .reveal{opacity:1;transform:none}
}

/* =========================================================================
   BLOG. The generator (scripts/build-blog.mjs) emits exactly these classes.
   Two surfaces: the INDEX (a card grid in the site's own language, one
   fill-card per view) and an ARTICLE (a centred single column that reads like
   a long-form post, no sidebar, generous measure and type). Phone rules for
   both live in the PHONE EXPERIENCE block below, not here.
   ========================================================================= */

/* ---- category pills. BUTTONS on /blog (they filter the grid in place) and
       LINKS on a category page (they navigate). One class, so the row looks
       identical either way. ---- */
.np-cats{display:flex;flex-wrap:wrap;gap:9px;margin:0 0 28px}
.np-pill{appearance:none;flex:none;display:inline-flex;align-items:center;gap:8px;
  border:1px solid var(--line);background:var(--card-grad);color:var(--text-2);
  font-family:inherit;font-weight:600;font-size:14.4px;border-radius:100px;
  padding:10px 18px;cursor:pointer;white-space:nowrap;min-height:44px;
  transition:border-color var(--t-fast) var(--ease),color var(--t-fast) var(--ease),
    background var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease)}
.np-pill:hover{border-color:var(--accent);color:var(--accent)}
.np-pill .np-n{font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--text-2)}
.np-pill.on{background:var(--btn-bg);border-color:var(--btn-bg);color:var(--btn-ink);
  box-shadow:0 8px 22px -10px var(--accent-glow)}
.np-pill.on .np-n{color:var(--btn-ink);opacity:.86}

/* ---- the card grid: 3 up on desktop, 2 on a tablet, 1 on a phone ---- */
.np-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:26px;align-items:stretch}
@media (max-width:1024px){.np-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}}

/* ---- the card. Image, then category + read time, then headline, then
       excerpt, then the author footer with the date. It is an <article> and
       not one big <a> on purpose: the category and the headline are separate
       destinations, and a link cannot legally sit inside a link. ---- */
.npcard{display:flex;flex-direction:column;position:relative;overflow:hidden;
  border:1px solid var(--line);border-radius:var(--radius);background:var(--card-grad);
  transition:border-color var(--t) var(--ease),transform var(--t) var(--ease),box-shadow var(--t) var(--ease);
  animation:np-in .42s var(--ease) both}
@keyframes np-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.npcard:hover{border-color:var(--accent);transform:translateY(-3px);box-shadow:var(--shadow-soft)}
.np-img{display:block;aspect-ratio:16/9;overflow:hidden;background:var(--glass);
  border-bottom:1px solid var(--line)}
.np-img img{display:block;width:100%;height:100%;object-fit:cover;
  transition:transform var(--t-slow) var(--ease)}
.npcard:hover .np-img img{transform:scale(1.04)}
.np-ico{display:flex;align-items:center;justify-content:center;height:100%;font-size:40px}
.np-body{display:flex;flex-direction:column;flex:1;padding:16px 18px 18px}
.np-top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px}
.np-cat{min-width:0;font-family:"JetBrains Mono",monospace;font-size:10.4px;font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--accent);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.np-cat:hover{text-decoration:underline;text-underline-offset:3px}
.np-read,.np-date{display:inline-flex;align-items:center;gap:6px;flex:none;
  font-family:"JetBrains Mono",monospace;font-size:10.4px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text-3);white-space:nowrap}
.np-i{width:13px;height:13px;flex:none}
.np-h{font-size:19px;font-weight:680;letter-spacing:-.022em;line-height:1.26;margin:0}
.np-h a{color:var(--text-1);transition:color var(--t-fast) var(--ease)}
.npcard:hover .np-h a{color:var(--accent)}
.np-ex{font-size:14.8px;color:var(--text-2);line-height:1.56;margin:9px 0 0;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}

/* the author footer: avatar, name, job title, then the date on the right */
.np-foot{display:flex;align-items:center;gap:10px;margin:auto 0 0;padding-top:15px;
  border-top:1px solid var(--line-soft)}
.np-av{flex:none;width:36px;height:36px;border-radius:50%;object-fit:cover;
  border:1px solid var(--line-strong);background:var(--glass-hi)}
.np-who{display:flex;flex-direction:column;min-width:0;line-height:1.25}
.np-name{font-size:12.8px;font-weight:700;color:var(--text-1);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.np-job{font-size:10.6px;color:var(--text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.np-foot .np-date{margin-left:auto}

/* ---- our own promo tiles, where Neil Patel sells ad space. No sponsors, so
       no "join 5000 companies" banners: just the next step on this site.
       ui.js places them with CSS order, so filtering never strands one. ---- */
/* the tile stretches to the tallest card in its row, so the copy is centred
   rather than pinned top and bottom with a hole in the middle */
.np-promo{display:flex;flex-direction:column;justify-content:center;position:relative;overflow:hidden;
  border:1px solid var(--line-strong);border-radius:var(--radius);
  background:linear-gradient(158deg,var(--glass-hi),var(--glass));padding:22px 20px 20px}
.np-promo::after{content:"";position:absolute;inset:0;pointer-events:none;
  background-image:radial-gradient(var(--dots) 1px,transparent 1px);background-size:20px 20px;opacity:.5;
  mask-image:radial-gradient(ellipse 78% 70% at 82% 0,black,transparent 72%);
  -webkit-mask-image:radial-gradient(ellipse 78% 70% at 82% 0,black,transparent 72%)}
.np-promo>*{position:relative;z-index:1}
.np-p-k{font-family:"JetBrains Mono",monospace;font-size:10.4px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}
.np-p-h{display:block;font-size:20px;font-weight:700;letter-spacing:-.025em;line-height:1.22;
  margin:10px 0 0;color:var(--text-1)}
.np-promo p{font-size:14.6px;color:var(--text-2);line-height:1.56;margin:9px 0 18px}
.np-p-cta{align-self:flex-start;flex:none}
.np-promo.fill{background:var(--fill);border-color:transparent;color:var(--fill-ink);
  box-shadow:0 0 0 6px var(--plate),var(--fill-glow)}
.np-promo.fill::after{opacity:.3}
.np-promo.fill .np-p-k{color:var(--fill-muted)}
.np-promo.fill .np-p-h{color:var(--fill-ink)}
.np-promo.fill p{color:var(--fill-muted)}
.np-promo.fill .btn.primary{background:#FFFFFF;color:#133875;border-color:transparent;
  box-shadow:0 12px 30px -14px rgba(0,0,0,.5)}
.np-promo.fill .btn.primary:hover{background:#EAF1FF;color:#133875;transform:translateY(-2px)}

/* ---- Load More, in place of the old 1 2 3 4 5 pager ---- */
.np-more{display:flex;flex-direction:column;align-items:center;gap:14px;margin-top:38px}
.np-more .btn{min-width:250px;justify-content:center}
.np-count{font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--text-3);margin:0}
.np-count b{color:var(--accent);font-weight:600}
.np-empty{text-align:center;color:var(--text-2);font-size:16.3px;padding:36px 0}

/* ---- featured card: the newest guide, above the grid ---- */
.bfeat{display:grid;grid-template-columns:1fr;gap:0;margin:0 0 26px;overflow:hidden;
  border:1px solid var(--line);border-radius:var(--radius);background:var(--card-grad);
  transition:border-color var(--t) var(--ease),box-shadow var(--t) var(--ease)}
.bfeat:hover{border-color:var(--accent);box-shadow:var(--shadow-soft)}
.bfeat .bf-body{display:flex;flex-direction:column;padding:20px 18px 22px}
.bfeat .np-h{font-size:24px;font-weight:700;letter-spacing:-.028em;line-height:1.18}
.bfeat .np-ex{font-size:15.4px;-webkit-line-clamp:4}
.bfeat .np-foot{margin-top:16px}
.bfeat .bf-more{align-self:flex-start;margin-top:20px}
.bfeat:hover .np-h a{color:var(--accent)}
@media (min-width:781px){
  /* the image keeps its 16:9 shape and centres itself rather than stretching to
     the row height, so the thumbnail is never cropped on a wide screen */
  .bfeat{grid-template-columns:1.1fr 1fr;align-items:center}
  .bfeat .np-img{align-self:center;border-bottom:0;border-right:1px solid var(--line)}
  .bfeat .bf-body{padding:30px 30px 32px;justify-content:center}
  .bfeat .np-h{font-size:31px}
}
@media (min-width:1025px){
  .bfeat .np-h{font-size:35px}
  .bfeat .bf-body{padding:38px 38px 40px}
}

/* ---- archive ---- */
.archive-wrap{max-width:820px;margin:0 auto}
.archive-group{margin-bottom:34px}
.ar-month{display:flex;align-items:center;gap:12px;font-size:21.8px;font-weight:650;letter-spacing:-.025em;
  padding-bottom:12px;margin-bottom:6px;border-bottom:1px solid var(--line)}
.ar-month .ar-count{font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:600;letter-spacing:.1em;
  color:var(--text-3);border:1px solid var(--line);border-radius:100px;padding:4px 11px}
.archive-list{list-style:none}
.archive-list li{border-bottom:1px solid var(--line-soft)}
.archive-list li:last-child{border-bottom:0}
.archive-list a{display:flex;flex-direction:column;gap:3px;padding:14px 2px;transition:padding var(--t-fast) var(--ease)}
.archive-list a:hover{padding-left:10px}
.archive-list .ar-t{font-size:16.7px;font-weight:600;color:var(--text-1);line-height:1.35;transition:color var(--t-fast) var(--ease)}
.archive-list a:hover .ar-t{color:var(--accent)}
.archive-list .ar-meta{font-family:"JetBrains Mono",monospace;font-size:10.9px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-3)}
.archive-list .ar-meta .bdot{opacity:.6}

/* =========================================================================
   ARTICLE: two columns from 1025px up. The reading column on the left, a
   sticky rail on the right carrying the table of contents and the CTA cards.
   Below 1025px it collapses to one centred column and the TOC goes back to
   being the collapsible strip above the prose.
   ========================================================================= */
.article{position:relative;z-index:1;padding:8px 0 40px}
.article-main{min-width:0;max-width:820px;margin:0 auto}
.art-side{display:none}
@media (min-width:1025px){
  .article-shell{display:grid;grid-template-columns:minmax(0,1fr) 336px;gap:56px}
  .article-main{max-width:none;margin:0}
  .art-side{display:block;min-width:0}
  /* the rail sticks INSIDE its own column, so the column has to keep the
     row's full height. Never add align-items:start to the grid above, that
     shrink-wraps the column and sticky then has nowhere to travel. */
  .art-side-in{position:sticky;top:88px;display:flex;flex-direction:column;gap:16px;
    max-height:calc(100dvh - 108px);overflow-y:auto;overscroll-behavior:contain;
    scrollbar-width:thin;padding-right:2px}
  .toc{display:none}
}
.article-head{margin:18px 0 22px}
.btag.standalone{display:inline-flex;align-items:center;gap:7px;font-family:"JetBrains Mono",monospace;
  font-size:11.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--accent);
  border:1px solid var(--line);border-radius:100px;padding:7px 15px;background:var(--glass);margin:0}
.btag.standalone:hover{border-color:var(--accent)}
.article-head h1{font-size:clamp(31px,4.4vw,49px);font-weight:600;letter-spacing:-.035em;line-height:1.08;margin:16px 0 14px}

/* the byline: avatar, name, job title, then the date and read time.
   When an article has been updated, the shown date is the update date and the
   full history lives in the title attribute and the BlogPosting schema, which
   is what search engines actually read. */
.art-by{display:flex;align-items:center;gap:11px;margin-top:18px;padding-top:16px;
  border-top:1px solid var(--line-soft)}
.art-by .np-av{width:44px;height:44px}
.art-by .np-name{font-size:14.4px}
.art-by .np-job{font-size:11.5px}
.art-by-meta{display:flex;align-items:center;gap:16px;margin-left:auto}
.art-by .d-sm{display:none}

/* ---- the sticky rail ---- */
.side-k{display:block;font-family:"JetBrains Mono",monospace;font-size:10.6px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--accent)}
.side-toc{border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--card-grad);
  padding:16px 17px 10px}
/* a 14-heading guide would make the rail taller than the screen and push the
   green Book card out of sight, so the list gets its own scroll and the CTAs
   always stay reachable */
.side-toc-list{list-style:none;counter-reset:stoc;margin-top:10px;position:relative;
  max-height:min(34vh,300px);overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin}
.side-toc-list li{counter-increment:stoc}
.side-toc-list a{display:flex;gap:10px;padding:8px 0 8px 11px;margin-left:-12px;
  border-left:2px solid transparent;font-size:14.4px;line-height:1.4;color:var(--text-2);
  transition:color var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease)}
.side-toc-list a::before{content:counter(stoc,decimal-leading-zero);font-family:"JetBrains Mono",monospace;
  font-size:10.6px;color:var(--text-3);flex:none;padding-top:3px}
.side-toc-list a:hover{color:var(--accent)}
.side-toc-list a.on{color:var(--accent);border-left-color:var(--accent);font-weight:600}
.side-toc-list a.on::before{color:var(--accent)}
.side-card{border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--card-grad);
  padding:18px 17px}
.side-card strong{display:block;font-size:17.3px;font-weight:700;letter-spacing:-.02em;line-height:1.25;
  color:var(--text-1);margin:9px 0 0}
.side-card strong em{font-style:normal;color:var(--accent)}
.side-card p{font-size:14px;color:var(--text-2);line-height:1.55;margin:8px 0 14px}
.side-card .btn{width:100%;justify-content:center}
.side-card.fill{background:var(--fill);border-color:transparent;
  box-shadow:0 0 0 5px var(--plate),var(--fill-glow)}
.side-card.fill .side-k{color:var(--fill-muted)}
.side-card.fill strong,.side-card.fill strong em{color:var(--fill-ink)}
.side-card.fill p{color:var(--fill-muted)}
.side-card.fill .btn.primary{background:#FFFFFF;color:#133875;border-color:transparent}
.side-card.fill .btn.primary:hover{background:#EAF1FF;color:#133875}

/* the answer-first box, the featured-snippet target */
.article-answer{padding:22px 24px;margin-bottom:26px}
.article-answer .aa-k{font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--accent);margin-bottom:10px}
.article-answer .answer-lead{font-size:19px;line-height:1.66;color:var(--text-1)}
.article-answer .answer-lead+.answer-lead{margin-top:14px}

/* table of contents, collapsible */
.toc{margin:0 0 30px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--card-grad);overflow:hidden}
.toc-toggle{appearance:none;width:100%;display:flex;align-items:center;justify-content:space-between;
  background:transparent;border:0;color:var(--text-1);font-family:"JetBrains Mono",monospace;font-size:11.5px;
  font-weight:600;letter-spacing:.16em;text-transform:uppercase;padding:15px 18px;cursor:pointer;min-height:50px}
.toc-toggle .toc-caret{transition:transform var(--t-med) var(--ease);color:var(--accent)}
.toc-toggle[aria-expanded="true"] .toc-caret{transform:rotate(180deg)}
/* the collapse animates ONE wrapper (.toc-body), exactly like the FAQ. Do NOT
   put the 0fr/1fr grid on .toc-list itself: its children are the <li>s, so the
   fr track only sizes the first row and the first item (Step 1) collapses to
   zero while the rest overflow into implicit auto rows. Wrapping fixes it. */
.toc-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--t-med) var(--ease)}
.toc-toggle[aria-expanded="true"]+.toc-body{grid-template-rows:1fr}
.toc-body>*{overflow:hidden;min-height:0}
.toc-list{list-style:none;counter-reset:toc}
.toc-list li{counter-increment:toc;border-top:1px solid var(--line-soft)}
.toc-list a{display:flex;gap:11px;padding:12px 18px;font-size:15.5px;color:var(--text-2);line-height:1.4;
  transition:color var(--t-fast) var(--ease),background var(--t-fast) var(--ease)}
.toc-list a::before{content:counter(toc,decimal-leading-zero);font-family:"JetBrains Mono",monospace;
  font-size:11.5px;color:var(--accent);flex:none;padding-top:2px}
.toc-list a:hover{color:var(--accent);background:var(--glass-hi)}
/* on a wide screen the TOC can stay open by default, it is not in the way */
@media (min-width:721px){
  .toc-body{grid-template-rows:1fr}
  .toc-toggle{cursor:default;pointer-events:none}
  .toc-toggle .toc-caret{display:none}
}

/* the prose body: the whole point is that it reads better than Shuraa */
.prose{font-size:19px;line-height:1.78;color:var(--text-1)}
.prose>*+*{margin-top:22px}
.prose p{color:var(--text-1);font-weight:400}
.prose h2{font-size:clamp(25px,3vw,32px);font-weight:620;letter-spacing:-.03em;line-height:1.18;
  margin-top:44px;scroll-margin-top:84px}
.prose h2:first-child{margin-top:0}
.prose h3{font-size:21px;font-weight:650;letter-spacing:-.02em;line-height:1.3;margin-top:30px}
.prose a{color:var(--accent);font-weight:600;text-decoration:underline;text-underline-offset:2px;
  text-decoration-color:var(--line-strong);transition:text-decoration-color var(--t-fast) var(--ease)}
.prose a:hover{text-decoration-color:var(--accent)}
.prose strong{color:var(--text-1);font-weight:700}
.prose-ul,.prose-ol{padding-left:0;list-style:none;display:flex;flex-direction:column;gap:12px}
.prose-ul li,.prose-ol li{position:relative;padding-left:32px;color:var(--text-1);line-height:1.65}
.prose-ul li::before{content:"";position:absolute;left:8px;top:12px;width:7px;height:7px;border-radius:50%;
  background:var(--accent);box-shadow:0 0 0 4px var(--accent-soft)}
.prose-ol{counter-reset:pro}
.prose-ol li{counter-increment:pro}
.prose-ol li::before{content:counter(pro);position:absolute;left:0;top:1px;width:24px;height:24px;border-radius:50%;
  background:var(--accent-soft);border:1px solid var(--line);color:var(--accent);font-family:"JetBrains Mono",monospace;
  font-size:12px;font-weight:600;display:flex;align-items:center;justify-content:center}
.prose-table{margin-top:26px;margin-bottom:26px}
.prose-quote{border-left:3px solid var(--accent);padding:6px 0 6px 22px;margin:28px 0;
  font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;font-style:italic;font-weight:300;font-size:22px;line-height:1.5;
  color:var(--text-1);letter-spacing:-.02em}

/* inline note / tip */
.prose-note{display:flex;gap:14px;align-items:flex-start;margin:28px 0;padding:18px 20px;border-radius:var(--radius-sm);
  border:1px solid var(--line);background:linear-gradient(150deg,var(--accent-soft),transparent 64%),var(--card-grad)}
.prose-note.tip{border-color:var(--gold-line);background:linear-gradient(150deg,var(--gold-soft),transparent 64%),var(--card-grad)}
.prose-note .pn-ico{flex:none;width:38px;height:38px;border-radius:11px;display:flex;align-items:center;justify-content:center;
  font-size:18px;background:var(--accent-soft);border:1px solid var(--line)}
.prose-note.tip .pn-ico{background:var(--gold-soft);border-color:var(--gold-line)}
.prose-note .pn-t{display:block;font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--accent);margin-bottom:6px}
.prose-note.tip .pn-t{color:var(--gold)}
.prose-note p{font-size:16px;color:var(--text-2);line-height:1.62;margin:0}

/* key takeaways box, sits high in the article */
.takeaways{margin:26px 0;padding:20px 22px;border-radius:var(--radius-sm);border:1px solid var(--line-strong);
  background:linear-gradient(158deg,var(--glass-hi),var(--glass))}
.takeaways .tk-t{display:block;font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--accent);margin-bottom:14px}
.takeaways ul{list-style:none;display:flex;flex-direction:column;gap:11px}
.takeaways li{position:relative;padding-left:30px;font-size:16.3px;line-height:1.55;color:var(--text-1)}
.takeaways li::before{content:"";position:absolute;left:6px;top:9px;width:8px;height:8px;border-radius:2px;
  transform:rotate(45deg);background:var(--accent)}

/* the inline calculator CTA (calculator-only, per the build decision) */
.prose-cta{display:flex;align-items:center;gap:18px;flex-wrap:wrap;justify-content:space-between;
  margin:32px 0;padding:22px 24px;border-radius:var(--radius);background:var(--fill);color:var(--fill-ink);
  border:1px solid transparent;box-shadow:0 0 0 6px var(--plate),var(--fill-glow);position:relative;overflow:hidden}
.prose-cta::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse 70% 60% at 10% -10%,rgba(215,251,227,.3),transparent 62%),
  radial-gradient(circle,rgba(255,255,255,.09) 1px,transparent 1px);background-size:auto,22px 22px;opacity:.9}
.prose-cta>*{position:relative;z-index:1}
.prose-cta .pc-k{display:block;font-family:"JetBrains Mono",monospace;font-size:10.9px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--fill-muted);margin-bottom:7px}
.prose-cta strong{display:block;font-size:20px;font-weight:650;color:var(--fill-ink);letter-spacing:-.02em;line-height:1.25}
.prose-cta p{font-size:15px;color:var(--fill-muted);margin:6px 0 0;max-width:440px;line-height:1.55}
.prose-cta .btn{flex:none;background:#FFFFFF;color:#133875;border-color:transparent;box-shadow:0 12px 30px -14px rgba(0,0,0,.5)}
.prose-cta .btn:hover{background:#EAF1FF;color:#133875;transform:translateY(-2px)}

/* the article FAQ reuses the .faq accordion; just spacing around it */
.article-faq{margin-top:46px}
.article-faq>h2{font-size:clamp(25px,3vw,32px);font-weight:620;letter-spacing:-.03em;margin-bottom:18px;text-align:center}
.article-faq .faq{margin-top:0}
.article-cta{margin-top:40px}
.article-related{position:relative;z-index:1;padding-top:8px}

/* ════════════════════════ PHONE EXPERIENCE ════════════════════════
   Effectively all of this site's traffic is on phones, so the phone layout is
   its own thing, not the desktop layout squeezed. Everything phone-specific
   lives in this ONE block so it is easy to find and tune later.
   Carried over from the command center: bottom sheets instead of centred
   boxes, icon-only in tight bars, fields paired two to a row, headers stacked
   instead of squeezed, pill rows that scroll sideways, tighter frames.
   ════════════════════════════════════════════════════════════════ */
@media (max-width:720px){
  /* tighter frames: page padding 24/16, card padding 20/17, radius 18 */
  :root{--radius:18px}
  section{padding:44px 0}
  /* DP, 2026-07-25: one gutter for the WHOLE site on a phone. The new sections
     used 16px and the ported legacy sections used 18px, so nothing lined up as
     you scrolled and cards read as if they were touching the screen edge.
     20px each side, matched in scanner.css, is the single source of truth. */
  .wrap{width:calc(100% - 40px)}

  /* phones scroll a lot: reveals FADE only, no upward slide (the 16px shift
     read as jumpy boxes while scrolling, DP 2026-07-23) */
  .reveal{transform:none;transition:opacity .45s var(--ease)}
  .reveal.in{transform:none}
  .tnode{transform:none}
  .tnode.lit{transform:none}

  /* no green glow pinned to the viewport edges on phones: the fixed radial
     washes read as an ugly fade at the top and bottom while scrolling */
  /* flat on phones too. No vertical wash. */
  .ambient{background:var(--bg-0)}
  [data-theme="light"] .ambient{background:var(--bg-0)}

  /* the bar carries the brand, the theme toggle and the menu. No page can
     afford a label-heavy header at 375px: the labels go, the icons stay. */
  .topbar{background:var(--bg-1);backdrop-filter:none;-webkit-backdrop-filter:none}
  [data-theme="light"] .topbar{background:var(--bg-1)}
  .topbar-inner{gap:10px;padding:9px 0}
  /* the horizontal lockup stays height-driven on phones too, never squashed
     back to a square */
  .brand img{height:31px;width:auto}
  /* the mark swaps with the theme: white art on dark, navy art on light,
   exactly the guidelines' logo usage rules */
.logo-on-dark{display:block}
.logo-on-light{display:none}
[data-theme="light"] .logo-on-dark{display:none}
[data-theme="light"] .logo-on-light{display:block}
.brand .b-name{font-size:15.5px}
  .brand .b-sub{font-size:9.4px;letter-spacing:.16em}
  .topbar-cta{gap:7px;margin-left:auto}

  /* the menu rises from the bottom edge, the way a phone menu should.
     The bar drops its backdrop-filter above precisely so this can be fixed to
     the viewport: a filtered ancestor becomes the containing block for fixed
     children and the sheet would open inside the header instead. */
  .navlinks{position:fixed;top:auto;left:0;right:0;bottom:0;
    border-radius:22px 22px 0 0;border:1px solid var(--line);border-bottom:0;
    padding:12px 16px calc(16px + env(safe-area-inset-bottom));
    max-height:82dvh;overflow-y:auto;overscroll-behavior:contain;
    box-shadow:0 -30px 70px -20px rgba(0,0,0,.7);
    transform:translateY(102%);opacity:1;z-index:90}
  /* the grab handle, so it reads as a sheet and not a stuck panel */
  .navlinks::before{content:"";flex:none;width:38px;height:4px;border-radius:99px;
    background:var(--line-strong);align-self:center;margin-bottom:10px}
  .navlinks.open{transform:translateY(0)}
  /* the dim behind the sheet. It cannot live on .navlinks::before: the sheet
     scrolls, and overflow:auto clips its own pseudo-elements. */
  .topbar:has(.navlinks.open)::after{content:"";position:fixed;inset:0;z-index:1;
    background:rgba(2,5,12,.62);animation:scrim-in var(--t-med) var(--ease) both}
  [data-theme="light"] .topbar:has(.navlinks.open)::after{background:rgba(14,26,51,.45)}
  @keyframes scrim-in{from{opacity:0}to{opacity:1}}
  /* the brand and the close button stay above the dim so the sheet can be shut */
  .brand,.topbar-cta{position:relative;z-index:3}
  .navlinks a{padding:13px 14px;font-size:17.3px;min-height:50px;display:flex;align-items:center;border-radius:12px}
  .navlinks a.on{background:var(--accent-soft);color:var(--accent)}

  /* hero */
  .hero{padding:28px 0 36px}
  .hero h1{margin:16px 0 12px}
  .hero .lead{font-size:17.3px}
  .hero-ctas{gap:10px;margin-top:20px}
  .hero-ctas .btn,.result-ctas .btn{flex:1 1 100%}
  /* the eyebrow drops its pill frame on phones: one quiet mono line, no box */
  .hero .eyebrow{border:0;background:transparent;box-shadow:none;padding:0;font-size:10.4px;letter-spacing:.12em;gap:7px}
  /* trust proof reads as one plain line with dot separators, so it stops
     competing with the two real buttons above it. The .chip-x tails are
     hidden here so all three fit a 375px line. */
  .hero-trust{gap:0;margin-top:16px;flex-wrap:nowrap;align-items:center;justify-content:flex-start;white-space:nowrap}
  .hero-trust > span{border:0;background:transparent;padding:0;font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;font-size:11px;letter-spacing:0}
  .hero-trust i{display:none}
  .hero-trust > span + span::before{content:"\00B7";margin:0 7px;color:var(--text-3)}
  .hero-trust .chip-x{display:none}
  /* the scroll cue between the hero copy and the snapshot card */
  .scroll-cue{display:flex;justify-content:center;margin:20px 0 2px;color:var(--accent);animation:cue-bob 2s var(--ease) infinite}
  .scroll-cue svg{width:20px;height:20px}

  /* cards: less frame, more content */
  .gcard,.quote,.info-card,.answer-card,.form-card{padding:20px 17px}
  .est-card{padding:20px 17px}
  .band{padding:30px 20px}
  .stat{padding:20px 12px}
  .gcard::before,.quote::before,.info-card::before,.stat::before,.est-card::before,
  .band::before,.step::before,.tnode .t-card::before{left:16px;right:16px}
  .gcard h3{font-size:20px}
  .gcard .g-link{padding-top:16px;min-height:44px;align-items:center}
  .sec-head{margin-bottom:22px}

  /* a squeezed header renders its subtitle one word per line. Stack it. */
  .calc-head{flex-wrap:wrap;align-items:center;gap:10px 12px}
  .calc-head .title{flex:1 0 100%}
  .calc-progress{flex:1;min-width:0}
  .calc-bar{flex:1;width:auto}
  .calc-xp{flex:none}
  .gpt-head{gap:8px}
  .gpt-head .gh-new{margin-left:auto}

  /* pair fields two to a row instead of stacking every field on its own line */
  .form-grid{grid-template-columns:1fr 1fr;gap:10px}
  .field label{font-size:10.4px;letter-spacing:.12em}

  /* the estimate total: stack it so the AED figure never wraps mid-number */
  .est-total{flex-direction:column;align-items:flex-start;gap:2px}
  .est-total strong{font-size:28px}
  .est-row{font-size:14.8px}

  /* quotes and FAQ stay readable, not shrunk */
  .quote p{font-size:18.4px}
  .faq-q{font-size:16.7px;padding:16px 16px}
  .faq-a p{padding:0 16px 18px;font-size:15.5px}

  /* the price tables: tighter cells so most of them fit without the inner
     sideways scroll. The scroll stays as the fallback for the wide ones. */
  .price-table th{padding:12px 12px;font-size:10.9px}
  .price-table td{padding:12px 12px;font-size:14.4px}
  .price-table td:last-child{font-size:13.2px}
  .table-wrap .tw-head{padding:14px 16px;font-size:11.5px}

  /* the footer link columns */
  .foot-brand p{font-size:15px}

  /* ── DBC GPT on a phone ──────────────────────────────────────────
     You land IN the chat. The header above it is cut to the headline, the
     breadcrumb goes, and the topic list moves into a bottom sheet, so the
     composer is on screen the moment the page opens and never moves after. */
  .gpt-section{--gpt-chrome:196px}
  .gpt-page-hero{padding:14px 0 12px}
  .gpt-page-hero .eyebrow,.gpt-page-hero .lead{display:none}
  .gpt-page-hero h1{font-size:25px;margin:0;line-height:1.15}
  .gpt-section .crumbs,.gpt-crumbs{display:none}
  .gpt-wrap{gap:0;min-height:400px}

  .gpt-head{padding:11px 14px;gap:8px}
  .gpt-head .gh-s{display:none}
  .gpt-head .gh-topics{display:inline-flex;margin-left:auto}
  .gpt-head .gh-new{margin-left:0}
  .gpt-head .btn.sm{font-size:13.2px;padding:8px 13px;min-height:38px}
  .gpt-log{padding:16px 14px 6px;gap:15px}
  .gpt-msg .gm-body{font-size:16px}
  /* a hairline over the chips row: chat text clips against the composer area
     while scrolling, and without a separator the cut read as broken layout */
  .gpt-starters{padding:9px 14px 0;border-top:1px solid var(--line)}
  .gpt-form{padding:10px 14px 6px}
  .gpt-note{font-size:11.5px;padding:2px 14px calc(10px + env(safe-area-inset-bottom))}

  /* the topic list rises from the bottom, like every other sheet on the site.
     transform:none matters: .reveal leaves an identity transform behind, and a
     transformed element cannot host a fixed-position sheet correctly. */
  .gpt-side{position:fixed;left:0;right:0;bottom:0;top:auto;z-index:90;
    opacity:1;transform:translateY(102%);
    border-radius:22px 22px 0 0;border:1px solid var(--line);border-bottom:0;
    padding:10px 14px calc(14px + env(safe-area-inset-bottom));
    max-height:78dvh;box-shadow:0 -30px 70px -20px rgba(0,0,0,.7);
    transition:transform var(--t-med) var(--ease)}
  .gpt-side.open{transform:translateY(0)}
  .gs-sheet-head{display:flex;align-items:center;gap:10px;flex:none;
    padding:2px 2px 10px;margin-bottom:6px;border-bottom:1px solid var(--line)}
  .gs-sheet-head span{font-family:"JetBrains Mono",monospace;font-size:11.5px;
    letter-spacing:.18em;text-transform:uppercase;color:var(--text-3)}
  .gs-close{margin-left:auto;appearance:none;width:38px;height:38px;border-radius:50%;
    border:1px solid var(--line);background:var(--glass-hi);color:var(--text-2);
    font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center}
  .gpt-topic{font-size:16.7px;min-height:48px}
  /* the dim behind the sheet, on the section so the sheet's own scroll cannot clip it */
  .gpt-section:has(.gpt-side.open)::after{content:"";position:fixed;inset:0;z-index:89;
    background:rgba(2,5,12,.62);animation:scrim-in var(--t-med) var(--ease) both}
  [data-theme="light"] .gpt-section:has(.gpt-side.open)::after{background:rgba(14,26,51,.45)}

  /* ── BLOG on a phone ─────────────────────────────────────────────
     The filter pills scroll sideways instead of wrapping into a tall block.
     ONE card per row (DP, 2026-07-25): the Neil Patel card carries an author
     footer with an avatar, a name and a job title, and that simply cannot be
     read at 167px, which is what a 2-up card is on a 375px screen. The
     article column loses its side gutters so the measure stays generous, and
     the prose type steps down so it is comfortable, not shrunk. */
  .np-cats{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;
    gap:8px;margin:0 0 20px;padding-bottom:2px}
  .np-cats::-webkit-scrollbar{display:none}
  .np-pill{font-size:13.6px;padding:9px 15px}

  .np-grid{grid-template-columns:1fr;gap:16px}
  .np-body{padding:14px 16px 16px}
  .np-h{font-size:18.4px}
  .np-ex{font-size:14.4px}
  .np-promo{padding:20px 17px 18px}
  .np-p-h{font-size:19px}
  .np-more{margin-top:30px}
  .np-more .btn{width:100%;min-width:0}

  /* featured card */
  .bfeat .np-h{font-size:21px}
  .bfeat .bf-body{padding:17px 15px 19px}
  .bfeat .np-ex{font-size:14.6px}

  /* article */
  .article{padding:4px 0 32px}
  .article-head{margin:14px 0 18px}
  /* the byline holds ONE line on a phone: avatar, name, date, read time.
     The job title is the thing that goes, it is already in the schema. */
  .art-by{gap:9px;margin-top:15px;padding-top:13px;flex-wrap:nowrap}
  .art-by .np-av{width:38px;height:38px}
  .art-by .np-name{font-size:13.2px}
  .art-by .np-job{display:none}
  .art-by-meta{gap:10px;min-width:0;flex:none}
  .art-by-meta .np-date,.art-by-meta .np-read{font-size:9.4px;letter-spacing:.03em;gap:5px}
  .art-by-meta .np-i{width:11px;height:11px}
  .art-by .d-lg{display:none}
  .art-by .d-sm{display:inline}
  .article-answer{padding:18px 17px}

  /* DP, 2026-07-25: on a phone the "On this page" bar is shut by default and
     people scrolled straight past it. While it is SHUT it breathes a green
     ring, gives an occasional wobble and bobs its caret, so it reads as a
     thing you can tap. The moment it opens, aria-expanded flips to true, the
     :has() below stops matching and the bar goes completely still. */
  .toc:has(.toc-toggle[aria-expanded="false"]){
    border-color:var(--accent);
    animation:toc-pulse 2.3s var(--ease) infinite, toc-wobble 6s var(--ease) infinite}
  @keyframes toc-pulse{
    0%,100%{box-shadow:0 0 0 0 var(--accent-glow)}
    55%{box-shadow:0 0 0 9px transparent}
  }
  @keyframes toc-wobble{
    0%,86%,100%{transform:none}
    89%{transform:rotate(-.55deg)}
    92%{transform:rotate(.55deg)}
    95%{transform:rotate(-.28deg)}
  }
  .toc-toggle[aria-expanded="false"]{color:var(--accent)}
  .toc-toggle[aria-expanded="false"] .toc-caret{animation:toc-bob 1.5s var(--ease) infinite}
  @keyframes toc-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(3px)}}
  /* nobody should get a wobbling box if they asked the phone to calm down */
  @media (prefers-reduced-motion:reduce){
    .toc:has(.toc-toggle[aria-expanded="false"]){animation:none;box-shadow:0 0 0 3px var(--accent-soft)}
    .toc-toggle[aria-expanded="false"] .toc-caret{animation:none}
  }
  .article-answer .answer-lead{font-size:17.3px}
  .prose{font-size:17.3px;line-height:1.72}
  .prose>*+*{margin-top:19px}
  .prose h2{margin-top:36px}
  .prose-cta{padding:20px 18px;gap:14px}
  .prose-cta .btn{flex:1 1 100%}
  .takeaways{padding:18px 17px}
  .prose-note{padding:16px 16px}
  .archive-list .ar-t{font-size:15.8px}

  /* Article tables stay TABLES on a phone (DP, 2026-07-23): the box keeps its
     card frame and the grid scrolls sideways inside .table-scroll when it is
     wider than the screen. Compact type keeps the rows short instead of the
     old stacked-card layout that ate vertical space. */
  .prose-table .tw-head{padding:13px 16px;font-size:10.4px;letter-spacing:.12em}
  .prose-table .table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .prose-table table.price-table{min-width:480px}
  .prose-table th{padding:10px 12px;font-size:9.8px;letter-spacing:.1em}
  .prose-table td{padding:10px 12px;font-size:13.2px;white-space:normal}
  .prose-table td:last-child{font-size:12.1px}
}
@media (max-width:380px){
  /* the mark swaps with the theme: white art on dark, navy art on light,
   exactly the guidelines' logo usage rules */
.logo-on-dark{display:block}
.logo-on-light{display:none}
[data-theme="light"] .logo-on-dark{display:none}
[data-theme="light"] .logo-on-light{display:block}
.brand .b-name{font-size:14.4px}
  .brand .b-sub{font-size:8.8px}
  .stepper .count{font-size:44px;min-width:74px}
}


/* ---------- handwritten aside (Caveat), the DP wink ----------
   On dark it runs pale yellow. On white, yellow lettering is unreadable, so it
   drops to deep bronze: same hue family, actual contrast. */
.hand{font-family:"Caveat",cursive;font-size:21px;font-weight:500;color:var(--accent-2);letter-spacing:0;transform:rotate(-1.6deg);display:inline-block;line-height:1.3}
[data-theme="light"] .hand{color:#2E6BD3}


/* ---------- author byline is now a link to the Dr. Ronak Patel profile ----------
   The name element was a <span>; it is an <a> from v15 so every article credits
   one canonical Person entity. It has to stay display:block or the ellipsis
   truncation that keeps the byline on one phone line stops working. */
a.np-name{display:block;text-decoration:none;color:var(--text-1);
  transition:color var(--t-fast) var(--ease)}
a.np-name:hover,a.np-name:focus-visible{color:var(--accent)}

/* ---------- explanatory in-article image ----------
   Used only where a picture teaches something a paragraph cannot: an exercise
   position, an anatomical region, a recovery setup. Never decoration, so it
   gets a real caption and reads as content, not as a banner. */
.prose-fig{margin:26px 0;border:1px solid var(--line);border-radius:var(--r-lg,18px);
  overflow:hidden;background:var(--card-grad)}
.prose-fig img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover}
.prose-fig figcaption{padding:12px 16px;font-size:13.6px;line-height:1.55;
  color:var(--text-3);border-top:1px solid var(--line-soft)}
@media (max-width:720px){
  .prose-fig{margin:20px 0}
  .prose-fig figcaption{padding:10px 13px;font-size:12.8px}
}


/* ════════════════════════ TYPE LIFT ════════════════════════
   Standing order (DP, 2026-07-26): type starts around 125%, small caps mono
   labels never go below 13px, and text is never crowded. The card language
   above is proven and stays untouched, so the lift lives HERE as an additive
   override block. Delete this block and the site returns to the old scale.

   Floors applied: body 20px, article prose 20.5px, card copy 16.5px, every
   mono label 13px, prose measure capped near 70ch.
   ═══════════════════════════════════════════════════════════ */
body{font-size:20px}

/* the reading surface */
.prose{font-size:20.5px;line-height:1.75}
.prose>*+*{margin-top:24px}
.prose p{max-width:70ch}
.prose h2{font-size:clamp(28px,3.4vw,38px);margin-top:50px}
.prose h3{font-size:23px;margin-top:34px}
.prose-ul li,.prose-ol li{line-height:1.68}
.prose-quote{font-size:24px}
.prose-note p{font-size:17.5px}
.takeaways li{font-size:18px;line-height:1.6}
.article-answer .answer-lead{font-size:21.5px;line-height:1.64}
.article-head h1{font-size:clamp(34px,5vw,58px)}
.article-head .art-sub,.article-head p{font-size:19px}
.toc-list a{font-size:17px}
.prose-cta strong{font-size:21.5px}
.prose-cta p{font-size:16.5px}
.article-faq>h2{font-size:clamp(28px,3.4vw,38px)}

/* the card grid on the blog index */
.np-h{font-size:20.5px}
.np-ex{font-size:16.5px;line-height:1.55}
.np-name{font-size:14px}
.np-job{font-size:12.5px}
.bfeat .np-h{font-size:26px}
.bfeat .np-ex{font-size:17px}
.np-p-h{font-size:22px}
.np-promo p{font-size:16.5px}
.np-empty{font-size:18px}

/* MONO LABEL FLOOR: 13px, never smaller. Small caps mono under 13px was the
   exact thing DP called out, so every label on a reading surface is listed. */
.np-cat,.np-read,.np-date,.np-count,.np-p-k,
.crumbs,.eyebrow,.sec-kicker,.brand .b-sub,
.article-answer .aa-k,.toc-toggle,.toc-list a::before,
.prose-note .pn-t,.takeaways .tk-t,.prose-cta .pc-k,
.side-card .side-k,.proof-note,.kb-count,.gpt-head .gh-s,
.gpt-side h3,.site-foot h4,.foot-bottom,.stat .label{font-size:13px}
.prose-ol li::before{font-size:13px}

/* do not crowd the text: more air inside every card at this scale */
.np-body{padding:18px 20px 20px}
.takeaways{padding:24px 26px}
.prose-note{padding:20px 22px}

@media (max-width:720px){
  body{font-size:18.5px}
  .prose{font-size:19px}
  .prose h2{font-size:clamp(25px,6.4vw,30px)}
  .prose h3{font-size:21px}
  .article-answer .answer-lead{font-size:19.5px}
  .np-h{font-size:19px}
  .np-ex{font-size:15.5px}
  .bfeat .np-h{font-size:22px}
  /* the mono floor relaxes by half a point on a phone, and no further */
  .np-cat,.np-read,.np-date,.crumbs,.eyebrow,.sec-kicker{font-size:12.5px}
}


/* ════════════════════════ WORDMARK ════════════════════════
   DP, 2026-07-26: the logo runs in the VaynerMedia lockup. One word, no gap,
   all caps, heavy first half against a light second half. Monochrome on
   purpose: it takes --text-1, so it is near-white on the dark theme and
   near-black on the light one, and the yellow stays for accents only.
   ═════════════════════════════════════════════════════════ */
.brand .wm{
  display:inline-block;
  font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;
  font-size:23px;
  font-weight:400;
  letter-spacing:-.012em;
  text-transform:uppercase;
  color:var(--text-1);
  line-height:1;
  white-space:nowrap;
  transition:opacity var(--t-fast) var(--ease);
}
.brand .wm b{font-weight:800;letter-spacing:-.026em}
.brand:hover .wm{opacity:.72}
.site-foot .brand .wm{font-size:21px}
@media (max-width:720px){
  .brand .wm{font-size:20px}
  .site-foot .brand .wm{font-size:19px}
}


/* ════════════════════ READABILITY PASS (DP, 2026-07-26) ════════════════════
   Five asks, in one additive block so it stays reversible:
     1. Titles heavier.
     2. Short-answer box matches body size (it was a point bigger for no reason).
     3. More left and right padding everywhere.
     4. Tables STACK on a phone. No sideways scrolling, ever.
     5. (gradients were removed higher up, in the .ambient block)
   ═══════════════════════════════════════════════════════════════════════════ */

/* ---- 1. titles heavier ---- */
.article-head h1{font-weight:800;letter-spacing:-.038em}
.page-hero h1{font-weight:800;letter-spacing:-.038em}
.hero h1{font-weight:800;letter-spacing:-.038em}
.sec-head h2{font-weight:780;letter-spacing:-.034em}
.prose h2{font-weight:780;letter-spacing:-.032em}
.prose h3{font-weight:750}
.article-faq>h2{font-weight:780}
.np-h{font-weight:780;letter-spacing:-.026em}
.bfeat .np-h{font-weight:800;letter-spacing:-.03em}
.np-p-h{font-weight:800}
.gcard h3,.step h3,.fitcard h3,.side-card strong{font-weight:780}
.band h2{font-weight:800;letter-spacing:-.036em}
/* the italic hook word keeps its light weight on purpose, that contrast is the
   whole point of the lockup. Do not bold it with the rest. */
h1 em,h2 em,h3 em,.it{font-weight:300}

/* ---- 2. the short answer reads at body size ---- */
.article-answer .answer-lead{font-size:20.5px;line-height:1.7}
@media (max-width:720px){.article-answer .answer-lead{font-size:19px}}

/* ---- 3. more breathing room left and right ---- */
.wrap{width:min(1180px,calc(100% - 56px))}
@media (min-width:721px){.wrap{width:min(1180px,calc(100% - 88px))}}
@media (max-width:720px){.wrap{width:calc(100% - 48px)}}
/* cards get more inside padding at the same time, otherwise a wider gutter just
   moves the crowding one layer in */
.np-body{padding:20px 22px 22px}
.takeaways{padding:26px 28px}
.prose-note{padding:22px 24px}
.gcard,.step,.side-card{padding:24px 26px}
@media (max-width:720px){
  .np-body{padding:18px 19px 20px}
  .takeaways{padding:22px 22px}
  .prose-note{padding:19px 20px}
  .gcard,.step,.side-card{padding:21px 21px}
}

/* ---- 4. TABLES STACK ON A PHONE ----
   The old behaviour forced a 480px min-width and let the box scroll sideways,
   so on a 375px screen the last column was off-screen and people had to drag.
   Below 720px every row becomes its own block: the first cell is the row title,
   and each remaining cell prints its column header from data-label beside the
   value. Nothing is hidden and nothing scrolls. The generator already emits
   data-label on every td, so this needs no content changes. */
@media (max-width:720px){
  .prose-table .table-scroll{overflow-x:visible}
  .prose-table table.price-table{min-width:0;width:100%;display:block}
  .prose-table .price-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .prose-table .price-table tbody,
  .prose-table .price-table tr{display:block;width:100%}
  .prose-table .price-table tr{
    padding:14px 16px;
    border-bottom:1px solid var(--line);
  }
  .prose-table .price-table tr:last-child{border-bottom:0}
  .prose-table .price-table td{
    display:flex;
    align-items:baseline;
    justify-content:space-between;
    gap:14px;
    width:100%;
    padding:5px 0;
    border:0;
    font-size:15.5px;
    text-align:right;
    white-space:normal;
  }
  /* first cell in a row is the row's own title: full width, no label, bolder */
  .prose-table .price-table td:first-child{
    display:block;
    text-align:left;
    font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;
    font-size:16.5px;
    font-weight:750;
    color:var(--text-1);
    padding-bottom:9px;
    margin-bottom:5px;
    border-bottom:1px solid var(--line-soft);
  }
  .prose-table .price-table td:first-child::before{content:none}
  /* every other cell prints its column header on the left */
  .prose-table .price-table td::before{
    content:attr(data-label);
    flex:0 0 auto;
    text-align:left;
    font-family:"JetBrains Mono",monospace;
    font-size:13px;
    font-weight:600;
    letter-spacing:.1em;
    text-transform:uppercase;
    color:var(--text-3);
  }
  /* a header-less column would leave a dangling colon, so hide the label slot */
  .prose-table .price-table td[data-label=""]::before{content:none}
  .prose-table .price-table td:last-child{
    font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;
    font-size:15.5px;
    font-weight:600;
    color:var(--text-1);
  }
  .prose-table .tw-head{font-size:13px;letter-spacing:.14em;padding:14px 16px}
}

/* ==========================================================================
   FEATURED CARD MOBILE OVERFLOW FIX (2026-07-27)
   Additive. Deletes cleanly, does not restructure the card components above.

   THE BUG. `.bfeat` is `grid-template-columns:1fr`, and `1fr` is shorthand for
   `minmax(auto, 1fr)`. That `auto` minimum is the track's min-content width, so
   a child that cannot shrink (here the `.np-top` row: category label plus read
   time, laid out with flex and no wrapping) pushes the track WIDER than the
   card itself. On a 375px screen the track resolved to ~374px inside a 327px
   card. `.bfeat` has `overflow:hidden`, so instead of a horizontal scrollbar
   the title was silently clipped mid-word and the page-level
   `scrollWidth === clientWidth` check still passed. That is why this survived
   the earlier mobile pass: nothing overflowed the PAGE, the card clipped itself.

   THE FIX. `minmax(0,1fr)` lets the track shrink to the container and
   `min-width:0` stops the text children re-inflating it. The meta row is left
   alone: it already ellipsises correctly by itself. Verified at a true 375px in both themes:
   track 325px inside a 327px card, zero elements past the right edge.
   ========================================================================== */
.bfeat{grid-template-columns:minmax(0,1fr)}
.bfeat .np-h,
.bfeat .np-ex{min-width:0;overflow-wrap:anywhere}

/* NOTE (2026-07-27): an earlier version of this fix also set
   `.bfeat .np-top{flex-wrap:wrap}`. That was wrong and DP spotted it on his
   phone: it pushed "7 MIN READ" onto its own orphan line under the category,
   which desktop never did. It was never needed. The real overflow cause was the
   grid track above, and the base `.np-cat` already carries min-width:0 with
   ellipsis while `.np-read` is flex:none, so the row shrinks correctly on its
   own. Category and read time share one line at every width, as designed. */

@media (min-width:860px){
  /* the two-column desktop layout is unchanged, just made shrink-safe */
  .bfeat{grid-template-columns:minmax(0,1.1fr) minmax(0,1fr)}
}

/* ==========================================================================
   AUTHOR BYLINE: REAL PHOTO + ROLE UNDER THE NAME (DP, 2026-07-27)
   Additive. Deletes cleanly.

   DP asked for his actual photo as the author image and for his role to sit
   under his name with proper padding. The role string itself lives in
   scripts/build-blog.mjs as AUTHOR_ROLE, not here.

   Two things were in the way. The role was set to a different string in the
   generator (fixed there, not here), and `.art-by .np-job{display:none}` hid it
   entirely below 720px because the original rule was that the article byline
   must hold ONE ROW on a phone. That rule still holds: `.np-who` is a flex
   COLUMN, so showing the role makes that one column two lines tall, it does not
   add a second row to the byline. The avatar simply grows to match.
   ========================================================================== */
.np-who{gap:2px}
.np-av{background:#FCD200}   /* matches the photo's own backdrop exactly, so the circle never flashes a different colour while it loads */

/* THE AVATAR IS PRE-COMPOSED, DO NOT RE-CROP IT (DP, 2026-07-27).
   DP asked that the circle show his smiling face AND the pointing hand, with
   nothing chopped. A circle only reveals the disc inscribed in the square, so
   the source was padded rather than cropped: the must-show region (full head
   from the hair down, plus the whole hand) was centred on a square canvas big
   enough that the region's DIAGONAL fits inside the circle, and the remainder
   filled with the photo's own backdrop #FCD200. The file is therefore already
   square and already safe. Keep `object-fit:cover` on a square box, which
   crops nothing, and never add a tighter crop or a zoom here. */

@media (max-width:720px){
  /* the role comes back on phones, with the padding DP asked for */
  .art-by .np-job{display:block;font-size:10.8px;line-height:1.3;margin-top:1px}
  .art-by{align-items:center}
  .art-by .np-av{width:42px;height:42px}
  /* the meta column must not squeeze the name now that the column is taller */
  .art-by-meta{flex-wrap:wrap;justify-content:flex-end;row-gap:2px}
}

@media (max-width:400px){
  /* tightest phones: keep the role, drop the read time instead. The role is
     brand, the read time is a nicety and it is still in the schema. */
  .art-by-meta .np-read{display:none}
}


/* ==========================================================================
   ASK DP AVATAR (DP, 2026-07-27)
   The assistant answers in the first person as him, so the bubble carries his
   photo instead of the letters "AI". The image is pre-cropped square and
   face-centred, so `cover` on a square box crops nothing further. The gradient
   stays as the loading colour underneath and as the visitor's own chip.
   ========================================================================== */
.gpt-msg .gm-av{overflow:hidden;padding:0}
.gpt-msg .gm-av img{width:100%;height:100%;object-fit:cover;display:block;border-radius:50%}


/* ==========================================================================
   BLOG SEARCH (DP, 2026-07-27)
   Additive block. Search sits in the SAME row as the topic pills and narrows
   the same grid, live, as you type. Nothing here restructures the existing
   .np-cats or .np-pill components: .np-cats simply becomes a flex child of a
   new .np-toolbar wrapper, and every pill rule still applies unchanged.
   Delete this block and the ONE `.np-toolbar` wrapper in build-blog.mjs and
   the old row returns exactly as it was.
   ========================================================================== */
.np-toolbar{display:flex;align-items:flex-start;gap:16px;margin:0 0 28px}
/* the pills keep their own wrapping and give up width to the field last */
.np-toolbar .np-cats{flex:1 1 auto;min-width:0;margin:0}
/* 340px is not arbitrary: it is the width at which the placeholder sentence
   stops truncating at 14.4px. A clipped prompt reading "Try meta ad..." looks
   broken, so the field is sized to its own copy. */
.np-search{position:relative;flex:0 0 340px;display:flex;align-items:center}
.np-search .np-s-i{position:absolute;left:15px;width:17px;height:17px;
  color:var(--text-3);pointer-events:none;transition:color var(--t-fast) var(--ease)}
.np-search input{width:100%;min-height:44px;appearance:none;
  font-family:inherit;font-size:14.4px;font-weight:500;color:var(--text-1);
  background:var(--card-grad);border:1px solid var(--line);border-radius:100px;
  padding:10px 40px 10px 41px;
  transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease)}
.np-search input::placeholder{color:var(--text-3);
  /* the placeholder is a full sentence and the field is narrow, so let it
     truncate rather than clip mid-letter */
  text-overflow:ellipsis}
.np-search input:hover{border-color:var(--line-strong)}
.np-search input:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft)}
.np-search input:focus + .np-s-x{color:var(--text-2)}
.np-search:focus-within .np-s-i{color:var(--accent)}
/* Safari draws its own clear button on type=search and it lands on top of ours */
.np-search input::-webkit-search-cancel-button,
.np-search input::-webkit-search-decoration{-webkit-appearance:none;appearance:none}
.np-s-x{position:absolute;right:6px;display:flex;align-items:center;justify-content:center;
  width:32px;height:32px;border:0;border-radius:50%;background:none;cursor:pointer;
  color:var(--text-3);font-size:13px;line-height:1;
  transition:color var(--t-fast) var(--ease),background var(--t-fast) var(--ease)}
.np-s-x:hover{color:var(--accent);background:var(--field-bg)}

/* Tablet down: the field takes the full width and sits UNDER the pills, so the
   pill row never gets squeezed into a two-line stub next to a tiny input. */
@media (max-width:900px){
  .np-toolbar{flex-direction:column;gap:12px}
  .np-toolbar .np-cats{width:100%}
  .np-search{flex:1 1 auto;width:100%}
}

/* Phone: the placeholder sentence does not fit in 375px, so ui.js swaps in a
   short one. Type stays at 16px because anything smaller makes iOS zoom the
   whole page the moment the field takes focus. */
@media (max-width:720px){
  .np-search input{font-size:16px}
}


/* ==========================================================================
   ACTIVE NAV PILL, STRENGTHENED (DP, 2026-07-27)
   Additive block. Delete it and the original faint pill returns.

   The pill already existed and shipped on every page. The problem was that it
   barely read as anything in LIGHT theme: `background:var(--glass)` is #FFFFFF,
   which is the same white as the bar behind it, so the only thing marking the
   current page was a 12% hairline. It looked like an outline, not the "circular
   box" it is meant to be. Dark theme was already fine, so it is left nearly
   alone and only gains a touch of edge.

   The fix is separation, not decoration: a fill that differs from the bar, a
   border you can actually see, and full-strength ink.
   ========================================================================== */
.navlinks a.on{
  color:var(--text-1);
  border-color:var(--line-strong);
  background:var(--glass-hi);
  font-weight:700;
}
[data-theme="light"] .navlinks a.on{
  /* a real fill against the white bar, plus a soft lift so the box has depth */
  background:#F1F1EC;
  border-color:rgba(10,10,10,.22);
  box-shadow:0 1px 2px rgba(10,10,10,.06);
}
/* hover must still out-rank the active state, or the current page feels dead */
.navlinks a.on:hover{border-color:var(--accent);color:var(--accent)}

/* The phone menu is a stacked sheet, not a bar, so a pill there reads oddly.
   It keeps the existing soft rectangle and only gains a clearer edge. */
@media (max-width:900px){
  .navlinks a.on{border-radius:12px;background:var(--accent-soft);color:var(--accent);border-color:var(--line-strong)}
  [data-theme="light"] .navlinks a.on{background:var(--accent-soft);color:var(--accent-ink);box-shadow:none}
}


/* ==========================================================================
   CENTRED PAGE HEROES (DP, 2026-07-27, extended to about + work-with-me 2026-07-28)
   Additive block. Remove it plus the `hero-centred` and `h1-3a` classes in
   the pages and the old left-aligned heroes return.

   THE PROBLEM DP REPORTED: the home hero was left aligned while every section
   under it is centred, so the page changed its mind halfway down and the eye
   had to reset. Fixing it by centring the hero rather than left-aligning the
   rest, because the rest of the page is already consistent.

   SCOPED BY CLASS, NOT BY ELEMENT. `.page-hero` is shared by every page hero.
   Only the pages carrying `.hero-centred` move, which is now home, about and
   work-with-me. The BLOG hero stays left aligned on purpose: it sits above a
   left-aligned toolbar and card grid, so centring it would create the same
   mismatch this block exists to remove.

   THE HEADLINE is the 3A thesis, so it now reads as three rows with the three
   A-words carrying the weight and the accent. That is the whole positioning in
   one glance instead of a paragraph that happens to wrap.
   ========================================================================== */
.hero-centred{text-align:center}
.hero-centred .lead{margin-left:auto;margin-right:auto}
.hero-centred .hero-ctas{justify-content:center}

/* CENTRE THE BOXES, NOT JUST THE TEXT. This is the bit that was wrong on the
   first pass and DP spotted it: `text-align:center` centres the words INSIDE
   each block, but `.page-hero h1` and `.page-hero .lead` carry `max-width`, so
   those blocks were still sitting hard left inside a wider wrap. The headline
   therefore centred on its own 900px box and landed about 140px left of the
   lead and the buttons, which is exactly the awkward look he described.
   `.hero-centred h1` beats `.page-hero h1` on specificity, so the auto margins
   here actually apply. Do not drop the selector back to `.h1-3a`, which loses
   to `.page-hero h1` and silently reintroduces the offset. */
.hero-centred h1,
.hero-centred .lead{margin-left:auto;margin-right:auto}

/* one clause per row, so the three A's stack instead of wrapping at random */
.h1-3a{font-weight:500}
.h1-3a span{display:block}
/* the three words that carry the thesis. Gradient text, which is the site's
   accent treatment: signal yellow on dark, near-black on light. */
.h1-3a b{font-weight:800;
  background:var(--grad);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent}

/* Phones: DP asked for everything centred here too, and the stacked full-width
   buttons already centre themselves. Tighten the line spacing a touch, because
   three short rows at the phone size otherwise read as a gappy list. */
@media (max-width:720px){
  .hero-centred h1{line-height:1.14}
  .hero-centred .eyebrow{margin-left:auto;margin-right:auto}
}

/* LIGHT THEME FIX for the three A-words, caught on the first render.
   `--grad` is a yellow gradient on dark, which is why AI / Automation / Ads
   glow there. In LIGHT it is `#0A0A0A -> #6A6A64`, so each emphasised word
   FADED OUT TO GREY while the plain words next to it stayed solid black. The
   emphasis was pointing the wrong way: the three words that carry the whole
   thesis looked weaker than "to build".
   Light therefore drops the gradient entirely: solid full-strength ink on the
   three words, and the rest of the line steps back to secondary. Dark keeps the
   gradient, because there it genuinely reads as the accent. */
[data-theme="light"] .h1-3a{color:var(--text-2)}
[data-theme="light"] .h1-3a b{
  background:none;-webkit-background-clip:border-box;background-clip:border-box;
  color:var(--text-1);-webkit-text-fill-color:var(--text-1)}


/* ==========================================================================
   HOME HERO, EMOTION FIRST (DP, 2026-08-10)
   Additive. Delete this block and put the `h1-3a` classes back on the home h1
   to restore the previous hero exactly.

   The three A's used to BE the h1. They are the mechanism, not the promise, so
   a founder read the homepage and learned what we do rather than what they get
   to stop feeling. The h1 is now the outcome, and the thesis moves one step
   down into its own line, still the loudest thing after the headline.

   Type: deliberately larger than `.lead` and smaller than the h1, so the page
   reads promise, then thesis, then who it is for. The bold-word treatment is
   copied from `.h1-3a` unchanged, INCLUDING the light-theme override, because
   the gradient is the ink on those three words and its palest stop is what has
   to stay readable. Do not "simplify" light back to the gradient.
   ========================================================================== */
.thesis-3a{
  font-weight:500;font-size:clamp(17.5px,2.3vw,23px);line-height:1.4;
  letter-spacing:-.015em;margin:16px auto 0;max-width:760px;color:var(--text-2)}
.thesis-3a b{font-weight:800;
  background:var(--grad);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent}
[data-theme="light"] .thesis-3a b{
  background:none;-webkit-background-clip:border-box;background-clip:border-box;
  color:var(--text-1);-webkit-text-fill-color:var(--text-1)}
/* the lead is now the third line, so it steps back rather than competing */
.page-hero .thesis-3a + .lead{margin-top:14px}


/* ==========================================================================
   FILLED-CARD PILL, CONTRAST FIX (DP, 2026-07-28)
   Additive block. Delete it and the old white pill returns.

   `.gcard.fill-card .g-price` was set to `color:#FFFFFF`, i.e. white text on
   the signal-yellow card. Measured against the card's own gradient that is
   1.27:1 to 1.88:1, where the accessible minimum for small text is 4.5:1. It
   was effectively unreadable, and DP spotted it.

   It was also the ONE element inside a filled card not following the rule the
   rest of the block already sets: everything on the yellow card takes
   `--fill-ink` / `--fill-muted`, which is near-black. Black on that same
   gradient measures 10.6:1 to 15.6:1.

   The pill keeps its shape. Only the ink and the tint flip from white to dark,
   so it now reads as a chip stamped ON the yellow rather than a ghost floating
   over it.
   ========================================================================== */
.gcard.fill-card .g-price{
  color:var(--fill-ink);
  border-color:rgba(0,0,0,.26);
  background:rgba(0,0,0,.07);
}


/* ==========================================================================
   IN-ARTICLE FIGURES, the illustrated-guide format (2026-07-28)
   Additive block. Delete it and articles return to the old figure styling,
   which is still sitting further up this file. Nothing here is destructive.

   WHY IT WAS NEEDED
   `.prose-fig img` was written for stock photography and carried
   `aspect-ratio:16/9;object-fit:cover`. Every picture in this new format is a
   SCREENSHOT of a real product page, and the source shots are 3200x2040, which
   is 1.57:1, not 1.78:1. Under the old rule the browser cropped roughly 11% off
   the top and bottom of every one of them, which on a screenshot means slicing
   the header off the app. The image now keeps its own shape.

   THE FRAME IS THE POINT
   These are dark screenshots and the site's DEFAULT theme is near-black. With
   no frame a dark screenshot bleeds into the page and stops reading as a
   picture. So there is a visible border, a rounded corner and a small inner
   inset ring, which also stops the black plate from touching the caption bar.
   On light the same frame reads as a card, and the shadow is only turned on
   there because a shadow under black on black is invisible work.

   PHONE SHOTS
   `.fig-phone` is a portrait screenshot (roughly 1:2). At full column width one
   would be over 1,400 pixels tall and push the next paragraph off the screen,
   so it is capped and centred on its own plate.
   ========================================================================== */
.prose-fig{
  margin:34px 0;
  background:var(--card-grad);
  border:1px solid var(--line);
  border-radius:16px;
  overflow:hidden;
}
[data-theme="light"] .prose-fig{box-shadow:0 6px 22px rgba(10,10,10,.07)}

/* The crop override: real shape, no cover. The RATIO IS NOT SET HERE. The
   generator writes `style="aspect-ratio:W/H"` on every figure image instead,
   because `aspect-ratio:auto` in a stylesheet also discards the ratio the
   browser derives from the width and height attributes, which collapses every
   lazy image to a one pixel box until it loads. Do not add a ratio back here. */
.prose-fig img{
  display:block;
  width:100%;
  height:auto;
  object-fit:fill;
  border-bottom:1px solid var(--line-soft);
}

/* the caption is content, not a label, so it gets read-able type and sits on a
   slightly recessed bar so it never looks like part of the screenshot */
.prose-fig figcaption{
  padding:13px 18px 14px;
  font-size:14.5px;
  line-height:1.6;
  color:var(--text-3);
  border-top:0;
}

/* portrait phone screenshot. The plate is padded so the phone floats rather
   than filling the frame edge to edge. */
.prose-fig.fig-phone{
  padding:22px 0 0;
  text-align:center;
}
/* width is set, not `auto` with a max-width. On a replaced element `width:auto`
   resolves to the NATURAL width, which is zero until the file arrives, so a
   lazy phone shot would reserve nothing and the page would jump when it landed. */
.prose-fig.fig-phone img{
  width:min(300px,72%);
  margin:0 auto;
  border-bottom:0;
  border-radius:12px;
}
.prose-fig.fig-phone figcaption{
  margin-top:20px;
  border-top:1px solid var(--line-soft);
  text-align:left;
}

@media (max-width:720px){
  .prose-fig{margin:26px 0;border-radius:13px}
  .prose-fig figcaption{padding:11px 14px 12px;font-size:13.6px}
  .prose-fig.fig-phone{padding:16px 0 0}
  .prose-fig.fig-phone img{width:min(230px,66%)}
}


/* ==========================================================================
   CONTRAST SWEEP, BOTH THEMES (DP, 2026-07-28)
   Additive block. Delete it and the old values return. Nothing is restructured.

   DP reported one instance: the CURRENT PAGE in the phone menu was yellow text
   on a pale yellow fill and unreadable. He then asked for the same class of
   error to be found everywhere rather than patched where it was visible, so
   every page was measured in both themes, at desktop and phone width, with the
   menu, the topic sheet and the table of contents opened. Thirty one distinct
   failures came back and they had exactly TWO causes, both fixed here.

   ------------------------------------------------------------------ CAUSE 1
   `--text-3`, the muted ink, failed the AA minimum for small text in BOTH
   themes. Measured against the surfaces it actually sits on:
     light  #8C8C86 on #FAFAF7  =  3.23:1   (needs 4.5)
     dark   #6E6E66 on #131313  =  3.61:1   (needs 4.5)
   It carries dates, read times, the author role, table headers, breadcrumbs,
   result counts, figure captions and the footer line, so this was most of the
   small print on the site sitting under the line. The new values measure 4.8:1
   and 5.3:1 against those same worst-case surfaces, and still read as clearly
   secondary next to `--text-2`.

   Muted is a HIERARCHY, not a licence to be unreadable. If you retune these,
   measure against the CARD colour, not the page colour: the card is the paler
   surface on light and the lighter one on dark, so it is always the worse case.

   ------------------------------------------------------------------ CAUSE 2
   `.navlinks a.on` on light, in the phone menu. It set `color:var(--accent-ink)`
   on a `--accent-soft` background. That looks reasonable until you read what
   the token is FOR: `--accent-ink` is the ink that sits ON the accent, and on
   light the accent is a BLACK button, so `--accent-ink` is yellow lettering.
   Used as text on a pale yellow fill it measured 1.30:1. This is the same
   mistake as the filled-card price pill above: a token named for one job used
   in another. The rule now takes `--text-1`, which is 16:1 on that fill.
   ========================================================================== */
/* THE BLUE RESKIN RE-TUNED THESE, 2026-07-29. They were #82827A / #6F6F6A,
   warm greys chosen to clear AA against the Gold-Noir card. The new cards are
   cooler and slightly different in value, and these are what carry dates, read
   times, the author role, captions and the footer, so they were re-measured
   rather than assumed. NOTE FOR ANYONE EDITING THE TOKEN BLOCKS AT THE TOP:
   this block overrides them, which is why a change up there appeared to do
   nothing. Change it HERE. */
:root{ --text-3:#8E939C; }
[data-theme="light"]{ --text-3:#69707C; }

@media (max-width:900px){
  [data-theme="light"] .navlinks a.on{color:var(--text-1)}
}


/* ==========================================================================
   THE BOOKING FLOW: /book, /thank-you, /a-message-from-pratik (2026-07-28)
   Additive block. Delete it plus the three pages and nothing else notices.

   DP asked for a native booking surface so calldp.com/book is no longer a
   separate site. Three pages share this block:
     book.html                   the VSL plus the eight qualifying questions
     thank-you.html              after the request, with the locked priority CTA
     a-message-from-pratik.html  where the polite-no email sends people

   The whole design brief for these is FEWER DECISIONS. One hook, one video,
   one button, then a form where seven of the eight questions are a single tap.
   ========================================================================== */

/* ---------------------------------------------------- the VSL hero ---- */
.vsl-hero{padding:56px 0 76px;text-align:center}
.vsl-hero h1{font-size:clamp(30px,5.2vw,52px);font-weight:800;letter-spacing:-.035em;line-height:1.08;
  margin:16px auto 0;max-width:16ch}
/* Emphasised words in a heading inherit a gradient-text treatment elsewhere in
   this stylesheet (background-image + background-clip:text). On this hero the
   em is the quiet half of the sentence, not the loud half, so the gradient is
   switched off EXPLICITLY rather than left to whichever rule happens to win on
   specificity. Relying on that has broken this codebase before. */
.vsl-hero h1 em{font-style:italic;font-weight:500;
  background:none;-webkit-background-clip:border-box;background-clip:border-box;
  color:var(--text-2);-webkit-text-fill-color:var(--text-2)}
.vsl-hero .lead{margin:18px auto 0;max-width:62ch;font-size:clamp(16.5px,2vw,19.5px);color:var(--text-2);line-height:1.62}
.vsl-hero .eyebrow{margin-left:auto;margin-right:auto}

/* the video. It is the point of the page, so it gets the width and a real
   frame rather than sitting loose on the background. */
.vsl-video{margin:34px auto 0;max-width:820px}
.vsl-video .vid-open{width:100%;display:block;padding:0;background:none;border:0;cursor:pointer}
.vsl-video .vid-thumb{display:block;position:relative;border-radius:18px;overflow:hidden;
  border:1px solid var(--line);background:var(--card-grad)}
.vsl-video img{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover}
[data-theme="light"] .vsl-video .vid-thumb{box-shadow:0 18px 44px -20px rgba(10,10,10,.4)}

.vsl-cta{margin:30px auto 0}
.vsl-cta .btn{min-width:min(320px,86vw)}
.vsl-note{margin:14px auto 0;font-size:14.6px;color:var(--text-3);max-width:44ch}

/* ---------------------------------------------------- the form ---- */
.qsec{padding:10px 0 92px}
.qsec .sec-head{margin:0 auto 30px}
.qsec .sec-head p{max-width:58ch;margin-left:auto;margin-right:auto;color:var(--text-2)}
.qform{max-width:760px;margin:0 auto;text-align:left}
.qgroup{margin:0 0 26px}
.qlabel{display:block;font-family:"JetBrains Mono",monospace;font-size:13px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--text-2);margin:0 0 12px;line-height:1.5}
.qlabel .req{color:var(--accent);font-style:normal}
[data-theme="light"] .qlabel .req{color:#2E6BD3}
/* NAME COLLISION, CAUGHT IN TESTING. This hint was first written as
   class="opt", which is ALREADY a component in this stylesheet: a big
   selectable option card with a border, a card gradient and 16px of padding.
   A two-word hint inside a label picked all of that up and rendered as a box.
   Short generic class names in a 2,000 line stylesheet are taken. Namespace
   anything new, which is why everything on this form starts with q. */
.qlabel .qhint,.qhint{font-style:normal;font-weight:400;color:var(--text-3);
  letter-spacing:.06em;text-transform:none;border:0;padding:0;background:none}

/* the chips. A tap target, not a dropdown: a dropdown on a phone is a modal,
   a scroll and a second tap, and eight of those is why forms get abandoned. */
.qchips{display:flex;flex-wrap:wrap;gap:9px}
.qchips.col{flex-direction:column;align-items:stretch}
.qchip{appearance:none;cursor:pointer;font-family:inherit;font-size:15.6px;font-weight:600;
  color:var(--text-2);background:var(--field-bg);border:1px solid var(--line);
  border-radius:12px;padding:12px 16px;min-height:46px;text-align:left;
  transition:border-color var(--t-fast) var(--ease),color var(--t-fast) var(--ease),
    background var(--t-fast) var(--ease),transform var(--t-fast) var(--ease)}
.qchip:hover{border-color:var(--line-strong);color:var(--text-1)}
.qchip:active{transform:scale(.98)}
.qchip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* SELECTED. The filled card is the brand signature and it is identical in both
   themes on purpose, so the chosen chip borrows it: yellow panel, black ink. */
.qchip.on{background:var(--accent);color:var(--accent-ink);border-color:var(--accent);font-weight:700}
[data-theme="light"] .qchip.on{background:#2E6BD3;color:#FFFFFF;border-color:#1C4FA8}

/* a group the reader skipped */
.qchips.miss{outline:1px dashed var(--danger);outline-offset:6px;border-radius:8px}

.qdiv{height:1px;background:var(--line-soft);margin:30px 0 26px}
.field .req{color:var(--accent);font-style:normal}
[data-theme="light"] .field .req{color:#2E6BD3}

/* CONTRAST, caught by the sweep. --text-3 is tuned against the CARD colour,
   but a form field is darker still (the card plus a 5% white wash), and a
   placeholder on it measured 4.27:1 where small text needs 4.5. Placeholders
   get their own value on dark rather than moving --text-3 for the whole site,
   which is already correct everywhere else. */
[data-theme="dark"] .field input::placeholder,
[data-theme="dark"] .field textarea::placeholder{color:#8E8E86}

.qerr{margin:18px 0 0;padding:13px 15px;border-radius:12px;font-size:15px;font-weight:600;
  color:#fff;background:var(--danger);border:1px solid var(--danger)}
[data-theme="light"] .qerr{color:#fff}

.qsubmit{margin-top:22px;width:100%}
.qsubmit.is-busy{opacity:.7;pointer-events:none}
.qfoot{margin:14px 0 0;font-size:14.4px;color:var(--text-3);text-align:center}

/* ---------------------------------------------------- thank you ---- */
.ty-priority{max-width:620px;margin:40px auto 0;padding:24px 22px;text-align:left;
  background:var(--card-grad);border:1px solid var(--line);border-radius:18px}
.typ-head{display:flex;align-items:center;gap:11px;margin:0 0 10px;flex-wrap:wrap}
.typ-k{font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--accent);border:1px solid var(--line-strong);border-radius:100px;padding:4px 11px}
[data-theme="light"] .typ-k{color:#2E6BD3}
.typ-head strong{font-size:19.5px;letter-spacing:-.02em}
.ty-priority p{color:var(--text-2);font-size:16px;margin:0 0 18px;line-height:1.6}
.ty-priority .btn{width:100%}
.typ-note{font-size:14px;color:var(--text-3);margin:14px 0 0}
.typ-note strong{color:var(--text-2)}

/* THE LOCKED BUTTON. It is a real disabled <button>, not a link to a checkout
   that does not exist yet, so it cannot be clicked through to a 404. When the
   $100 payment is real, swap the element for an <a> and drop .is-locked. */
/* The locked button is DISABLED, which WCAG exempts from contrast, but the
   whole reason DP wants it visible is the price. An unreadable "$100" does no
   marketing work at all, so it is lifted to a readable value anyway. */
.btn.is-locked{
  background:var(--field-bg);
  color:var(--text-2);
  border-color:var(--line);
  box-shadow:none;
  cursor:not-allowed;
  position:relative;
}
.btn.is-locked:hover{transform:none;color:var(--text-2);border-color:var(--line)}
.btn.is-locked::after{content:"🔒";margin-left:9px;font-size:14px;filter:grayscale(1);opacity:.75}

.ty-next{max-width:620px;margin:34px auto 0;text-align:left}
.ty-next h2{font-size:21px;letter-spacing:-.02em;margin:0 0 14px}
.ty-steps{margin:0;padding:0 0 0 20px;color:var(--text-2);font-size:16.2px;line-height:1.65}
.ty-steps li{margin:0 0 9px}
.ty-steps strong{color:var(--text-1)}
.ty-meanwhile{margin:20px 0 0;color:var(--text-2);font-size:16px;line-height:1.65}

/* ------------------------------------------- a message from pratik ---- */
.nf-body{max-width:820px;margin:44px auto 0;text-align:left}
.nf-body h2{font-size:clamp(23px,3vw,30px);letter-spacing:-.025em;margin:0 0 12px}
.nf-body > p{color:var(--text-2);font-size:16.8px;line-height:1.65;margin:0 0 26px;max-width:62ch}
.nf-cards{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.nf-card{display:block;text-decoration:none;padding:20px 19px;border-radius:16px;
  background:var(--card-grad);border:1px solid var(--line);
  transition:border-color var(--t-fast) var(--ease),transform var(--t-fast) var(--ease)}
.nf-card:hover{border-color:var(--line-strong);transform:translateY(-2px)}
.nf-k{display:block;font-family:"JetBrains Mono",monospace;font-size:11.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--text-3);margin:0 0 9px}
.nf-card strong{display:block;color:var(--text-1);font-size:18.5px;letter-spacing:-.02em;line-height:1.28;margin:0 0 8px}
.nf-card p{color:var(--text-2);font-size:15.4px;line-height:1.58;margin:0 0 14px}
.nf-go{font-size:14.6px;font-weight:700;color:var(--accent)}
[data-theme="light"] .nf-go{color:var(--text-1)}

.nf-when{margin:34px 0 0;padding:24px 22px;border-radius:18px;
  background:var(--plate);border:1px solid var(--line-strong)}
.nf-when h3{font-size:20px;letter-spacing:-.02em;margin:0 0 11px}
.nf-when p{color:var(--text-2);font-size:16.2px;line-height:1.65;margin:0 0 18px}
.nf-when strong{color:var(--text-1)}

@media (max-width:720px){
  .vsl-hero{padding:36px 0 54px}
  .vsl-hero h1{max-width:none}
  .vsl-video{margin-top:26px}
  .vsl-cta .btn{width:100%}
  .qsec{padding-bottom:64px}
  .qchip{font-size:15px;padding:11px 14px;min-height:44px}
  .nf-cards{grid-template-columns:1fr}
  .ty-priority,.nf-when{padding:20px 17px}
}


/* ---------- portrait VSL frame, BUILT AND NOT YET USED (2026-07-28) ----------
   Kept ready for the moment DP supplies his OWN vertical video for /book. The
   first file he sent turned out to be another creator's Instagram reel that he
   had downloaded as reference for a different task, so nothing was published
   and the page is back on the Loom placeholder.

   When his real file arrives: transcode to H.264 (the reference file was HEVC,
   which Chrome will not play), drop it in assets/video/, and swap the
   .vid-open button on book.html for a <video class="vsl-native" preload="none"
   poster="..."> inside .vsl-video.is-portrait. preload="none" plus a poster is
   what keeps a multi-megabyte file off the initial page weight. */
.vsl-video.is-portrait{max-width:none;display:flex;justify-content:center}
.vsl-native{
  display:block;
  width:min(340px,78vw);
  height:auto;
  aspect-ratio:720/1280;
  border-radius:18px;
  border:1px solid var(--line);
  background:#000;
  object-fit:cover;
}
[data-theme="light"] .vsl-native{box-shadow:0 18px 44px -20px rgba(10,10,10,.4)}
@media (max-width:720px){
  .vsl-native{width:min(300px,80vw)}
}

/* ==========================================================================
   LINKS INSIDE AN ANSWER CARD (added 2026-07-28)

   The answer card was built for the article template, where the `answer` field
   is plain text with at most a <strong>, so it never needed link styling and
   never got any. The "In one paragraph" entity block on about.html is the first
   answer card to carry links, and without this they inherited the paragraph
   colour exactly: same colour, no underline, normal weight. Visually and to a
   screen reader they were not links at all.

   This mirrors the `.prose a` treatment already used in article bodies rather
   than inventing a second link style. Scoped to .answer-card so it cannot leak
   into anything else, and additive: delete this block and only those two links
   lose their styling.
   ========================================================================== */
.answer-card a{
  color:var(--accent);
  font-weight:600;
  text-decoration:underline;
  text-underline-offset:2px;
  text-decoration-thickness:1px;
  text-decoration-color:color-mix(in srgb, var(--accent) 45%, transparent);
}
.answer-card a:hover{text-decoration-color:var(--accent)}

/* ---------- BUTTONS NEVER UNDERLINE (DP, 2026-08-05) ----------
   Base a{} already drops the underline, but .prose a{} adds one for inline body
   links and it was bleeding onto the in-article CTA button (an a.btn inside the
   prose). This keeps every button clean, in prose and everywhere else. */
a.btn, a.btn:hover,
a[class*="btn-"], a[class*="btn-"]:hover,
.prose a.btn, .prose a.btn:hover,
.prose-cta .btn, .prose-cta .btn:hover{ text-decoration:none }

/* ---------- MOBILE POLISH (DP, 2026-08-05) ----------
   1. FAQ box sits further below its heading (it was hugging the hook).
   2. Hooks wrap evenly so a black + blue split breaks at the colour boundary
      instead of orphaning the first blue word on line one. Short hooks stay on
      one line because balancing never forces a wrap that is not needed. */
.faq{margin-top:26px}
@media (min-width:721px){.faq{margin-top:34px}}
.page-hero h1,.sec-head h2,.band h2{text-wrap:balance}

/* Section kickers removed site-wide (DP, 2026-08-05): the small "dash-and-label" lines
   above section headings were unnecessary. Hidden, not deleted, so restoring is
   removing this one rule. */
.sec-kicker{display:none}

/* ---------- THEME-INVERTED COMMAND-CENTER MOCKUPS (DP, 2026-08-05) ----------
   The flagship nine-step guide carries `ccfig` figures that ship BOTH renders
   of each command-center screen. DP's rule: a LIGHT page shows the DARK mockup,
   a DARK page shows the LIGHT mockup, so the screenshot always pops off the
   paper instead of blending into it.

   The blog theme lives on <html data-theme>, key `dp-theme`, and the inline
   head script stamps it before first paint, so KEY OFF data-theme, never
   prefers-color-scheme (the OS setting is not what the reader chose here).

   Both images sit inside the .prose-fig card and get its border, radius and
   shadow for free. Only one paints: the other is display:none, so there is no
   double box and no layout jump. Delete this block and both images would show;
   nothing here is destructive to the rest of the figure system. */
.cc-fig .cc-light{display:none}
[data-theme="dark"] .cc-fig .cc-dark{display:none}
[data-theme="dark"] .cc-fig .cc-light{display:block}

/* ---------- BRAND FACE (DP, 2026-08-05) ----------
   DP's smiling photo, circular, before the wordmark on every page, as constant
   brand recall against his name. The photo already sits on his signature yellow,
   so a thin yellow ring finishes it as a brand token. This is the ONE place
   yellow returns to the otherwise-blue system, on DP's explicit call, scoped to
   the personal mark only; the UI (buttons, links, headings) stays blue.
   Delete this block and the topbar falls back to the plain wordmark. */
.brand-face{
  width:40px;height:40px;flex:none;border-radius:50%;
  background:#FFD60A;
  box-shadow:0 0 0 2px #FFD60A, 0 1px 3px rgba(10,10,10,.28);
  overflow:hidden;
}
.brand-face img{width:100%;height:100%;object-fit:cover;border-radius:50%;display:block}
/* the dark-theme rule inverts .brand img (for a monochrome logo mark); the photo
   must never be inverted, so pin it back in BOTH themes. */
html .brand .brand-face img,
html:not([data-theme="light"]) .brand .brand-face img{filter:none !important;height:100%;width:100%}
@media (max-width:720px){.brand-face{width:33px;height:33px}}

/* ---------- TEXT-COLUMN TABLES (DP, 2026-08-05) ----------
   The base .price-table makes the LAST column nowrap and right-aligned, which
   is right for a short money figure ("$3,240") and wrong for a column of prose.
   A table authored with `variant:'text'` gets `table-text`, and on DESKTOP its
   cells wrap and left-align so a long sentence fits the reading column instead
   of forcing the whole box to scroll sideways. Fixed layout with two narrow
   label columns keeps the wide column predictable.

   SCOPED to min-width:721px on purpose. Below that the phone STACKED layout
   (further up this file) already turns every row into its own card with no
   horizontal scroll, so it must not be overridden here. Delete this block and
   text tables simply fall back to the old sideways-scroll behaviour. */
@media (min-width:721px){
  .prose-table.table-text table.price-table{table-layout:fixed;min-width:0}
  .prose-table.table-text .price-table th,
  .prose-table.table-text .price-table td{white-space:normal;text-align:left;vertical-align:top}
  .prose-table.table-text .price-table th:last-child,
  .prose-table.table-text .price-table td:last-child{
    text-align:left;white-space:normal;
    font-family:"Plus Jakarta Sans",ui-sans-serif,system-ui,-apple-system,sans-serif;
    font-size:15.5px;font-weight:400;color:var(--text-2);
  }
  .prose-table.table-text .price-table th:first-child,
  .prose-table.table-text .price-table td:first-child{width:16%}
  .prose-table.table-text .price-table th:nth-child(2),
  .prose-table.table-text .price-table td:nth-child(2){width:17%}
}

/* ============================================================
   CLIENT LOGO MARQUEE (home hero) - added 2026-08-07
   Infinite, smooth, pauses on hover, respects reduced-motion.
   The .track holds the logo set TWICE so translateX(-50%) loops seamlessly.
   Swap the .logo placeholders for <img> logos (see index.html).
   ============================================================ */
.logo-marquee{width:100%;max-width:1200px;margin:52px auto 0;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 8%,#000 92%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 8%,#000 92%,transparent 100%);}
/* The label became a PROOF LINE on 2026-08-10 ("Trusted by 100+ clients from
   UAE, US and India across 20 industries") instead of the two-word "Brands I've
   worked with". Sixty-five letter-spaced capitals need wrapping hygiene the old
   label never did: a max-width so it breaks in the middle rather than at the
   very edge, a line-height so two rows do not collide, and less tracking on a
   phone, where .22em over three rows reads as a ransom note. */
.logo-marquee .lm-label{display:block;text-align:center;margin:0 auto 20px;max-width:62ch;
  font-family:var(--font-mono);font-size:12px;letter-spacing:.22em;line-height:1.85;
  text-transform:uppercase;color:var(--text-3);text-wrap:balance;}
@media (max-width:720px){
  .logo-marquee .lm-label{font-size:11px;letter-spacing:.12em;line-height:1.75;max-width:34ch;}
}
.logo-marquee .lm-track{display:flex;width:max-content;align-items:center;gap:64px;
  animation:lm-scroll 44s linear infinite;will-change:transform;}
.logo-marquee:hover .lm-track{animation-play-state:paused;}
/* each logo sits on a clean white chip so mixed-colour + white logos all read in both themes */
.logo-marquee .lm-logo{flex:none;height:66px;min-width:150px;padding:0 26px;box-sizing:border-box;
  display:flex;align-items:center;justify-content:center;background:#fff;border-radius:14px;
  border:1px solid rgba(0,0,0,.05);box-shadow:0 8px 22px rgba(0,0,0,.28);transition:transform .3s var(--ease),box-shadow .3s var(--ease);}
.logo-marquee .lm-logo:hover{transform:translateY(-3px);}
.logo-marquee .lm-logo img{max-height:34px;max-width:150px;width:auto;height:auto;object-fit:contain;display:block;}
.logo-marquee .lm-logo.invert img{filter:invert(1);}            /* a white logo -> dark, so it shows on a white chip */
.logo-marquee .lm-logo.icon img{max-height:50px;border-radius:9px;}  /* square icon marks a touch larger */
.logo-marquee .lm-more{flex:none;height:66px;padding:0 30px;box-sizing:border-box;display:flex;align-items:center;
  justify-content:center;border:1px dashed rgba(255,255,255,.30);border-radius:14px;color:var(--text-2);
  font-family:var(--font-mono);font-size:13px;letter-spacing:.12em;text-transform:uppercase;background:transparent;}
/* LIGHT THEME: white chips would vanish on the white page, so give them a defined edge + soft blue shadow */
[data-theme="light"] .logo-marquee .lm-logo{border-color:rgba(16,40,80,.14);box-shadow:0 10px 26px rgba(16,40,80,.16);}
[data-theme="light"] .logo-marquee .lm-more{border-color:rgba(16,40,80,.26);color:var(--text-2);}
@keyframes lm-scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){
  .logo-marquee .lm-track{animation:none;flex-wrap:wrap;justify-content:center;width:100%;gap:28px 44px;}
}

/* ASK-AI FOOTER ROW (added 2026-08-13). Five buttons that deep-link into the
   AI tools with a prefilled question about Digital Pratik / JorrDaar LLC. It
   lives on the navy footer slab, so it uses FIXED light ink (rgba white) like
   everything else inside .site-foot, never a theme token. */
.foot-ai{
  display:flex; align-items:center; flex-wrap:wrap; gap:14px 18px;
  margin:30px 0 0; padding:22px 0 0;
  border-top:1px solid rgba(255,255,255,.14);
}
.foot-ai-k{
  font-family:"JetBrains Mono",monospace; font-size:12px; font-weight:500;
  letter-spacing:.14em; text-transform:uppercase; color:rgba(255,255,255,.62);
}
.foot-ai-row{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.foot-ai-btn{
  display:inline-flex; align-items:center; justify-content:center;
  width:38px; height:38px; border-radius:10px;
  border:1px solid rgba(255,255,255,.18); color:rgba(255,255,255,.78);
  background:rgba(255,255,255,.03); transition:color .16s ease,border-color .16s ease,background .16s ease,transform .16s ease;
}
.foot-ai-btn:hover{
  color:#fff; border-color:rgba(255,255,255,.45); background:rgba(255,255,255,.12);
  transform:translateY(-1px);
}
.foot-ai-btn svg{ display:block; }
@media (max-width:640px){
  .foot-ai{ gap:12px; }
  .foot-ai-k{ width:100%; }
}

/* ==========================================================================
   NAV DROPDOWN: the seven services under "Work With Me"
   Added 2026-08-14 on DP's request. Additive: delete this block and the nav
   falls back to the plain "Work With Me" link it was before, because the
   parent is still a real <a> to work-with-me.

   The rule that shapes the whole thing: the label ALWAYS navigates. Hover
   opens the panel on a mouse, the caret button opens it on touch and for
   keyboards, and nothing here can swallow the click on the word itself.
   Under 1080px the navlinks bar is already a panel (a bottom sheet on a
   phone), so the menu stops floating and becomes an indented list that the
   caret expands.
   ========================================================================== */
.navdrop{position:relative;display:flex;flex-direction:column}
.navdrop-head{display:flex;align-items:center}
.navlinks .navdrop-t{display:inline-flex;align-items:center;gap:5px}
.navdrop-cx{appearance:none;border:1px solid transparent;background:transparent;
  padding:7px 6px;cursor:pointer;display:flex;align-items:center;justify-content:center;
  color:var(--text-3);border-radius:9px;margin-left:-8px;
  transition:color var(--t-fast) var(--ease)}
.navdrop-cx:hover{color:var(--accent)}
.navdrop-cx svg{width:11px;height:11px;display:block;transition:transform var(--t-fast) var(--ease)}
.navdrop.open .navdrop-cx svg{transform:rotate(180deg)}

/* the floating panel. The padding-top on the wrapper is the hover bridge:
   without it the pointer crosses a dead gap on its way down and the menu
   closes under the cursor. */
.navdrop-menu{position:absolute;top:100%;right:0;z-index:70;width:352px;padding-top:11px;
  opacity:0;visibility:hidden;transform:translateY(-8px);
  transition:opacity var(--t-fast) var(--ease),transform var(--t-fast) var(--ease),visibility var(--t-fast) var(--ease)}
.navdrop-panel{display:flex;flex-direction:column;gap:2px;padding:8px;
  background:var(--glass);border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow)}
@media (min-width:1081px){
  .navdrop:hover .navdrop-menu,
  .navdrop:focus-within .navdrop-menu,
  .navdrop.open .navdrop-menu{opacity:1;visibility:visible;transform:translateY(0)}
  .navdrop:hover .navdrop-cx svg{transform:rotate(180deg)}
}
/* .navlinks a is a pill with nowrap; these rows are not pills */
.navlinks .nd-item{display:flex;align-items:flex-start;gap:11px;padding:9px 10px;
  border-radius:12px;border:1px solid transparent;white-space:normal;font-weight:600}
.navlinks .nd-item:hover{background:var(--glass-hi);border-color:var(--line)}
.nd-ico{flex:none;width:26px;text-align:center;font-size:16.5px;line-height:1.3}
.nd-tx{display:flex;flex-direction:column;gap:1px;min-width:0}
.nd-tx b{font-size:14.6px;font-weight:700;color:var(--text-1);letter-spacing:-.01em;line-height:1.3}
.nd-tx i{font-style:normal;font-size:12.6px;font-weight:500;color:var(--text-3);line-height:1.35}
.navlinks .nd-item:hover .nd-tx b{color:var(--accent)}
.navlinks .nd-all{display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin-top:5px;padding:11px 12px;border-radius:12px;border:1px solid var(--line);
  background:var(--accent-soft);color:var(--accent);font-size:13.4px;font-weight:700;white-space:nowrap}
.navlinks .nd-all:hover{border-color:var(--accent);color:var(--accent)}

/* anchor targets on work-with-me sit under the sticky bar without this */
.gcard[id]{scroll-margin-top:96px}

@media (max-width:1080px){
  .navdrop{align-items:stretch}
  .navdrop-head{justify-content:space-between;gap:6px}
  .navlinks .navdrop-t{flex:1 1 auto}
  .navdrop-cx{margin-left:0;width:44px;height:44px;flex:none;
    border-color:var(--line);border-radius:12px;background:var(--glass)}
  .navdrop-cx svg{width:13px;height:13px}
  /* in the sheet the panel stops floating: collapsed it is out of the flow
     entirely, so seven rows never stretch the sheet before they are asked for */
  .navdrop-menu{position:static;width:auto;padding-top:4px;display:none;
    opacity:1;visibility:visible;transform:none}
  .navdrop.open .navdrop-menu{display:block}
  .navdrop-panel{background:transparent;border:0;box-shadow:none;padding:0 0 4px 12px;gap:0}
  .navlinks .nd-item{padding:11px 12px;min-height:0}
  .nd-tx i{display:none}
  .nd-tx b{font-size:15.5px;font-weight:600}
  .navlinks .nd-all{margin-top:2px;font-size:14px}
}

/* The client strip is the LAST thing inside the home hero, and the navy footer
   slab starts the moment that section ends, so the strip's own bottom margin is
   the only air between the logo chips and the footer. Without it the chips sit
   almost on the slab. Scoped to .page-hero on purpose: the same strip on
   work-with-me lives in its own section with its own padding and is followed by
   more content, so it must not inherit this. */
.page-hero .logo-marquee{margin-bottom:56px}
@media (max-width:720px){.page-hero .logo-marquee{margin-bottom:36px}}

/* ==========================================================================
   NAV DROPDOWN, part 2: the label and its caret are ONE control
   First cut drew the pill around the words and left the caret floating
   outside it, so the header read as a link with a stray arrow next to it.
   The pill moves onto .navdrop-head, which wraps both, and the link inside
   goes flat. Specificity is deliberate: `.navlinks .navdrop .navdrop-t` beats
   `.navlinks a.on` and its light-theme twin, which is what would otherwise
   keep painting a second pill on the current page.
   ========================================================================== */
.navdrop-head{border:1px solid transparent;border-radius:100px;padding-right:9px;
  transition:border-color var(--t-fast) var(--ease),background var(--t-fast) var(--ease)}
.navlinks .navdrop .navdrop-t{border-color:transparent;background:transparent;
  box-shadow:none;padding-right:5px}
.navdrop-cx{margin-left:0;padding:6px 2px}
/* hover, keyboard focus and the touch-open state all light the same frame */
.navdrop:hover .navdrop-head,
.navdrop:focus-within .navdrop-head,
.navdrop.open .navdrop-head{border-color:var(--line)}
.navdrop:hover .navdrop-t,.navdrop:hover .navdrop-cx{color:var(--accent)}
/* the current page: the frame that used to sit on the link now sits on the pair */
.navdrop-head:has(.navdrop-t.on){border-color:var(--line-strong);background:var(--glass-hi)}
[data-theme="light"] .navdrop-head:has(.navdrop-t.on){background:#F1F1EC;
  border-color:rgba(10,10,10,.22);box-shadow:0 1px 2px rgba(10,10,10,.06)}
.navdrop:hover .navdrop-head:has(.navdrop-t.on){border-color:var(--accent)}

@media (max-width:1080px){
  /* in the sheet the row is full width, so the frame belongs on the link
     itself again and the caret keeps its own separate button */
  .navdrop-head{border:0;border-radius:0;padding-right:0;background:none}
  [data-theme="light"] .navdrop-head:has(.navdrop-t.on){background:none;box-shadow:none;border:0}
  .navdrop-head:has(.navdrop-t.on){background:none;border:0}
  .navlinks .navdrop .navdrop-t{padding:13px 14px}
  /* the flat rule above would otherwise strip the current-page highlight in
     the sheet, where it is the only cue for where you are */
  .navlinks .navdrop .navdrop-t.on{border-radius:12px;background:var(--accent-soft);
    color:var(--accent);border-color:var(--line-strong)}
  .navdrop-cx{padding:0}
}

/* ============================================================
   THREE-COLUMN TEXT TABLES
   Added 2026-08-15. The .table-text variant was written for a
   "narrow label, narrow label, wide prose" shape and hard-codes
   16% and 17% on the first two columns. A three-column mapping
   table where ALL THREE columns are sentences (the UAE to Saudi
   paperwork table) got two crushed columns and one wide one.

   The :has() pair below matches a text table with EXACTLY three
   columns and nothing wider, and gives it a readable split. Any
   other column count keeps the original widths untouched.
   ============================================================ */
@media (min-width:721px){
  .prose-table.table-text .price-table:has(thead th:nth-child(3)):not(:has(thead th:nth-child(4))) th:first-child,
  .prose-table.table-text .price-table:has(thead th:nth-child(3)):not(:has(thead th:nth-child(4))) td:first-child{ width:34% }
  .prose-table.table-text .price-table:has(thead th:nth-child(3)):not(:has(thead th:nth-child(4))) th:nth-child(2),
  .prose-table.table-text .price-table:has(thead th:nth-child(3)):not(:has(thead th:nth-child(4))) td:nth-child(2){ width:24% }
  .prose-table.table-text .price-table:has(thead th:nth-child(3)):not(:has(thead th:nth-child(4))) th:nth-child(3),
  .prose-table.table-text .price-table:has(thead th:nth-child(3)):not(:has(thead th:nth-child(4))) td:nth-child(3){ width:42% }
  /* the first column is a real label in these, so it keeps full-strength ink */
  .prose-table.table-text .price-table:has(thead th:nth-child(3)):not(:has(thead th:nth-child(4))) td:first-child{
    color:var(--text-1); font-weight:600;
  }
}

/* ==========================================================================
   NAV DROPDOWN, part 3: THE COLUMNED MEGA PANEL (DP's call 2026-08-15)
   Additive, and it only fires when the markup carries `nd-wide` + `nd-mega`.
   Strip those two class names and the panel falls straight back to the single
   tall column from part 1, which is why this block is safe to delete.

   WHY IT EXISTS. The panel grew from seven rows to nine when the two consultant
   entity pages joined it, and nine stacked rows read as a wall. DP asked for the
   shape already proven on the DBC client site: a few short titled columns plus
   one highlighted card on the right. Grouping also does a second job here, which
   is telling a visitor (and a crawler) that these are three kinds of work rather
   than nine unrelated links.

   THE SUBTITLES ARE HIDDEN INSIDE THE THREE COLUMNS ON PURPOSE. At about 215px
   of column width a 12.6px subtitle wraps to two lines under every single row
   and the panel doubles in height, which is the exact problem this replaced.
   They survive in the right-hand card, where there is room, and on mobile, where
   the panel is one full-width column again. Same pattern as part 1's mobile
   rule, not a new idea.
   ========================================================================== */
.navdrop-menu.nd-wide{width:min(980px,calc(100vw - 28px))}
.navdrop-panel.nd-mega{display:grid;grid-template-columns:repeat(3,minmax(0,1fr)) 252px;
  gap:4px 12px;padding:14px;align-items:start}
.nd-col{display:flex;flex-direction:column;gap:1px;min-width:0}
/* the column heading. Mono small-caps with a hairline under it, the same
   language the sec-kicker uses elsewhere on the site. */
.nd-h{display:block;font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;color:var(--accent);
  padding:4px 10px 8px;margin-bottom:5px;border-bottom:1px solid var(--line)}
/* the right-hand card: the two entity pages plus the way through to all seven */
.nd-side{display:flex;flex-direction:column;gap:1px;min-width:0;padding:8px;
  border:1px solid var(--line);border-radius:14px;background:var(--glass-hi)}
.nd-side .nd-h{padding-top:2px}
@media (min-width:1081px){
  .navdrop-panel.nd-mega .nd-col .nd-tx i{display:none}
  .navdrop-panel.nd-mega .nd-item{padding:8px 10px;gap:9px}
  .navdrop-panel.nd-mega .nd-ico{width:21px;font-size:15px}
  .navdrop-panel.nd-mega .nd-side .nd-tx i{display:block}
  .navdrop-panel.nd-mega .nd-all{margin-top:6px}
}
/* Under 1080px the sheet is one column again, so the grid collapses and the
   right-hand card stops being a card: a bordered box inside the bottom sheet
   reads as a second menu. The headings stay, and they are the actual win on a
   phone, where nine unlabelled rows were worst of all. */
@media (max-width:1080px){
  .navdrop-menu.nd-wide{width:auto}
  .navdrop-panel.nd-mega{display:flex;flex-direction:column;gap:0;padding:0 0 4px 12px}
  .nd-side{border:0;background:transparent;padding:0}
  .nd-h{padding:10px 10px 6px;margin-bottom:2px;font-size:10.5px}
  .nd-col+.nd-col .nd-h,.nd-side .nd-h{margin-top:4px}
}

/* ==========================================================================
   NAV DROPDOWN, part 4: THE DOUBLE PILL (fixed 2026-08-15, DP spotted it)
   The "Work With Me" control was drawing TWO nested rounded outlines on any
   page that marks itself current, which is every service page and both
   consultant pages. Measured, not guessed: in light theme the inner <a> was
   painting bg #F1F1EC, a 1px rgba(10,10,10,.22) border, a 100px radius AND its
   own shadow inside the head's identical pill, offset by exactly 1px. That
   1px offset is what made it read as a lopsided rectangle rather than a pill.

   WHY PART 2's FLATTENING RULE MISSED IT, because this will happen again.
   Part 2 kills the inner pill with `.navlinks .navdrop .navdrop-t`, which is
   three classes (0,3,0). The light-theme current-page rule it has to beat is
   `[data-theme="light"] .navlinks a.on`, and an attribute selector counts as a
   class, so that is 0,3,1 and it WINS. Dark was correct the whole time, which
   is why this survived: the dark rule is only `.navlinks a.on` at 0,2,1 and
   loses cleanly. Anything added here must therefore carry the [data-theme]
   prefix too, or it silently only works in one theme.

   AND THE SECOND BUG, found while measuring the first: the control was 45px
   tall while every other pill in that bar (Blog, About, Book a call) is 43px.
   The link kept its full 8px vertical padding and the head then added its own
   1px border top and bottom. Two pixels taller than its neighbours is exactly
   what reads as "chunky" without anyone being able to say why. The link now
   gives those 2px back so the outer pill lands at 43px.

   Scoped to min-width 1081px on purpose: below that the head has no pill at
   all and the current-page highlight belongs on the link itself, which is
   part 2's mobile block and must not be flattened.
   ========================================================================== */
@media (min-width:1081px){
  .navlinks .navdrop .navdrop-t,
  .navlinks .navdrop .navdrop-t:hover,
  .navlinks .navdrop .navdrop-t.on,
  [data-theme="light"] .navlinks .navdrop .navdrop-t,
  [data-theme="light"] .navlinks .navdrop .navdrop-t:hover,
  [data-theme="light"] .navlinks .navdrop .navdrop-t.on{
    background:transparent;border-color:transparent;box-shadow:none;
    /* 7px, not 8px: the head's own 1px border adds the difference back and the
       pair lands at the same 43px as every other pill in the bar */
    padding:7px 4px 7px 13px;
  }
  /* text sits 14px off the left edge, the caret glyph 12px off the right. The
     caret carries less visual weight than a word, so the slightly wider gap on
     that side is what makes the pill look optically centred rather than equal. */
  .navdrop-head{padding-right:9px}
}

/* ==========================================================================
   ABOVE-THE-FOLD PAINTS WITHOUT JAVASCRIPT (2026-08-16, mobile speed pass)
   Measured, not guessed. On a throttled phone the homepage reported
   FCP 2.43s / LCP 3.12s cold, and Chrome named the LCP element as
   `P.lead reveal d3`: the hero paragraph. That paragraph is TEXT, and text
   should paint almost immediately, so something was holding it back.

   IT WAS US. `.reveal` (line ~386) starts every element at opacity:0 and
   ui.js adds `.in` from an IntersectionObserver. ui.js is the LAST tag on the
   page, so the whole first screen stayed invisible until the HTML parsed, the
   CSS loaded, ui.js downloaded, ui.js executed, the observer fired, and THEN a
   0.24s transition-delay ran. Every one of those steps is on a 4x-slower CPU on
   a phone. The hero was hiding from the visitor and from Google's LCP timer.

   THE FIX: inside .page-hero only, the reveal is a pure CSS animation. CSS
   animations need no JavaScript, so the first screen now paints as soon as the
   stylesheet is parsed. Deliberately NO opacity ramp and NO delay on the hero:
   an element at opacity 0 does not count as painted for LCP, so fading the hero
   in would hand back most of what this saves. The hero slides, it does not fade.

   Everything below the fold keeps the original fade-and-rise on scroll, which is
   where that effect was always meant to be seen. .reveal.in still applies when
   ui.js gets there; opacity is already 1 by then, so it is a no-op.

   The prefers-reduced-motion block above already zeroes animation-duration, so
   this respects that setting without needing its own rule.
   ========================================================================== */
@keyframes dp-hero-rise{from{transform:translateY(14px)}to{transform:none}}
.page-hero .reveal{opacity:1;animation:dp-hero-rise .5s var(--ease) both}
.page-hero .reveal.d1{animation-delay:.04s}
.page-hero .reveal.d2{animation-delay:.08s}
.page-hero .reveal.d3{animation-delay:.12s}
.page-hero .reveal.d4{animation-delay:.16s}
/* the transition on .reveal would otherwise fight the animation on the frame
   ui.js adds .in, which reads as a tiny double-bounce on a slow phone */
.page-hero .reveal{transition:none}

/* ==========================================================================
   V2 REDESIGN SKIN (2026-08-20). DP asked for the same sections and the same
   flow with a far richer look. Everything in this block is ADDITIVE: it only
   overrides earlier rules, so deleting the whole block restores the previous
   design exactly. All colours ride the existing tokens, so both themes keep
   working, and every hard rule above still holds: buttons never use --accent,
   the light heading gradient still stops at #4E86DB, the footer slab keeps
   fixed light ink, and the hero still paints without JavaScript.
   ========================================================================== */

/* ---------- 1. atmosphere: a restrained blue aurora at the top of the page.
   Not the retired grey wash: this is a masked, blue-tinted glow that fades
   out by mid-hero, sits behind everything, and is fainter still on light. */
.ambient::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(ellipse 62% 42% at 50% -8%,rgba(46,107,211,.20),transparent 68%),
    radial-gradient(ellipse 34% 30% at 82% -6%,rgba(94,146,232,.10),transparent 70%);
}
[data-theme="light"] .ambient::before{
  background:
    radial-gradient(ellipse 62% 42% at 50% -8%,rgba(46,107,211,.09),transparent 68%),
    radial-gradient(ellipse 34% 30% at 82% -6%,rgba(94,146,232,.05),transparent 70%);
}
.ambient .grid{opacity:.68}

/* ---------- 2. type: a larger, tighter display scale ---------- */
.page-hero h1{font-size:clamp(34px,5.2vw,60px);font-weight:640;letter-spacing:-.042em;line-height:1.05}
body.home .page-hero h1{font-size:clamp(37px,5.6vw,68px)}
.page-hero .lead{font-size:19px;line-height:1.62}
.sec-head h2{font-weight:640;letter-spacing:-.036em}
.thesis-3a{font-size:clamp(19px,2.2vw,24px)}

/* ---------- 3. buttons: gradient primary, sheen sweep, real focus ----------
   The gradient runs DARKER than --btn-bg only (#2E6BD3 to #1C4FA8). Every stop
   keeps white ink at or above the 5.04:1 the flat button had, so this cannot
   reintroduce the 3.11:1 failure that --accent buttons had. */
.btn{position:relative;overflow:hidden}
.btn.primary{background:linear-gradient(135deg,#2E6BD3 0%,#2559B8 55%,#1C4FA8 100%);border-color:transparent}
.btn.primary::after{content:"";position:absolute;top:0;bottom:0;left:-70%;width:46%;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.22),transparent);
  transform:skewX(-18deg);transition:transform .55s var(--ease);pointer-events:none}
.btn.primary:hover::after{transform:skewX(-18deg) translateX(340%)}
.btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
a:focus-visible,button:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:6px}

/* ---------- 4. the top bar: heavier glass, gradient hairline ----------
   DESKTOP ONLY. The phone block at ~1445 removes the bar's backdrop-filter on
   purpose: a filtered ancestor becomes the containing block for fixed
   children, and the phone menu is a position:fixed bottom sheet parked at
   translateY(102%). Re-filtering the bar on a phone re-parents the sheet to
   the bar and leaves the menu permanently open. Scoped, never global. */
@media (min-width:721px){
  .topbar{backdrop-filter:blur(20px) saturate(1.5);-webkit-backdrop-filter:blur(20px) saturate(1.5);border-bottom:1px solid transparent;
    border-image:linear-gradient(90deg,transparent,var(--line-strong),transparent) 1}
  .topbar-inner{padding:12px 0}
}
.brand-face img{border-radius:50%}
.brand-face{position:relative;display:block;border-radius:50%;padding:2px;
  background:conic-gradient(from 210deg,var(--accent),var(--accent-deep),var(--accent))}

/* ---------- 5. cards: deeper lift, lit icon plates ---------- */
.gcard:hover,.stat:hover,.quote:hover,.step:hover{transform:translateY(-4px)}
.gcard:hover{border-color:var(--line-strong)}
.gcard .g-ico{background:linear-gradient(150deg,var(--accent-soft),transparent 70%);border-color:var(--line);
  box-shadow:inset 0 1px 0 var(--card-edge)}
.gcard:hover .g-ico{border-color:var(--line-strong)}

/* ---------- 6. photo language (.ph-*). Real photos of DP, framed in the
   card system: plate ring, hairline, a fixed dark caption chip that is
   identical in both themes because it sits ON the photo. ---------- */
.ph-card{position:relative;margin:0;border-radius:var(--radius);overflow:hidden;
  border:1px solid var(--line);background:var(--card-grad);
  box-shadow:0 0 0 6px var(--plate),var(--shadow)}
.ph-card img{display:block;width:100%;height:100%;object-fit:cover;
  transition:transform var(--t-slow) var(--ease)}
.ph-card:hover img{transform:scale(1.03)}
.ph-card::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,transparent 55%,rgba(5,12,26,.42) 100%)}
.ph-card figcaption{position:absolute;left:12px;right:12px;bottom:12px;z-index:2;
  display:flex;flex-direction:column;gap:2px;padding:10px 14px;border-radius:13px;
  background:rgba(6,14,30,.60);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  border:1px solid rgba(255,255,255,.16)}
.ph-card figcaption strong{font-size:14.4px;font-weight:650;letter-spacing:-.01em;color:#FFFFFF}
.ph-card figcaption span{font-family:"JetBrains Mono",monospace;font-size:10.2px;
  letter-spacing:.14em;text-transform:uppercase;color:#A9C7F7}
/* a strip of photo cards inside an existing section, never its own section */
.ph-band{display:grid;grid-template-columns:1fr;gap:14px;margin-top:34px}
.ph-band .ph-card{aspect-ratio:3/2}
@media (min-width:721px){.ph-band{grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}}
/* one wide photo closing a prose section */
.ph-wide{margin-top:38px}
.ph-wide .ph-card{aspect-ratio:5/2}
@media (max-width:720px){.ph-wide .ph-card{aspect-ratio:3/2}}

/* ---------- 7. the home hero: copy left, photo cluster right ----------
   Same single section, same copy, same CTAs. The cluster is one large stage
   photo with a smaller audience shot overlapping its corner and a floating
   stat chip. Stacks under the copy on a phone. */
.hh-grid{display:grid;grid-template-columns:1fr;gap:44px;align-items:center}
.hh-photo{position:relative;max-width:560px;margin:26px auto 0;width:100%}
.hh-photo .ph-main{aspect-ratio:3/2}
.hh-float{position:absolute;left:-14px;bottom:-22px;width:46%;aspect-ratio:3/2;margin:0;
  border-radius:16px;overflow:hidden;border:1px solid rgba(255,255,255,.22);
  box-shadow:var(--shadow-lg);transform:rotate(-2deg)}
.hh-float img{display:block;width:100%;height:100%;object-fit:cover}
.hh-chip{position:absolute;right:-8px;top:-14px;display:inline-flex;align-items:center;gap:8px;
  font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--text-1);background:var(--bar);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border:1px solid var(--line-strong);border-radius:100px;padding:9px 15px;box-shadow:var(--shadow-soft)}
.hh-chip i{width:6px;height:6px;border-radius:50%;background:var(--success);flex:none;animation:pulse-dot 2.2s var(--ease) infinite}
@media (min-width:961px){
  body.home .hh-grid{grid-template-columns:1.04fr .96fr;gap:56px;text-align:left}
  body.home .hh-grid .hero-ctas{justify-content:flex-start}
  body.home .hh-grid .eyebrow{margin-left:0}
  body.home .hh-photo{margin:0;max-width:none}
  body.home .page-hero h1{margin-left:0;margin-right:0}
  body.home .page-hero .lead{margin-left:0}
}
@media (max-width:960px){
  .hh-float{bottom:-16px;left:-6px}
  .hh-chip{right:0;top:-12px}
}

/* ---------- 8. blog: the featured card becomes a true split feature ---------- */
@media (min-width:821px){
  .bfeat{grid-template-columns:1.08fr 1fr;align-items:stretch}
  .bfeat .np-img{aspect-ratio:auto;height:100%;border-bottom:0;border-right:1px solid var(--line)}
  .bfeat .bf-body{padding:28px 30px;justify-content:center}
}
.npcard:hover{transform:translateY(-4px);box-shadow:var(--shadow-lg)}

/* ---------- 9. article reading progress. Pure CSS scroll timeline, no JS.
   Browsers without scroll() or :has() simply never draw it. ---------- */
@supports (animation-timeline: scroll(root)) {
  @keyframes dp-read{from{transform:scaleX(0)}to{transform:scaleX(1)}}
  body:has(.article)::before{content:"";position:fixed;top:0;left:0;right:0;height:3px;
    z-index:90;background:var(--grad);transform-origin:0 50%;transform:scaleX(0);
    animation:dp-read linear both;animation-timeline:scroll(root)}
}

/* ---------- 10. the CTA band gets its glow back ---------- */
.band{box-shadow:0 0 0 6px var(--plate),var(--fill-glow),0 0 90px -30px rgba(46,107,211,.45)}

/* ---------- 11. footer credit line. Fixed light ink: it lives on the navy
   slab, exactly like everything else inside .site-foot. ---------- */
.foot-credit{margin-top:18px;padding-top:16px;border-top:1px solid rgba(234,241,255,.14);
  text-align:center;font-family:"JetBrains Mono",monospace;font-size:11px;
  letter-spacing:.14em;text-transform:uppercase;color:rgba(234,241,255,.55)}
.foot-credit a{color:rgba(234,241,255,.85);font-weight:600;transition:color var(--t-fast) var(--ease)}
.foot-credit a:hover{color:#FFFFFF}

/* ---------- 12. rhythm and polish ---------- */
@media (min-width:721px){section{padding:72px 0}}
.crumbs{opacity:.85}
.checklist li{border-radius:var(--radius-sm)}
::selection{background:var(--accent-deep);color:#FFFFFF}
/* two-up variant of the photo band */
@media (min-width:721px){.ph-band.two{grid-template-columns:repeat(2,minmax(0,1fr))}}
.ph-band.two .ph-card{aspect-ratio:2/1}
@media (max-width:720px){.ph-band.two .ph-card{aspect-ratio:3/2}}

/* ==========================================================================
   HOME HERO: THE FLOAT PHOTO WAS HALF HIDDEN (DP spotted it 2026-08-20)
   Additive, scoped to the home hero only. Delete it and the previous
   (broken) stacking returns; the About and Work With Me photo bands are
   untouched and keep their full-width captions.

   MEASURED, NOT GUESSED. The main photo's caption is left:12/right:12, so it
   spanned the whole card and ran straight through the overlapping audience
   photo below it: 32% of that photo covered at 1440px, 52% at 375px. It also
   WON the paint order, because the caption carries z-index:2 while the float
   was z-index:auto, so the chip drew over the picture rather than under it.

   Two fixes, both needed. The caption un-anchors from the left and sits in the
   bottom-RIGHT corner at its own width, which is the half of the card the
   float never reaches. And the float is lifted above the caption's layer, so
   even if a longer caption is ever written, a photo can never be painted over
   by a text chip again.

   On a phone the sub-line is dropped. At 375px the card is about 325px wide,
   and "GROWTH MARKETING, LIVE ON STAGE" in tracked mono needs roughly 230px
   of it, which forces the chip back across the float whatever it is anchored
   to. The name is the part that carries the authority; the headline directly
   above it already says what the work is.
   ========================================================================== */
.hh-photo .ph-main figcaption{left:auto;right:12px;width:max-content;max-width:56%}
.hh-float{z-index:3}
@media (max-width:560px){
  .hh-photo .ph-main figcaption span{display:none}
  .hh-photo .ph-main figcaption{max-width:60%}
}
/* 961 to 1120px is where the two-column hero is tightest: the card is short
   enough that the caption wraps to two lines and grows back toward the float,
   which left an 8px sliver of the photo covered. The float gives up four
   points of width there rather than the caption giving up a line. */
@media (min-width:961px) and (max-width:1120px){.hh-float{width:42%}}

/* the Projects menu sits left of Work With Me, so its wide panel is pinned to the viewport
   (fixed, centred) instead of hanging off its own trigger: a fixed box can never widen the page,
   and translate, not transform, keeps the open animation working */
@media (min-width:721px){
  .navdrop-projects .navdrop-menu.nd-wide{position:fixed;top:66px;right:auto;left:50%;translate:-50% 0;width:min(980px,calc(100vw - 28px))}
}
.nd-all{white-space:normal;text-align:center}

/* the blog hero keeps its centred layout and gets a photo behind it (DP, 2026-08-22) */
.blog-hero{position:relative;isolation:isolate;overflow:hidden}
.blog-hero-bg{position:absolute;inset:0;z-index:-2}
.blog-hero-bg img{width:100%;height:100%;object-fit:cover;object-position:center 40%}
.blog-hero::before{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(to bottom,rgba(5,8,20,.78),rgba(5,8,20,.88) 70%,var(--bg-0))}
.blog-hero h1,.blog-hero .lead,.blog-hero .eyebrow{color:#FFFFFF}
.blog-hero .lead{color:rgba(255,255,255,.8)}
[data-theme="light"] .blog-hero::before{background:linear-gradient(to bottom,rgba(5,8,20,.72),rgba(5,8,20,.8) 70%,var(--bg-0))}

/* ==========================================================================
   BLOG HERO, LIGHT THEME (DP, 2026-09-02).
   The blog index hero carried its dark photo scrim into the light theme, so a
   light page opened with a near-black slab and a washed-out chip on it, while
   every category page beside it opened on white paper. In light the photo now
   sits under a white scrim instead: same photo, same layout, ink headline, the
   normal chip. Dark is untouched. Delete this block to get the dark slab back.
   ========================================================================== */
[data-theme="light"] .blog-hero::before{
  background:linear-gradient(to bottom,rgba(255,255,255,.84),rgba(255,255,255,.9) 70%,var(--bg-0));
}
[data-theme="light"] .blog-hero h1{color:var(--text-1)}
[data-theme="light"] .blog-hero .lead{color:var(--text-2)}
[data-theme="light"] .blog-hero .eyebrow{color:var(--chip-ink);background:var(--chip-bg)}

/* ==========================================================================
   BLOG HERO BREADCRUMB (DP, 2026-09-02).
   The blog index breadcrumb sat in its own strip between the topbar and the
   photo hero, and the page-wide dot grid showed through that strip, so it read
   as a stray band. The nav now sits inside the hero, top left over the photo.
   Ink follows the hero: light ink on the dark scrim, dark ink on the light one.
   The hero keeps its centred layout; only the crumb is left-aligned.
   ========================================================================== */
.blog-hero .wrap{position:relative}
.blog-hero .hero-crumbs{position:absolute;left:0;top:-6px;padding:0;text-align:left;opacity:1}
.blog-hero .hero-crumbs,.blog-hero .hero-crumbs a{color:rgba(255,255,255,.62)}
.blog-hero .hero-crumbs span[aria-current]{color:#FFFFFF}
.blog-hero .hero-crumbs a:hover{color:#FFFFFF}
[data-theme="light"] .blog-hero .hero-crumbs,
[data-theme="light"] .blog-hero .hero-crumbs a{color:var(--text-3)}
[data-theme="light"] .blog-hero .hero-crumbs span[aria-current]{color:var(--accent)}
[data-theme="light"] .blog-hero .hero-crumbs a:hover{color:var(--accent)}
/* give the centred headline room above it so the crumb never overlaps the chip */
.blog-hero .wrap{padding-top:22px}
@media (max-width:720px){.blog-hero .hero-crumbs{position:static;justify-content:center;margin-bottom:14px}.blog-hero .wrap{padding-top:0}}
