/* ChartSynq — one visual language for the site and the app.
   Palette and typeface are taken from app.html, so moving between the
   marketing pages and the charts should feel like one product. */
:root{
  /* brand — identical to the app */
  --brand:#3f6fb0;          /* "Bridge" blue */
  --brand-lt:#5b8ed6;       /* lightened for dark backgrounds */
  --brand-dk:#12192b;       /* "Chart" navy */

  --bg:#0d1117; --bg2:#0a0e14;
  --panel:#151b24; --panel2:#1b222d; --line:#232c39; --line2:#2f3a4a;
  --txt:#e9eff7; --txt2:#b9c5d4; --dim:#7f8c9c;
  --ok:#2fb8a4; --err:#f0544f; --warn:#e8a33d;
  --accent:#3f6fb0; --accent2:#5b8ed6;   /* older pages still name these */
  --mono:Consolas,ui-monospace,Menlo,monospace;
  --ui:"Nunito","Segoe UI",system-ui,-apple-system,sans-serif;
  --r:14px; --r-sm:9px;
  --shadow:0 18px 50px rgba(0,0,0,.45);
  --ring:0 0 0 3px rgba(91,142,214,.22);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
/* A STICKY FOOTER. Every page is header + main + footer, and on a short one -
   sign in, forgotten password, a one-line notice - the footer used to stop
   wherever the content did and leave a couple of hundred pixels of empty page
   below it, which reads as a page that failed to finish loading (Pat,
   2026-09-05: "on the sign in page the footer is not at the bottom but half
   way up the page ... check them all"). The column stretches to the viewport
   and main takes the slack, so the footer is at the bottom of a short page and
   below the content on a long one. body::before is position:fixed, so it is
   out of flow and is not a flex item. */
body{margin:0;background:var(--bg);color:var(--txt);
  font:16px/1.7 var(--ui);font-weight:400;-webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  display:flex;flex-direction:column;min-height:100vh}
body>main{flex:1 0 auto}
body>.foot{flex:none}
body::before{content:"";position:fixed;inset:0;pointer-events:none;z-index:0;
  background:
    radial-gradient(1100px 620px at 12% -12%, rgba(63,111,176,.20), transparent 62%),
    radial-gradient(820px 480px at 96% 2%, rgba(91,142,214,.10), transparent 64%)}
body>*{position:relative;z-index:1}
::selection{background:rgba(91,142,214,.32)}

a{color:var(--brand-lt);text-decoration:none}
a:hover{color:#8ecbff}
:focus-visible{outline:2px solid var(--brand-lt);outline-offset:2px;border-radius:4px}
code{font-family:var(--mono);font-size:.88em;background:var(--panel2);
  border:1px solid var(--line);padding:2px 6px;border-radius:5px;color:var(--txt2)}
hr{border:0;border-top:1px solid var(--line);margin:32px 0}
em{font-style:normal;color:var(--txt);font-weight:700}

/* ---- the mark ---------------------------------------------------------- */
.brandmark{display:inline-flex;align-items:center;gap:.42em;color:var(--brand-lt);
  font-weight:800;letter-spacing:-.02em;line-height:1;white-space:nowrap}
.brandmark .mark{flex:none;height:1em;width:1.29em;display:block}
.brandmark .word{display:inline-flex}
.brandmark .b1{color:#f2f6fb}          /* "Chart"  — same near-white as the app */
.brandmark .b2{color:var(--brand-lt)}  /* "Synq"  — --brand-lt, as in the app  */
.brandmark.sm{font-size:19px}
.brandmark.md{font-size:26px}
.brandmark.lg{font-size:34px}

/* ---- chrome ------------------------------------------------------------ */
.top{position:sticky;top:0;z-index:20;display:flex;align-items:center;
  justify-content:space-between;gap:16px;padding:14px 26px;
  border-bottom:1px solid var(--line);
  background:rgba(13,17,23,.78);backdrop-filter:saturate(140%) blur(12px)}
/* The anchor inherits body's line-height:1.7 and 16px, so its line box is
   ~27px and the inline-flex mark sits on that BASELINE, not centred - the logo
   rode high in the bar (Pat, 2026-08-17). Make the link its own flex box so it
   collapses to the mark's height and align-items:center on .top can centre it. */
.top .brand{display:flex;align-items:center;line-height:1}
.top .brand,.top .brand:hover{text-decoration:none}
.top nav{display:flex;align-items:center;gap:4px}
.top nav a{color:var(--txt2);padding:8px 12px;border-radius:var(--r-sm);
  font-size:14.5px;font-weight:600;transition:background .12s,color .12s}
.top nav a:hover{color:var(--txt);background:var(--panel2)}
.top nav a.btn{color:#fff}

/* The header was the one piece of chrome with no responsive rule at all. A
   non-wrapping flex nav on a phone pushed "Create account" - the conversion
   action - off the right edge, and dragged the whole document's scrollWidth
   with it (463px inside a 390px viewport, so every page scrolled sideways).
   The footer nav has always had flex-wrap:wrap; this is the same fix applied
   where it was missed.

   It stays sticky here on purpose: the reason the overflow mattered is that
   the primary action was unreachable, and un-sticking the bar to buy back a
   few pixels would take it away again the moment anyone scrolled. */
@media(max-width:640px){
  .top{flex-wrap:wrap;gap:6px 12px;padding:8px 14px}
  /* wrap on the nav as well as on .top: at 360px and up the four links fit one
     row, and at 320px - where they do not - they break onto a second rather
     than pushing the button off the edge again. No extra breakpoint; the
     content decides where it gives. */
  .top nav{width:100%;gap:2px;justify-content:space-between;flex-wrap:wrap}
  .top nav a{padding:8px 9px;font-size:14px}
  .top nav a.btn.small{padding:8px 13px}
}

/* Touch targets are a property of the POINTER, not of the screen: a laptop
   with a touchscreen needs a finger-sized target at 1600px, and a narrow
   window driven by a mouse does not. min-height rather than padding, so the
   44px holds whatever the font metrics do. */
@media(pointer:coarse){
  .top .brand,.top nav a,.footin a{min-height:44px;display:inline-flex;
    align-items:center}
  .footin nav{gap:0 18px}
}

.wrap{max-width:800px;margin:0 auto;padding:40px 24px 84px}
/* 1400, not 1120: Pat sized the page against tradingview.com and then asked
   for a quarter more ("make the whole page 25% wider"). The showcase pieces
   (hero, gallery) were already breaking out to ~1368, so at 1400 the column
   and its media finally agree instead of one stepping past the other. */
.wrap.wide{max-width:1400px}
.wrap.mid{max-width:980px}   /* roomier than the 800 default, not the full stage */
/* The admin console needs more width than any reading column - its tab strip
   and its widest tables both wrap at 800px - but it is NOT the home page.
   Its own class rather than 'wide' so the console's width can move without
   dragging the marketing pages along (it did exactly that once, in the
   other direction, back when 'wide' went full-bleed on big screens). */
.wrap.admin{max-width:1500px}
/* the wallpaper candles behind the home page: fixed, faint, no interaction;
   site.js drifts them a little on scroll (parallax), unless the visitor asked
   for reduced motion */
.bgCandles{position:fixed;inset:0;z-index:-1;pointer-events:none;overflow:hidden;
  perspective:1400px;perspective-origin:66% 42%;will-change:transform}
/* the chart plane itself, tilted like a screen photographed from the left -
   the browser's own projection is what makes the rows converge; no amount of
   hand-scaling in flat space can imitate it */
.bgPlane{position:absolute;inset:-14% -14% -14% -34%;transform-origin:54% 50%;
  transform:rotateY(-24deg) rotateX(6deg) rotateZ(-2deg) scale(1.06) translateY(-4%);opacity:.6}
.bgPlane svg{width:100%;height:100%;display:block}
/* the vignette is FLAT over the page, outside the tilted plane */
.bgVig{position:absolute;inset:0;background:
  radial-gradient(ellipse 80% 72% at 52% 40%,transparent 42%,rgba(11,14,23,.95) 100%),
  radial-gradient(ellipse 44% 36% at 50% 28%,rgba(11,14,23,.66),transparent 100%)}
@media (prefers-reduced-motion:reduce){.bgCandles{will-change:auto}}
/* A topic row is as tall as its MESSAGE. The vote column used to be in flow,
   and a fixed 230px stack of button + button + two-step manual set the height
   of every card - a one-line topic stood as tall as a paragraph (Pat,
   2026-08-19). Closed, .rmVote is just its "Vote" chip; the manual drops open
   under it on click. Only the sum stays beside the text.
   It is a <details>, so the open/closed state costs no script: no
   collapse-on-load flash, and the manual is still reachable with JS off. */
.rmTopic{display:flex;gap:20px;align-items:flex-start}
.rmMain{flex:1;min-width:0}
/* the tally reads as a tally, not as a price tag: the figure with what it IS
   underneath it */
.rmSide{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;
  text-align:right;gap:1px;white-space:nowrap}
.rmSumLbl{font-size:10.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--txt2)}
/* The column keeps its width whether it is open or shut, so opening a panel
   drops it DOWN and moves nothing sideways - the chip and the sum stay put. */
.rmVote{flex:0 0 236px;display:flex;flex-direction:column;align-items:flex-end}
.rmVoteTog{list-style:none;cursor:pointer;user-select:none;white-space:nowrap;
  display:inline-flex;gap:6px;align-items:center;font-size:12.5px;font-weight:600;
  color:var(--txt2);background:rgba(255,255,255,.04);border:1px solid var(--line2);
  border-radius:999px;padding:4px 12px}
.rmVoteTog::-webkit-details-marker{display:none}   /* Safari's own triangle */
.rmVoteTog code{font-size:12px;background:none;padding:0;color:inherit}
.rmVoteTog:hover{color:var(--txt);border-color:#3d4b5e;background:var(--panel2)}
.rmVote[open]>.rmVoteTog{color:var(--brand-lt);border-color:var(--brand-lt)}
.rmCaret{font-size:9px;line-height:1;transition:transform .12s ease}
.rmVote[open] .rmCaret{transform:rotate(180deg)}
@media (prefers-reduced-motion:reduce){.rmCaret{transition:none}}
.rmVoteBody{display:flex;flex-direction:column;gap:8px;align-items:flex-end;
  text-align:right;margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}
.rmSum{font-weight:800;font-size:17px}
/* the code named right next to the title, labelled so it reads as the thing
   you put in the Ko-fi message (Pat: "test [vote code: #1-Q]") */
.rmCodeTag{font-size:12px;color:var(--txt2);background:rgba(255,255,255,.04);
  border:1px solid var(--line2);border-radius:5px;padding:2px 8px;white-space:nowrap}
.rmCodeTag code{font-size:12px;color:var(--txt)}
/* the steps read LEFT-aligned inside the right column - right-ragged
   instructions were a mess to read */
.rmSteps{font-size:12px;color:var(--txt2);line-height:1.5;text-align:left;max-width:230px}
ol.rmSteps{margin:2px 0 0;padding-left:18px}
ol.rmSteps li{margin:0 0 4px}
.rmSteps code{font-size:12px}
/* the copy-code button: the ONE place the code lives, and it says what
   happened - the label flips to "copied to clipboard" on click */
.codeBtn{background:rgba(255,255,255,.04);border:1px solid var(--line2);color:var(--txt);
  border-radius:6px;padding:5px 10px;font:600 12px/1 var(--mono,monospace);cursor:pointer}
.codeBtn:hover{border-color:#3d4b5e;background:var(--panel2)}
.codeBtn.done{border-color:#2fb8a4;color:#2fb8a4}
@media(max-width:720px){
  .rmTopic{flex-direction:column}
  .rmVote{flex-basis:auto;align-items:flex-start}
  .rmVoteBody{align-items:flex-start;text-align:left}
}
/* The full-bleed desktop mode lived here: at >=1400px and 3:2 the 'wide'
   pages dropped their max-width and the showcase figures stretched with the
   window. REMOVED on request (Pat, 2026-08-16: "make the whole page less wide
   then please") - on a 1920 monitor the start page sprawled and its hero
   image stood taller than the screen. Every page now keeps its centred
   column at any size (.wrap.wide caps at 1400 - see its comment). Do not
   bring the full-bleed back piecemeal; it is what made the first image
   impossible to take in at one glance. */

h1{font-size:32px;font-weight:800;letter-spacing:-.025em;margin:0 0 14px;line-height:1.15}
h2{font-size:20px;font-weight:700;margin:0 0 10px;letter-spacing:-.015em}
h3{font-size:15px;font-weight:700;margin:20px 0 6px;color:var(--txt2)}
p{margin:0 0 14px}
.lead{font-size:17.5px;color:var(--txt2);margin:0 0 26px;max-width:64ch;font-weight:400}
.dim{color:var(--dim)}
.small{font-size:13.5px}
.warn{color:var(--warn)}
.eyebrow{display:flex;align-items:center;gap:10px;font-size:11.5px;font-weight:800;
  letter-spacing:.16em;text-transform:uppercase;color:var(--brand-lt);margin:0 0 18px}
.eyebrow::after{content:"";height:1px;flex:1;
  background:linear-gradient(90deg,var(--line2),transparent)}

/* ---- cards ------------------------------------------------------------- */
.card{position:relative;background:linear-gradient(180deg,#161d27,#11161e);
  border:1px solid var(--line);border-radius:var(--r);padding:24px 26px;margin:0 0 20px}
/* a single hairline of light along the top edge — the thing that separates a
   panel from a rectangle */
.card::before{content:"";position:absolute;inset:0 0 auto;height:1px;
  border-radius:var(--r) var(--r) 0 0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.09),transparent)}
.card.danger{border-color:#4a2320}
.card h2{margin-top:0}
.card h3{font-size:14.5px;font-weight:700;margin:18px 0 6px;color:var(--txt2)}
/* min(...,100%) on the track floor, not a bare minmax: an auto-fit track is
   allowed to be WIDER than its container, so a 290px floor inside the 272px
   .wrap gets at 320px pushes the whole document sideways. The min() lets the
   single column collapse to the container instead. Identical at every width
   where the floor already fits. */
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(290px,100%),1fr));gap:20px}
.grid3{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:20px}

/* ---- hero -------------------------------------------------------------- */
/* The FIRST shot fits a screen in one glance (Pat) - it is the one image
   people must take in whole, and it will become a GIF whose motion is lost
   if any of it hangs below the fold. The sizing that delivers that is the
   next comment's; this one is just the why. */
/* Sized to Pat's reference, MEASURED, not eyeballed: tradingview.com's product
   showcase is a 1200px-wide video, centred - 63% of a 1902px viewport
   (2026-08-16, read off their live page). So: 1200. Wider than the 1120 text
   column, so the hero BREAKS OUT of it - the text keeps its readable measure,
   the showcase steps a little beyond, centred by symmetric (negative when
   needed) margins. Margins, not transforms: a translated box still counts
   into scrollable overflow and would put a sideways scrollbar on mid-width
   windows. 100vw-40px keeps it off the edges on anything smaller. */
.heroFig .figure.wide,.heroFig .shot{
  /* +14% on the TradingView-matched 1200 (Pat) -> 1368 */
  --heroW:min(1368px,calc(100vw - 40px));
  width:var(--heroW);max-width:none;
  margin:44px calc((100% - var(--heroW))/2) 0}
.hero{padding:44px 0 10px;text-align:center}
.hero .brandmark{margin-bottom:26px}
.hero h1{font-size:clamp(34px,5.2vw,56px);margin:0 auto 18px;max-width:18ch;
  letter-spacing:-.03em;line-height:1.08}
.hero h1 .hl{background:linear-gradient(180deg,#9dc2f0,var(--brand-lt));
  -webkit-background-clip:text;background-clip:text;color:transparent}
.hero .lead{margin:0 auto 30px;font-size:clamp(16px,1.55vw,19px);text-align:center;
  max-width:60ch}
.hero .cta,.endcta .cta{display:flex;gap:12px;justify-content:center;
  align-items:center;flex-wrap:wrap}
/* Every button in a call-to-action row is the same size, and its label is
   centred in its own box.

   Both halves of that were wrong. The primary carried .big (16.5px / 15px
   padding) and the ghost beside it did not (15px / 12px), so the pair was two
   different sizes; and because .btn is inline-block, flex's default stretch
   grew the SHORTER button's box to match without moving the text inside it,
   leaving the ghost's label sitting a few pixels above the primary's. A
   primary earns its dominance from colour and weight, not from a taller box,
   so they match and inline-flex centres both labels. */
.cta .btn{padding:15px 30px;font-size:16.5px;
  display:inline-flex;align-items:center;justify-content:center}
/* Once the row wraps there is no pairing left to preserve, and two stacked
   buttons of different widths read as ragged rather than as a hierarchy. Below
   the wrap point they take the full column, which is the ordinary phone
   pattern and gives the secondary a full-width tap target too. */
@media(max-width:520px){
  .cta{flex-direction:column;align-items:stretch}
  .cta .btn{width:100%}
}
.hero .soon{max-width:60ch;margin:22px auto 20px;padding:13px 18px;font-size:15px;
  line-height:1.55;color:#f0d9a8;background:rgba(232,163,61,.10);
  border:1px solid rgba(232,163,61,.42);border-radius:var(--r-sm)}
.hero .soon b{color:#ffd88a}
.hero .under{font-size:13.5px;color:var(--dim);margin:16px 0 0}

/* The closing call to action. Deliberately NOT a .card: by this point the
   reader has passed six of them, and one more bordered box reads as a seventh
   feature rather than as the end of the argument. A rule and open space say
   "this is the bottom" more clearly than another border would. */
.endcta{margin:56px 0 0;padding:46px 20px 0;text-align:center;
  border-top:1px solid var(--line)}
.endcta h2{font-size:clamp(23px,2.6vw,30px);letter-spacing:-.02em;margin:0 0 12px}
.endcta p{color:var(--txt2);max-width:56ch;margin:0 auto 22px;font-size:15.5px}

/* ---- screenshots ------------------------------------------------------- */
/* Framed the way the app frames a window, so a screenshot sits on the page as
   part of the design rather than as a rectangle someone pasted on. */
.figure{margin:0;border:1px solid var(--line2);border-radius:var(--r);overflow:hidden;
  background:var(--bg2);box-shadow:var(--shadow)}
.figure img{display:block;width:100%;height:auto}
.figure figcaption{padding:11px 16px;border-top:1px solid var(--line);
  background:linear-gradient(180deg,#161d27,#11161e);
  font-size:13px;color:var(--dim);text-align:left}
.figure.wide{max-width:1000px;margin:48px auto 0}
/* One row of three (Pat: "make them next to each other"), stepping out of
   the text column to the hero's own breakout width so each shot keeps real
   size. Same margin trick as .heroFig, same reason. Below 900px
   three-across would make postage stamps, so they stack. */
.gallery{--galW:min(1368px,calc(100vw - 40px));
  width:var(--galW);margin-left:calc((100% - var(--galW))/2);margin-right:calc((100% - var(--galW))/2);
  display:grid;grid-template-columns:repeat(3,1fr);gap:22px;justify-content:center}
@media(max-width:900px){.gallery{width:auto;margin-left:0;margin-right:0;grid-template-columns:1fr}}
/* the thumbs invite the click; the overlay shows the shot as large as the
   viewport allows and closes from its backdrop (site.js) */
.gallery .figure img{cursor:zoom-in}
.lightbox{position:fixed;inset:0;z-index:120;background:rgba(5,8,13,.86);
  display:flex;align-items:center;justify-content:center;padding:3vh 3vw;cursor:zoom-out}
.lightbox img{max-width:100%;max-height:100%;cursor:default;
  border:1px solid var(--line2);border-radius:var(--r);box-shadow:0 18px 60px rgba(0,0,0,.55);
  background:var(--bg2)}
/* No forced aspect and no cover-crop. The 16/10 box amputated the right-hand
   15% of the replay shot - the price axis and every TP/SL/break-even chip -
   which is precisely the evidence its own caption promises ("costs charged the
   way your broker charges them"). A screenshot that has had its proof cropped
   off is worse than one of an awkward shape.

   The two shots still have different natural heights until they are re-taken
   at a matching aspect, so each frame stretches to the tallest in the row and
   its caption is pushed to the bottom. Captions that line up read as a pair;
   captions floating at two different heights read as a mistake. */
.gallery .figure{margin:0;display:flex;flex-direction:column}
.gallery .figure figcaption{margin-top:auto}

/* Drawn, not screenshotted: nothing to ship and nothing to go stale. */
.shot{margin:48px auto 0;max-width:980px;border:1px solid var(--line2);
  border-radius:var(--r);background:var(--bg2);box-shadow:var(--shadow);overflow:hidden}
.shot .bar{display:flex;align-items:center;gap:7px;padding:10px 14px;
  border-bottom:1px solid var(--line);background:linear-gradient(180deg,#19202a,#151b24)}
.shot .dot{width:9px;height:9px;border-radius:50%;background:#2c3847}
.shot .chip{font-size:11px;color:var(--txt2);background:var(--panel2);
  border:1px solid var(--line);border-radius:6px;padding:2px 8px;font-family:var(--mono)}
.shot .chip.on{color:#fff;background:var(--brand);border-color:var(--brand-lt)}
.shot .grow{flex:1}
.shot .body{display:grid;grid-template-columns:1fr 190px;gap:1px;background:var(--line)}
.shot .panes{display:grid;grid-template-columns:1.9fr 1fr;gap:1px;background:var(--line);
  height:330px}
.shot .pane{background:var(--bg2);position:relative;overflow:hidden}
.shot .pane .tf{position:absolute;left:11px;top:8px;font-size:10.5px;color:var(--dim);
  font-family:var(--mono);z-index:2;letter-spacing:.06em}
.shot .rows{display:grid;grid-template-rows:1fr 1fr;gap:1px;background:var(--line);height:100%}
.shot svg{display:block;width:100%;height:100%}
.shot .side{background:var(--panel);padding:12px 13px;font-size:11.5px}
.shot .side .h{font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--dim);margin:0 0 9px;font-weight:800}
.shot .side .kv{display:flex;justify-content:space-between;gap:8px;padding:3px 0;
  color:var(--dim);font-family:var(--mono);font-size:11px}
.shot .side .kv b{color:var(--txt2);font-weight:400}
.shot .side .kv .up{color:var(--ok)}
.shot .side .buy{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin:11px 0 14px}
.shot .side .buy span{border-radius:7px;padding:9px 0;text-align:center;font-weight:800;
  font-size:12px;color:#fff}
.shot .side .buy .s{background:rgba(240,84,79,.85)}
.shot .side .buy .b{background:rgba(47,184,164,.85)}
@media(max-width:900px){.shot .body{grid-template-columns:1fr}.shot .side{display:none}}
@media(max-width:640px){.shot .panes{grid-template-columns:1fr;height:230px}
  .shot .rows{display:none}}

.feature{padding:22px 24px}
.feature .ic{width:38px;height:38px;border-radius:11px;display:flex;align-items:center;
  justify-content:center;background:rgba(91,142,214,.13);
  border:1px solid rgba(91,142,214,.26);color:var(--brand-lt);font-size:18px;margin:0 0 14px}
/* Drawn icons, not emoji: an emoji is a different shape, weight and colour on
   every OS, which is a strange thing to put on a page whose whole argument is
   that it renders things precisely. One 24-grid, one stroke width, currentColor. */
.feature .ic svg{width:20px;height:20px;display:block;fill:none;stroke:currentColor;
  stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
.feature h2{font-size:17px}
.feature p{margin:0;color:var(--dim);font-size:14.5px;line-height:1.65}

.steps{margin:0 0 10px;padding-left:22px;color:var(--txt2)}
.steps li{margin:7px 0}
.stepnum{counter-reset:s;list-style:none;padding:0;margin:0}
.stepnum li{counter-increment:s;position:relative;padding:0 0 0 50px;margin:0 0 22px;
  color:var(--dim);font-size:14.5px;line-height:1.62}
.stepnum li:last-child{margin-bottom:0}
.stepnum li::before{content:counter(s);position:absolute;left:0;top:-1px;
  width:34px;height:34px;border-radius:11px;
  background:rgba(91,142,214,.13);border:1px solid rgba(91,142,214,.28);
  color:var(--brand-lt);font-weight:800;font-size:14.5px;
  display:flex;align-items:center;justify-content:center}
.stepnum li b{color:var(--txt);font-weight:800;display:block;font-size:16px;
  margin-bottom:3px;letter-spacing:-.01em}

/* ---- forms ------------------------------------------------------------- */
.form{display:block}
.form label{display:block;font-size:13px;font-weight:700;color:var(--txt2);margin:18px 0 6px;
  letter-spacing:.01em}
.form input[type=text],.form input[type=email],.form input[type=password],
.form input[type=number],.form input[type=datetime-local],.form select,.form textarea{
  width:100%;background:var(--bg2);border:1px solid var(--line2);border-radius:var(--r-sm);
  color:var(--txt);padding:12px 14px;font-size:15px;font-family:inherit;
  transition:border-color .12s,box-shadow .12s,background .12s}
/* textarea had no rule at all, so it fell back to the browser default: a small
   white box that ignored the dark theme and was narrower than every field
   above it. Sized to be written IN, and only vertically resizable so dragging
   one cannot break the card's layout. */
.form textarea{min-height:120px;line-height:1.55;resize:vertical}
.form input::placeholder,.form textarea::placeholder{color:#5d6a7a}
.form input:hover,.form select:hover,.form textarea:hover{border-color:#3a475a}
.form input:focus,.form select:focus,.form textarea:focus{outline:none;border-color:var(--brand-lt);
  box-shadow:var(--ring);background:#0c1117}
.form .hint{font-size:13px;color:var(--dim);margin:8px 0 0;line-height:1.6}
.form .check{display:flex;gap:11px;align-items:flex-start;margin:20px 0 0;
  font-size:14px;color:var(--txt2)}
.form .check input{margin-top:4px;accent-color:var(--brand);width:16px;height:16px}
.form .row2{display:grid;grid-template-columns:1fr 1fr;gap:0 18px}
@media(max-width:560px){.form .row2{grid-template-columns:1fr}}

.btn{display:inline-block;margin-top:18px;background:var(--brand);
  border:1px solid rgba(255,255,255,.14);color:#fff;border-radius:var(--r-sm);
  padding:12px 24px;font-size:15px;font-weight:800;font-family:inherit;cursor:pointer;
  text-decoration:none;letter-spacing:.01em;
  transition:background .13s,transform .07s,box-shadow .13s;
  box-shadow:0 6px 18px rgba(63,111,176,.30)}
.btn:hover{background:var(--brand-lt);color:#fff;box-shadow:0 10px 26px rgba(63,111,176,.42)}
.btn:active{transform:translateY(1px)}
.btn.ghost{background:rgba(255,255,255,.03);border-color:var(--line2);color:var(--txt2);
  box-shadow:none}
.btn.ghost:hover{background:var(--panel2);color:var(--txt);border-color:#3d4b5e;box-shadow:none}
.btn.danger{background:#7a2b28;border-color:#a3403c;box-shadow:none}
.btn.danger:hover{background:#98352f}
.btn.small{padding:8px 15px;font-size:14px;margin-top:0}
.btn.big{padding:15px 30px;font-size:16.5px}
/* Ko-fi donation / vote button (external link). Friendly GREEN, not red (Pat) -
   support should read as a warm invitation, and red is this app's colour for
   losses and warnings. */
/* White on this green measured 3.31:1 at 15px/800 - under AA - and the hover
   made it WORSE at 2.47, because the fill lightened while the text stayed
   white. Rather than muting the green into a forest colour (the whole point of
   it is that supporting reads as warm, not as a warning), the label goes dark:
   near-black on the brighter teal measures about 7.6:1, and hover can now get
   brighter still instead of having to get darker. */
.btn.kofi{background:#2fb8a4;border-color:#5fd8c6;color:#06231f;
  box-shadow:0 6px 18px rgba(47,184,164,.30)}
.btn.kofi:hover{background:#45cfba;color:#06231f;border-color:#7ee6d6;
  box-shadow:0 10px 26px rgba(47,184,164,.42)}
/* Demo call-to-action — amber, matching the in-app SIMULATION banner, so it
   reads as "try the sandbox" and stands apart from the blue account buttons. */
.btn.demo{background:linear-gradient(180deg,#ffd479,#e8a33d);border-color:#ffcf6a;color:#2a1d00;
  box-shadow:0 8px 22px rgba(232,163,61,.34)}
.btn.demo:hover{background:linear-gradient(180deg,#ffe09a,#f2b451);color:#2a1d00;border-color:#ffe09a;
  box-shadow:0 12px 30px rgba(232,163,61,.46)}
.demoPitch{margin:0 auto 30px;max-width:62ch;display:flex;flex-direction:column;align-items:center;gap:13px}
.demoPitch .demoWhat{margin:0;font-size:14.5px;line-height:1.55;color:var(--txt2);text-align:center}
.demoPitch .demoWhat b{color:#f0c46a;font-weight:800}
.heroBrandLink{display:inline-block;text-decoration:none;cursor:pointer;border-radius:12px}
.heroBrandLink:focus-visible{outline:none;box-shadow:var(--ring)}
/* Five feature cards read as 3 + 2: the first three are peers, and the last
   two (No internet, Automated rules) are a PAIR of equal tiles (Pat: "the
   automated rules should not stand by its own"). A 6-track grid gives thirds
   and halves off the same unit; below the breakpoint the cards fall back to
   the auto-fit flow every other grid on the site uses. */
.grid3.feat5{grid-template-columns:repeat(6,1fr)}
.grid3.feat5>.feature{grid-column:span 2}
.grid3.feat5>.feature:nth-child(4),
.grid3.feat5>.feature:nth-child(5){grid-column:span 3}
@media(max-width:980px){
  .grid3.feat5{grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr))}
  .grid3.feat5>.feature{grid-column:auto}
}
button.link{background:none;border:0;color:var(--brand-lt);cursor:pointer;font:inherit;
  padding:0;font-weight:600}
button.link:hover{color:#8ecbff}
.inline{display:inline}

.note{border-radius:var(--r-sm);padding:13px 16px;margin:0 0 20px;font-size:14.5px;
  border:1px solid var(--line);background:var(--panel2)}
.note.ok{border-color:#1d5f55;background:rgba(47,184,164,.10);color:#9ee5d8}
.note.err{border-color:#6b2b28;background:rgba(240,84,79,.10);color:#f5a19d}
.note.info{color:var(--txt2)}
/* The early-release notice on the start page: honest, quiet, and centred with
   the hero it sits inside. Amber family - a fact worth knowing, not an error -
   and inline-block so the card hugs its text instead of spanning the stage. */
.betaNote{display:inline-block;max-width:58ch;margin:6px auto 26px;padding:11px 18px;
  font-size:13.5px;line-height:1.55;text-align:left;color:#e6d3ac;
  border:1px solid rgba(232,163,61,.4);border-radius:var(--r-sm);
  background:rgba(232,163,61,.07)}
.betaNote b{color:#f0c46a}

.feat{list-style:none;padding:0;margin:14px 0 0;font-size:13.5px;color:var(--dim);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:4px 16px}
.feat b{color:var(--txt);font-weight:700}

.tbl{width:100%;border-collapse:collapse;font-size:13.5px;margin:8px 0 0}
.tbl th{text-align:left;color:var(--dim);font-weight:800;font-size:11px;
  letter-spacing:.1em;text-transform:uppercase;
  border-bottom:1px solid var(--line);padding:8px}
.tbl td{padding:9px 8px;border-bottom:1px solid #19212b}
/* sortable header links: the column title IS the control, so it inherits the
   header's small-caps look and only brightens on hover / when it is the active
   sort. The arrow says which way. */
.tbl th a.sorth{color:inherit;text-decoration:none;display:inline-block;white-space:nowrap}
.tbl th a.sorth:hover{color:var(--txt2)}
.tbl th a.sorth.on{color:var(--brand-lt)}
/* the row above the table: result count on the left, page-size picker on the right */
.listtools{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  flex-wrap:wrap;margin:14px 0 2px}
.listtools a{color:var(--txt2);text-decoration:none;padding:0 3px}
.listtools a:hover{color:var(--brand-lt)}
/* prev / next under the table */
.pager{display:flex;align-items:center;gap:14px;margin:12px 0 4px}
.btn.small.disabled{opacity:.4;pointer-events:none}
/* Dates must never wrap: "2026-08-01" broken across two lines doubles every
   row's height and reads as two numbers. nowrap makes the column claim the
   width it needs, and the wide columns give it up. */
/* the admin's site-wide notice: above everything, quiet but unmissable */
.sitenotice{padding:10px 18px;font-size:13.5px;line-height:1.5;text-align:center;
  border-bottom:1px solid var(--line2);background:var(--panel2);color:var(--txt2)}
.sitenotice.info{border-bottom-color:var(--accent);color:var(--txt)}
.sitenotice.ok{border-bottom-color:var(--ok);color:var(--txt)}
.sitenotice.warn{border-bottom-color:var(--warn);color:#f4d9a8;
  background:rgba(232,163,61,.10)}
.sitenotice.err{border-bottom-color:var(--err);color:#f6c9c7;
  background:rgba(240,84,79,.10)}
.tbl .nw{white-space:nowrap}
.tbl .date{white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--txt2)}
/* The grant controls were the widest thing in the row and squeezed everything
   else; sized to their content so the dates get their line back. */
/* .inline-form carries a 16px bottom margin for standalone use; inside a table
   row that is just dead height on every line. */
.grantf{flex-wrap:nowrap;gap:5px;margin:0}
.grantf select{padding:4px 6px;font-size:12.5px}
.grantf input[type=date]{padding:4px 6px;font-size:12.5px;width:auto;min-width:0}
.grantf .btn.small{padding:5px 12px;white-space:nowrap}
.tbl tr:last-child td{border-bottom:0}
.tbl td.ua{color:var(--dim);font-size:12px;max-width:280px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}

.foot{border-top:1px solid var(--line);background:var(--bg2)}
/* Even padding top and bottom. The 52px bottom left visibly more air under the
   last line than above the first, which on the start page read as the footer
   sitting too high with a gap hanging off it (Pat, 2026-09-05). */
.footin{max-width:1400px;margin:0 auto;padding:30px 24px 30px;display:flex;
  gap:18px;flex-wrap:wrap;align-items:center;font-size:13px;color:var(--dim)}
.footin nav{display:flex;gap:18px;flex-wrap:wrap}
/* the two footer rows: product links, then the legal set on its own line.
   Four legal pages is the law's arithmetic, not a design choice - grouping
   them is how they stop reading as clutter without any of them going away. */
.footnav{display:flex;flex-direction:column;gap:9px}
.footin .legalnav{gap:14px;align-items:baseline}
.footin .legalnav a{font-weight:500;font-size:12.5px}
.legalLbl{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--dim);opacity:.75;font-weight:700}
.footin a{color:var(--dim);font-weight:600}
.footin a:hover{color:var(--txt2)}
/* The risk note sets its OWN measure. Left to fill the footer it ran to about
   110 characters and wrapped into a long line plus a two-word orphan; capping
   it makes a tidy block whatever the window does. text-wrap:balance evens the
   two lines where the browser supports it and is harmless where it does not. */
/* The note asks for a real measure rather than whatever is left over. With
   flex:1 and a 250px floor it was CRUSHED at middling widths - around 900px it
   came out 275px wide, which pushed the second sentence to three lines and left
   "disclaimer." alone on the last one. A flex-basis it can actually be read at
   means it either gets that width or wraps onto its own full row, and never the
   squeezed in-between. text-wrap:balance is repeated on the sentence itself
   rather than left to inherit through the flex box, and the markup binds the
   closing words with non-breaking spaces, so a one-word last line is not
   possible even where balance is unsupported. */
.footin .dim{flex:1 1 360px;min-width:0;text-align:right}
.footin .risknote{display:flex;flex-direction:column;gap:2px;align-items:flex-end;
  max-width:46ch;margin-left:auto;line-height:1.55}
.footin .risknote b{color:var(--txt2);font-weight:600;text-wrap:balance}
.footin .risknote2{display:block;text-wrap:balance}
@media(max-width:680px){
  .footin .dim{text-align:left}
  .footin .risknote{align-items:flex-start;margin-left:0;max-width:none}
}

.tabs{display:flex;gap:4px;margin:0 0 24px;border-bottom:1px solid var(--line);flex-wrap:wrap}
.tabs a{color:var(--dim);font-size:14.5px;font-weight:700;padding:10px 14px;
  border-bottom:2px solid transparent;margin-bottom:-1px}
.tabs a:hover{color:var(--txt2)}
.tabs a.on{color:var(--txt);border-bottom-color:var(--brand-lt)}

.inline-form{display:flex;gap:8px;align-items:center;margin:0 0 16px}
.inline-form input{flex:1;background:var(--bg2);border:1px solid var(--line2);
  border-radius:var(--r-sm);color:var(--txt);padding:10px 13px;font:inherit}
pre.code{background:var(--bg2);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:15px 17px;overflow:auto;max-height:520px;font-family:var(--mono);font-size:12.5px;
  line-height:1.6;color:var(--txt2);white-space:pre;margin:10px 0 0}

.envbar{background:#7a4a0f;color:#ffe9c7;text-align:center;padding:7px 12px;
  font-size:12.5px;font-weight:800;letter-spacing:.04em}

/* Motion here is decoration; anyone who has asked for less should get none. */
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{transition:none!important;animation:none!important}
}

/* ---- plan comparison (pricing.php) ---------------------------------------
   A features-only value ladder: tiers across the top, features down the side.
   The whole table scrolls sideways on a narrow screen rather than the page. */
.plans-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;
  border:1px solid var(--line);border-radius:var(--r);background:var(--panel)}
table.cmp{width:100%;border-collapse:collapse;min-width:560px}
table.cmp th,table.cmp td{padding:12px 16px;text-align:center;
  border-bottom:1px solid var(--line)}
table.cmp tbody tr:last-child td{border-bottom:0}
table.cmp .rowhead{text-align:left;color:var(--txt2);font-weight:600;white-space:nowrap}
table.cmp thead th{vertical-align:bottom;border-bottom:2px solid var(--line2);padding-top:18px}
table.cmp .pname{display:block;font-size:19px;font-weight:800;color:var(--txt)}
table.cmp .ptag{display:block;font-size:12px;color:var(--dim);font-weight:500;
  margin-top:4px;max-width:16ch;margin-inline:auto;line-height:1.35}
table.cmp td.yes{color:var(--ok);font-weight:800}
table.cmp td.no{color:var(--dim)}
/* the top tier gets a faint highlighted column so the eye lands on it */
table.cmp th.feat,table.cmp td.feat{background:rgba(63,111,176,.07)}
table.cmp thead th.feat{border-bottom-color:var(--brand)}
table.cmp tbody tr:hover td{background:rgba(255,255,255,.02)}
table.cmp tbody tr:hover td.feat{background:rgba(63,111,176,.11)}

/* ---- admin: account-status badge, danger link, highlighted audit rows ---- */
.badge-off{display:inline-block;margin-left:6px;font-size:10px;font-weight:800;
  letter-spacing:.4px;color:#ffd0cc;background:#7a2b28;border:1px solid #a3403c;
  border-radius:5px;padding:1px 6px;vertical-align:1px}
.link.danger{color:var(--err)}
.link.danger:hover{color:#ff8a84}
.tbl tr.hot td{background:rgba(232,163,61,.07)}

/* ---- the admin dashboards: server-rendered SVG, no charting library ----
   The console's CSP is script-src 'self' with no inline, so every graph here
   is an <svg> PHP printed. These styles only place it: the colours, the bars
   and the gridlines are attributes on the elements themselves (admin.php's
   chart_bars/chart_line), because a chart that lost its colours when a
   stylesheet failed to load would be unreadable rather than plain. */
.cgraph{display:block;width:100%;height:auto;margin:10px 0 2px}
.spark{display:block;width:90px;height:20px;opacity:.85}
.clegend{display:flex;gap:16px;flex-wrap:wrap;margin:0 0 4px;font-size:12px;color:var(--dim)}
.clegend i{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:6px}
/* the window pickers above a graph - a tab row that is not THE tab row */
.tabsInline{display:flex;gap:8px;align-items:baseline;flex-wrap:wrap;
  margin:2px 0 10px;font-size:13px;color:var(--dim)}
.tabsInline a{color:var(--dim);font-weight:700;padding:2px 9px;border-radius:20px;
  border:1px solid transparent}
.tabsInline a:hover{color:var(--txt2);border-color:var(--line2)}
.tabsInline a.on{color:var(--txt);background:var(--panel2);border-color:var(--line2)}
/* "almost nobody uses this" - the removal candidates, marked rather than
   left for the reader to spot */
.tbl tr.cold td{background:rgba(240,84,79,.05);color:var(--dim)}
.tbl tr.cold td code{color:var(--dim)}
.okc{color:var(--ok)}

/* amber "UNVERIFIED" style badge, next to .badge-off */
.badge-warn{display:inline-block;margin-left:6px;font-size:10px;font-weight:800;
  letter-spacing:.4px;color:#ffe6ad;background:#5a4a1e;border:1px solid #8a6d2a;
  border-radius:5px;padding:1px 6px;vertical-align:1px}

/* Password field enhancements — show/hide toggle (ASVS 2.1.12) and strength
   meter (ASVS 2.1.8). Added by assets/site.js; the toggle sits inside the box,
   the meter below it. */
.pwWrap{position:relative;display:block}
.pwWrap>input{width:100%;padding-right:64px}
.pwToggle{position:absolute;top:0;right:0;height:100%;display:flex;align-items:center;
  background:none;border:0;color:var(--dim);font-size:12.5px;font-weight:600;cursor:pointer;
  padding:0 13px;border-radius:var(--r-sm)}
.pwToggle:hover{color:var(--txt)}
.pwToggle:focus-visible{outline:2px solid var(--brand-lt);outline-offset:-2px}
.pwMeter{margin:7px 0 2px}
.pwMeterBar{display:flex;gap:5px}
.pwMeterBar>span{flex:1;height:4px;border-radius:2px;background:var(--line2)}
.pwMeterBar>span.on.s0,.pwMeterBar>span.on.s1{background:var(--err)}
.pwMeterBar>span.on.s2{background:var(--warn)}
.pwMeterBar>span.on.s3{background:#8bc34a}
.pwMeterBar>span.on.s4{background:var(--ok)}
.pwMeterLbl{font-size:11.5px;margin-top:5px;color:var(--dim)}
.pwMeterLbl.s0,.pwMeterLbl.s1{color:var(--err)}
.pwMeterLbl.s2{color:var(--warn)}
.pwMeterLbl.s3{color:#8bc34a}
.pwMeterLbl.s4{color:var(--ok)}

/* ---- the indicator manual (manual.php, manual-ai.php) --------------------
   A reference page, not a marketing page: a standing index on the left so a
   reader can jump between chapters without scrolling back, and code blocks
   that are meant to be taken away rather than admired. */
.wrap.manual{max-width:1240px}
.manLayout{display:grid;grid-template-columns:236px minmax(0,1fr);gap:34px;align-items:start}
.manIx{position:sticky;top:78px;max-height:calc(100vh - 100px);overflow:auto}
.manIxIn{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  padding:14px 12px}
.manIxHd{margin:0 0 8px;font-size:11px;font-weight:800;letter-spacing:.08em;
  text-transform:uppercase;color:var(--dim)}
.manIx ol{list-style:none;margin:0;padding:0;counter-reset:none}
.manIx li{margin:0}
.manIx a{display:flex;gap:9px;align-items:baseline;padding:5px 8px;border-radius:7px;
  font-size:13.5px;line-height:1.35;color:var(--txt2)}
.manIx a:hover{background:var(--panel2);color:var(--txt)}
.manIx .n{flex:none;width:15px;text-align:right;color:var(--dim);font-size:11.5px;
  font-variant-numeric:tabular-nums}
.manIx ol.plain a{padding-left:8px}

/* Every chapter is a scroll target under a sticky header, so it needs the
   header's height back or the heading lands underneath it. */
.manBody{min-width:0}   /* a grid item defaults to min-width:auto, so a wide
                              code block would push the whole page sideways
                              instead of scrolling inside its own <pre> */
.manBody section.card{scroll-margin-top:86px}
.manBody h2{font-size:20px}
.manBody ul{padding-left:20px}
.manBody ul li{margin:0 0 8px}

/* a worked example: what it is, the picture it drew, the code that drew it */
.mex{margin:26px 0 0;padding-top:22px;border-top:1px solid var(--line)}
.mex:first-of-type{border-top:0;padding-top:0}
.mex h3{font-size:15px;font-weight:800;color:var(--txt);margin:0 0 6px}
.mex>p{margin:0 0 12px;color:var(--txt2);font-size:15px}
.mexShot{margin:0 0 10px;border:1px solid var(--line2);border-radius:var(--r-sm);
  overflow:hidden;background:var(--bg2);line-height:0}
.mexShot img{display:block;width:100%;height:auto}
.mexNote{font-size:13.5px;color:var(--dim);margin:10px 0 0;
  border-left:2px solid var(--line2);padding-left:11px}

.codewrap{margin:10px 0 0;border:1px solid var(--line);border-radius:var(--r-sm);
  overflow:hidden;background:var(--bg2)}
.codehead{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:6px 8px 6px 13px;border-bottom:1px solid var(--line);background:var(--panel)}
.codehead .dim{font-size:11.5px}
.codewrap pre.code{margin:0;border:0;border-radius:0;max-height:none}
.codeBtn.copyBtn{margin:0;padding:4px 11px;font-size:11.5px;white-space:nowrap}

/* the AI reference is one long block - give it a window rather than the page */
pre.code.manAi{max-height:70vh}

@media(max-width:900px){
  .manLayout{grid-template-columns:minmax(0,1fr);gap:18px}
  /* Un-stick it: a sticky index on a phone eats the screen the chapter needs. */
  .manIx{position:static;max-height:none}
  /* Two even columns, not a wrap: sixteen chapters of very different name
     lengths wrap into a ragged block that reads like a mistake. */
  .manIx ol{display:grid;grid-template-columns:1fr 1fr;gap:1px 6px}
  .manIx a{font-size:13px}
}

/* the ta reference: one signature per row, its note beneath */
.taList{margin:4px 0 4px}
.taList .grp{margin:22px 0 4px;font-size:12px;font-weight:800;letter-spacing:.07em;
  text-transform:uppercase;color:var(--dim);border-bottom:1px solid var(--line2);
  padding-bottom:6px}
.taList .grp:first-child{margin-top:6px}
.taFn{padding:9px 0;border-bottom:1px solid var(--line)}
.taFn:last-child{border-bottom:0}
.taFn .sig{overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}
.taFn .sig code{background:none;border:0;padding:0;color:var(--txt);font-size:13px}
.taFn .ret{color:var(--brand-lt);font-family:var(--mono);font-size:12px;margin-left:10px}
.taFn .nt{margin:3px 0 0;color:var(--txt2);font-size:14px;line-height:1.55}
