/* ==========================================================================
   Birds Eye Trading — licence portal
   Design tokens. Change these first if you rebrand.
   ========================================================================== */

:root {
  /* Colour ---------------------------------------------------------------- */
  --ink:        #141b2a;   /* primary text, header bar, footer */
  --ink-soft:   #3b4658;   /* secondary text */
  --ink-faint:  #6d7789;   /* captions, disabled */
  --page:       #edeff2;   /* page background */
  --surface:    #ffffff;   /* cards, panels */
  --surface-2:  #f6f7f9;   /* inset panels */
  --rule:       #d2d7de;   /* hairlines */
  --accent:     #0f5c4a;   /* pine — links, primary action, "active" */
  --accent-ink: #0a3f33;   /* accent pressed */
  --search-hit: rgba(15, 92, 74, .18);  /* behind letters a search matched */
  --brand:      #38A9E0;   /* BET logo blue — identity only, not actions.
                              Pine stays the interactive colour; this is for
                              the mark and anything badging the brand itself,
                              where pine would vanish on the dark header. */
  --mark:       #c0392b;   /* strike-through, promo, errors */
  --warn-bg:    #fdf3e6;
  --danger:     #b3261e;   /* invalid input, destructive action */
  --danger-bg:  #fdecea;

  /* Type ------------------------------------------------------------------ */
  --font-ui:   "Archivo", ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-data: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;

  --step--1: 0.8125rem;
  --step-0:  1rem;
  --step-1:  1.1875rem;
  --step-2:  1.5rem;
  --step-3:  2rem;
  --step-4:  2.75rem;
  --step-5:  clamp(2.75rem, 1.6rem + 4.6vw, 4.5rem);

  /* Space ----------------------------------------------------------------- */
  --s-1: 0.5rem;
  --s-2: 0.875rem;
  --s-3: 1.375rem;
  --s-4: 2.25rem;
  --s-5: 3.5rem;
  --s-6: 5.5rem;

  --radius: 3px;
  --wrap: 1180px;
  --measure: 68ch;

  /* Page background ------------------------------------------------------- */
  /* Two washes and a grid, all built from the palette above so a rebrand
     carries them. Kept as tokens because the print rule has to switch the
     whole thing off in one line. */
  --wash-brand: rgba(56, 169, 224, .13);   /* --brand, top right */
  --wash-accent: rgba(15, 92, 74, .09);    /* --accent, bottom left */
  --grid-line:  rgba(20, 27, 42, .032);    /* --ink, chart paper */
  --grid-cell:  48px;
}

/* Reset -------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background-color: var(--page);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  line-height: 1.6;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}
/* The page itself ----------------------------------------------------------
   Flat --page read as unfinished in the margins beside the content column,
   which is most of a wide screen. Three layers over it, in paint order:

     1. a wash of brand blue from the top right
     2. a wash of pine from the bottom left
     3. a fine grid — chart paper, at an alpha where you notice the texture
        rather than the lines

   `fixed` anchors all three to the window instead of the document. Without it
   the washes stretch to whatever height the page happens to be, so the same
   design looks entirely different on the pricing page and on the login form,
   and the grid drifts as you scroll. iOS has never honoured fixed attachment
   properly; there it scrolls with the content, which is the degradation and
   not a fault.

   Everything the eye actually reads sits on --surface or --ink, so none of
   this is behind body text: it fills the space around the cards. Contrast is
   unchanged, which is why the alphas are as low as they are.
   -------------------------------------------------------------------------- */
body {
  background-image:
    radial-gradient(62rem 42rem at 88% -12%, var(--wash-brand), transparent 62%),
    radial-gradient(54rem 40rem at -10% 108%, var(--wash-accent), transparent 60%),
    repeating-linear-gradient(to right, var(--grid-line) 0 1px, transparent 1px var(--grid-cell)),
    repeating-linear-gradient(to bottom, var(--grid-line) 0 1px, transparent 1px var(--grid-cell));
  background-attachment: fixed;
  background-repeat: no-repeat, no-repeat, repeat, repeat;
}

/* Ink on paper. The washes cost toner and the grid prints as visible ruled
   lines across the text, which is worse than no background at all. */
@media print {
  body { background-image: none; background-color: #fff; }
}

img, svg { max-width: 100%; height: auto; display: block; }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-ink); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

h1, h2, h3, h4 {
  font-family: var(--font-ui);
  line-height: 1.12;
  letter-spacing: -0.018em;
  margin: 0 0 var(--s-2);
  font-weight: 700;
}
h1 { font-size: var(--step-5); letter-spacing: -0.03em; }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-1); }
/* No max-width. Prose runs the full width of whatever contains it, so pages
   fill the wrapper instead of sitting in a column down the left. Containers
   that should stay narrow set their own width rather than relying on a global
   cap on every paragraph. */
p  { margin: 0 0 var(--s-3); }

.skip-link {
  position: absolute; left: -9999px;
  background: var(--ink); color: #fff; padding: var(--s-2) var(--s-3);
}
.skip-link:focus { left: var(--s-3); top: var(--s-3); z-index: 999; }

.wrap { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }
.screen-reader-text { position:absolute; width:1px; height:1px; overflow:hidden; clip-path: inset(50%); }

/* Data face — used only for real data: prices, IDs, keys, dates ------------ */
.data { font-family: var(--font-data); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }

/* ==========================================================================
   Header
   ========================================================================== */
.site-header {
  background: var(--ink);
  color: #fff;
  border-bottom: 1px solid var(--ink);
}
.site-header a { color: #fff; text-decoration: none; }
.header-inner {
  display: flex; align-items: center; gap: var(--s-4);
  min-height: 72px;
}
.brand { display: flex; align-items: center; gap: 0.6rem; flex: 0 0 auto; }
/* The mark is the full BET lockup now, so it is sized by height and keeps its
   own aspect ratio. The inline SVG inherits header colour for the wordmark. */
.brand__mark { display: block; flex: 0 0 auto; line-height: 0; }
/* Three selectors, not two. wp_get_attachment_image() puts the class we ask
   for on the <img> itself, so a custom logo arrives as img.brand__mark and the
   descendant rules never touch it — which renders the logo at its natural
   1253px and swallows the page. The inline SVG, by contrast, sits inside a
   span carrying the class. Both shapes have to be sized here. */
.brand__mark svg,
.brand__mark img,
img.brand__mark { display: block; height: 38px; width: auto; }
@media (max-width: 560px) {
  .brand__mark svg,
  .brand__mark img,
  img.brand__mark { height: 32px; }
}
.brand__name { font-weight: 700; font-size: var(--step-1); letter-spacing: -0.02em; }

/* Header lockup: the disc, then the acronym with the full name under it.
   The name is real text rather than part of the SVG — inside the artwork it
   would render at about 3.6px at this header size. See bet_brand_lockup(). */
.brand__mark--disc svg { height: 34px; width: auto; }
.brand__lockup { display: flex; flex-direction: column; justify-content: center; gap: 0.12em; }
.brand__wordmark {
  font-weight: 800; font-size: 1.32rem; line-height: 1;
  letter-spacing: 0.02em;
}
/* Sized and spaced to sit under the acronym as a base line, not to compete
   with it: the tracking is what makes a small mono line read as a lockup. */
.site-header .brand__name {
  font-family: var(--font-data);
  font-size: 0.55rem; font-weight: 400; line-height: 1;
  letter-spacing: 0.17em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
}
@media (max-width: 560px) {
  .brand__mark--disc svg { height: 30px; }
  .brand__wordmark { font-size: 1.14rem; }
  .site-header .brand__name { font-size: 0.5rem; letter-spacing: 0.14em; }
}

.primary-nav { margin-left: auto; }
/* align-items so the items centre on each other rather than on their own
   heights: the cart link is an icon and is shorter than the text links, so
   without this it hangs above the row. */
.primary-nav ul { display: flex; align-items: center; gap: var(--s-3); list-style: none; margin: 0; padding: 0; }
.primary-nav a {
  display: block; padding: 0.4rem 0; font-size: 0.95rem;
  border-bottom: 2px solid transparent;
}
.primary-nav a:hover { border-bottom-color: rgba(255,255,255,.45); }
.primary-nav .current-menu-item > a,
.primary-nav .current_page_item > a { border-bottom-color: #fff; }
.header-actions { display: flex; align-items: center; gap: var(--s-2); flex: 0 0 auto; }

/* Sign up sits beside the button reading as one more nav destination, so it
   borrows the primary nav's own treatment rather than approximating it. */
.header-actions__link {
  display: block; padding: 0.4rem 0; font-size: 0.95rem;
  border-bottom: 2px solid transparent; white-space: nowrap;
}
.header-actions__link:hover { border-bottom-color: rgba(255,255,255,.45); }

/* Account avatar badge -----------------------------------------------------
   Sits to the right of Cart. The ring reads the plan at a glance, but colour
   is never the only carrier: the corner flag prints the plan's initial and
   the link's accessible name spells it out. */
.account-badge {
  position: relative; display: inline-flex; flex: 0 0 auto;
  width: 34px; height: 34px; border-radius: 50%;
  outline: 2px solid transparent; outline-offset: 2px;
  transition: outline-color 0.15s ease;
}
/* A drawn user icon on a tinted disc, sized to match the cart icon beside it. */
.account-badge__avatar {
  /* Positioned so the flag inside it has something to pin to. */
  position: relative;
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  border-radius: 50%;
  background: rgba(255,255,255,.14);
  color: #fff;
}
.account-badge__avatar .bet-icon { width: 20px; height: 20px; }
/* The bar has no room for a word beside the avatar; the mobile menu does. */
.account-badge__name { display: none; }
/* Plan ring */
.account-badge--free  { outline-color: rgba(255,255,255,.34); }
.account-badge--paid  { outline-color: var(--brand); }
.account-badge:hover  { outline-color: #fff; }
.account-badge:focus-visible { outline-color: #fff; outline-width: 3px; }

.account-badge__flag {
  position: absolute; right: -4px; bottom: -4px;
  min-width: 15px; height: 15px; padding: 0 3px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px; border: 2px solid var(--ink);
  font-family: var(--font-data); font-size: 0.56rem; font-weight: 700;
  line-height: 1; color: #fff; background: #6b7687;
}
.account-badge--paid .account-badge__flag { background: var(--brand); }

/* Account dropdown --------------------------------------------------------
   Hidden with the [hidden] attribute rather than a class, so it is genuinely
   absent from the accessibility tree when closed instead of merely invisible. */
.account-menu { position: relative; display: inline-flex; }
.account-menu__list {
  position: absolute; top: calc(100% + 0.6rem); right: 0; z-index: 40;
  min-width: 13rem; max-width: min(20rem, calc(100vw - 2.5rem)); margin: 0; padding: 0.3rem 0;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: 0 6px 22px rgba(20,27,42,.18);
}
.account-menu__list[hidden] { display: none; }
/* A caret joining the menu to the badge it belongs to. */
.account-menu__list::before {
  content: ""; position: absolute; top: -5px; right: 12px;
  width: 8px; height: 8px; transform: rotate(45deg);
  background: var(--surface);
  border-left: 1px solid var(--rule); border-top: 1px solid var(--rule);
}
.account-menu__who {
  padding: 0.45rem 0.85rem 0.5rem;
  margin-bottom: 0.3rem;
  border-bottom: 1px solid var(--rule);
  font-size: var(--step--1); color: var(--ink-faint);
}
.account-menu__who-label { display: block; }
/* An address is one long unbreakable token as far as the browser is
   concerned, so without this it either overflows the card or forces it wide.
   anywhere rather than break-all: it breaks only when it has to, and prefers
   to do it at the @ or a dot. */
.account-menu__who-email {
  display: block;
  overflow-wrap: anywhere;
  color: var(--ink);
}
.account-menu__list a {
  display: block; padding: 0.5rem 0.85rem;
  color: var(--ink) !important;
  font-size: 0.95rem; text-decoration: none;
}
.account-menu__list a:hover { background: var(--surface-2); color: var(--accent) !important; }

/* Header icons ------------------------------------------------------------ */
.bet-icon { display: block; width: 20px; height: 20px; flex: 0 0 auto; }

@media (max-width: 560px) {
  .account-badge { width: 30px; height: 30px; }
}

.nav-toggle {
  display: none; margin-left: auto; background: none; border: 1px solid rgba(255,255,255,.3);
  color: #fff; padding: 0.45rem 0.7rem; border-radius: var(--radius); font: inherit; cursor: pointer;
}

@media (max-width: 860px) {
  .nav-toggle { display: block; }
  .primary-nav, .header-actions { display: none; width: 100%; }
  .header-inner { flex-wrap: wrap; padding-block: var(--s-2); }
  .site-header.is-open .primary-nav,
  .site-header.is-open .header-actions { display: block; margin-left: 0; }

  /* The header row's own gap sits between the destinations and the account
     actions once they wrap onto separate lines — 36px, which broke the stack
     into two blocks that did not look related. Even it up, and give the menu
     its breathing room below the bar explicitly instead. */
  .site-header.is-open .header-inner { row-gap: var(--s-1); }
  .site-header.is-open .primary-nav { padding-top: var(--s-2); }

  /* The open menu is a stack of targets, not a list of words.
     ------------------------------------------------------------------
     On a phone each destination used to be a 15px label with a hairline
     under it, shrink-wrapped to the width of its own text and floating in
     the middle of an otherwise empty row — a small thing to hit with a
     thumb, and hard to tell apart from a heading. Each one is now a
     full-width control with a visible edge, at the 48px minimum both Apple
     and Google give for a touch target.

     Sign up and Login join the same stack rather than sitting in a row of
     their own underneath, so the menu reads as one column of choices. They
     keep their difference in weight: Login stays the filled button because
     it is what a returning customer came for, and Sign up takes the same
     outline as the destinations above it, which is what it is. */
  .site-header.is-open .primary-nav ul {
    flex-direction: column;
    /* The row layout centres items on each other, which in a column
       shrinks every one to the width of its own label. */
    align-items: stretch;
    gap: var(--s-1);
    padding-bottom: 0;
  }
  .site-header.is-open .primary-nav a,
  .site-header.is-open .header-actions__link,
  .site-header.is-open .header-actions .btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 48px;
    padding: 0.6rem 1rem;
    border-radius: var(--radius);
    font-size: 1rem;
    text-align: center;
  }
  .site-header.is-open .primary-nav a,
  .site-header.is-open .header-actions__link {
    background: rgba(255,255,255,.06);
    border: 1px solid rgba(255,255,255,.18);
  }
  .site-header.is-open .primary-nav a:hover,
  .site-header.is-open .header-actions__link:hover {
    background: rgba(255,255,255,.12);
    border-color: rgba(255,255,255,.34);
  }
  /* The page you are on. On the desktop bar this is an underline; at this
     size the whole control is available to say it, and an underline inside
     a bordered box reads as an accident. */
  .site-header.is-open .primary-nav .current-menu-item > a,
  .site-header.is-open .primary-nav .current_page_item > a {
    background: rgba(255,255,255,.16);
    border-color: rgba(255,255,255,.5);
    border-bottom-color: rgba(255,255,255,.5);
    font-weight: 600;
  }
  .site-header.is-open .header-actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--s-1);
    padding-bottom: var(--s-3);
  }
  /* Signed in, the header holds an avatar badge with a dropdown behind it.
     Neither belongs in a drawer: the badge is one small target standing in
     for two destinations, and a dropdown inside a drawer is a menu inside a
     menu. So the badge steps aside and its contents — Settings, Log out —
     become rows in the same stack as Home and Pricing. main.js shows and
     hides the list with the drawer, using the hidden attribute, so the
     accessibility tree agrees with the screen. */
  .site-header.is-open .header-actions .account-menu { width: 100%; display: block; }
  .site-header.is-open .account-badge { display: none; }

  .site-header.is-open .account-menu__list {
    position: static;
    display: flex;
    flex-direction: column;
    gap: var(--s-1);
    width: 100%;
    min-width: 0;
    /* The card above is capped so a long address cannot drag it across the
       screen. In the drawer there is no card, and the cap left these rows
       narrower than the ones above them. */
    max-width: none;
    margin: 0;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
  /* The caret points at a badge that is no longer there. */
  .site-header.is-open .account-menu__list::before { display: none; }
  /* Who you are signed in as: worth saying, but it is a label rather than a
     destination, so it is not dressed as one. */
  .site-header.is-open .account-menu__who {
    order: -1;
    margin: 0;
    padding: 0 0 0.1rem;
    border: 0;
    color: rgba(255,255,255,.6);
    text-align: center;
    line-height: 1.35;
  }
  .site-header.is-open .account-menu__who-email { color: rgba(255,255,255,.85); }
  .site-header.is-open .account-menu__list a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 48px;
    padding: 0.6rem 1rem;
    border-radius: var(--radius);
    background: rgba(255,255,255,.06);
    border: 1px solid rgba(255,255,255,.18);
    color: #fff !important;
    font-size: 1rem;
  }
  .site-header.is-open .account-menu__list a:hover {
    background: rgba(255,255,255,.12);
    border-color: rgba(255,255,255,.34);
    color: #fff !important;
  }
}

/* ==========================================================================
   Buttons
   ========================================================================== */
/* background and appearance are here because of a <button>. Every .btn on the
   site had been an <a> until the Disconnect button, and a browser gives a
   <button> a grey face of its own unless something says otherwise — so it
   arrived wearing a box nobody had designed, with .btn--quiet's zero side
   padding making that box hug the text on two sides and not the other two.
   Declared on .btn rather than on button.btn so the modifiers below, which
   have the same specificity and come after, still win. */
.btn {
  display: inline-block; font: inherit; font-weight: 600; line-height: 1.2;
  padding: 0.72rem 1.25rem; border-radius: var(--radius);
  border: 1px solid transparent; cursor: pointer; text-decoration: none;
  background: transparent; -webkit-appearance: none; appearance: none;
  text-align: center;
}
.btn--primary { background: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-ink); color: #fff; }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn--ghost:hover { border-color: var(--ink); color: var(--ink); }
/* For actions that should be available but not invited — cancelling a plan. */
.btn--quiet { color: var(--ink-faint); border-color: transparent; padding-inline: 0; }
.btn--quiet:hover { color: var(--mark); border-color: transparent; text-decoration: underline; }
.btn--onink { background: #fff; color: var(--ink); }
.btn--block { display: block; width: 100%; text-align: center; }
/* Header-sized. The default padding is built for page buttons and makes the
   masthead taller than the nav links beside it. */
.btn--sm { padding: 0.42rem 0.9rem; font-size: 0.9rem; }

/* The header sets `.site-header a { color: #fff }` at (0,1,1), which outranks
   a button's own (0,1,0) colour — so a white button in the masthead came out
   white on white. Stated here at (0,2,0) so the button's colours win on
   purpose rather than by accident of ordering. */
.header-actions .btn--primary {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.header-actions .btn--primary:hover { background: var(--accent-ink); color: #fff; }

/* ==========================================================================
   Hero — the license card is the memorable object on this page
   ========================================================================== */
.hero { background: var(--ink); color: #fff; padding-block: var(--s-6) var(--s-6); }
.hero__grid {
  display: grid; grid-template-columns: 7fr 5fr; gap: var(--s-5); align-items: center;
}
.hero h1 { color: #fff; max-width: 15ch; }
.hero__lede { color: #c3cad6; font-size: var(--step-1); }
.hero__actions { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-top: var(--s-4); }
.hero__note { margin-top: var(--s-3); font-size: var(--step--1); color: #8d99ac; }

/* The product screenshot in the hero's second column, with its disclosure
   beneath it.

   The shot is dark NinjaTrader UI on the dark hero, which would otherwise bleed
   into the background with no edge. A hairline border plus a drop shadow lifts
   it off the ground and reads as a window onto the platform. */
.hero__shots { display: grid; gap: var(--s-3); }
.shot { margin: 0; }
.shot img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius);
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: 0 18px 40px -22px rgba(0,0,0,.9);
  background: #1e1e1e; /* holds the frame's shape before the JPEG paints */
}
.shot figcaption {
  margin-top: 0.5rem; font-size: var(--step--1); color: #8d99ac;
}

@media (max-width: 900px) {
  .hero__grid { grid-template-columns: 1fr; }
  .hero { padding-block: var(--s-5); }
  /* One shot, stacked under the copy at full width. The two-column rule that
     used to sit here was for a pair of screenshots side by side; with one it
     squeezed the chart into half the width between 561 and 900px. */
  .hero__shots { gap: var(--s-2); }
}

/* ==========================================================================
   Sections
   ========================================================================== */
.section { padding-block: var(--s-6); }
.section--surface { background: var(--surface); }
/* Full wrapper width. Headings get the whole measure of the page rather than
   wrapping early inside a 68ch box; the standfirst underneath is still held to
   a readable line length by the global `p` rule, so widening the container
   does not produce over-long prose. */
.section__head { margin-bottom: var(--s-4); }
.section__head p { color: var(--ink-soft); margin-bottom: 0; }

.rule-top { border-top: 1px solid var(--rule); }

/* Steps — numbered because setup genuinely is a sequence */
.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; }
.steps li {
  counter-increment: step;
  display: grid; grid-template-columns: 2.5rem 1fr; gap: var(--s-3);
  padding: var(--s-3) 0; border-top: 1px solid var(--rule);
}
.steps li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--font-data); color: var(--accent); font-size: 0.85rem; padding-top: 0.2rem;
}
.steps h3 { margin-bottom: 0.25rem; }
.steps p { margin-bottom: 0; color: var(--ink-soft); }
/* Sits below the numbered list, outside it, so it does not read as a step. */
.steps__more { margin-top: var(--s-3); margin-bottom: 0; font-size: var(--step--1); }

/* ==========================================================================
   Pricing
   ========================================================================== */
.promo-bar {
  background: var(--warn-bg); border: 1px solid #e8d3b4;
  border-radius: var(--radius); padding: var(--s-2) var(--s-3);
  margin-bottom: var(--s-4); font-size: 0.95rem;
}
/* Headline row: the offer, its end date and the clock. The bar itself is no
   longer the flex container — the coupon note below has to sit on its own
   line, and as a flex item it would only wrap there when the row happened to
   run out of room. */
.promo-bar__head {
  display: flex; gap: var(--s-2); align-items: baseline; flex-wrap: wrap;
}
/* Set at the theme's note size, the same as .plan-note and .hero__note, so
   it reads as an aside under the headline rather than as a second line of it.
   Colour stays --ink-soft rather than the --ink-faint those two use: this note
   sits on the warm promo tint instead of the page background, and faint washes
   out against it.

   Also overrides the base p rule on both counts: no bottom margin (it is the
   last thing in the bar) and no reading measure (it is a caption under a
   full-width row, not prose). */
.promo-bar__note {
  margin: 0.35rem 0 0; max-width: none;
  font-size: var(--step--1); color: var(--ink-soft);
}
.promo-bar strong { color: var(--mark); }
.promo-bar .data { font-size: 0.85rem; color: var(--ink-soft); }
/* Countdown sits immediately right of the end date. Tabular figures and a
   fixed min-width stop the row jittering as the digits tick over. */
.promo-bar__countdown {
  margin-left: -0.35rem;
  padding: 0.1rem 0.45rem;
  border-radius: var(--radius);
  background: rgba(192, 57, 43, .09);
  color: var(--mark) !important;
  font-variant-numeric: tabular-nums;
  min-width: 12ch;
  text-align: center;
}

/* stretch, not start: the panels carry different numbers of features, and
   sizing each to its own content left three cards of three different heights
   with their buttons at three different levels. Stretching them to the tallest
   in the row squares off the bottom edge, and .plan__cta's auto top margin
   then drops every button onto the same line. */
.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-3); align-items: stretch; }
@media (max-width: 900px) { .plans { grid-template-columns: 1fr; } }

.plan {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: var(--s-3) var(--s-3) var(--s-4);
  display: flex; flex-direction: column;
}
.plan--featured { background: var(--ink); border-color: var(--ink); color: #fff; }

/* Seats left, under the price. Sized like the cycle line it sits beside — it
   is a fact about the offer, not a klaxon. */
.plan__seats {
  font-size: var(--step--1);
  color: var(--ink-soft);
  margin-top: 0.15rem;
}
.plan--gone .plan__seats { color: var(--mark); }
.plan--gone .plan__price { opacity: 0.55; }
.plan--featured .plan__meta,
.plan--featured .plan__features li { color: #b9c2d0; }
.plan--featured .plan__was { color: #8d99ac; }
.plan--soon { opacity: 0.85; }

.plan__name { font-size: var(--step-1); font-weight: 700; margin-bottom: 0.2rem; }
.plan__meta { color: var(--ink-faint); font-size: var(--step--1); margin-bottom: var(--s-3); }

.plan__price { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.2rem; }
.plan__was {
  font-family: var(--font-data); font-size: 1.05rem; color: var(--ink-faint);
  text-decoration: line-through; text-decoration-color: var(--mark);
  text-decoration-thickness: 2px;
}
.plan__now { font-family: var(--font-data); font-size: 2.6rem; font-weight: 700; letter-spacing: -0.03em; }
.plan__cycle { font-size: var(--step--1); color: var(--ink-faint); }
.plan__save {
  font-family: var(--font-data); font-size: 0.72rem; color: var(--mark);
  border: 1px solid currentColor; border-radius: var(--radius); padding: 0.05rem 0.4rem;
}
.plan--featured .plan__save { color: #ff9c8c; }

.plan__features { list-style: none; margin: var(--s-3) 0 var(--s-4); padding: 0; font-size: 0.93rem; }
.plan__features li { padding: 0.42rem 0; border-top: 1px solid var(--rule); color: var(--ink-soft); }
.plan--featured .plan__features li { border-top-color: rgba(255,255,255,.14); }
.plan__cta { margin-top: auto; }
.plan__cta .btn[disabled],
.plan__cta .btn.is-disabled {
  background: var(--surface-2); color: var(--ink-faint);
  border-color: var(--rule); cursor: not-allowed; pointer-events: none;
}

/* The note runs under the full width of the plan grid rather than being held
   to the reading measure the base p rule applies. It is a one-line caption
   sitting beneath a wide row of panels, not a paragraph of prose, so wrapping
   it early leaves it stranded against the left edge of the grid. */
.plan-note { margin-top: var(--s-4); font-size: var(--step--1); color: var(--ink-faint); max-width: none; }

/* ==========================================================================
   FAQ
   ========================================================================== */
.faq { border-top: 1px solid var(--rule); }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary {
  cursor: pointer; padding: var(--s-3) 2rem var(--s-3) 0; font-weight: 600;
  list-style: none; position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+"; position: absolute; right: 0.25rem; top: 50%; transform: translateY(-50%);
  font-family: var(--font-data); color: var(--accent); font-size: 1.2rem;
}
.faq details[open] summary::after { content: "\2212"; }
.faq details > div { padding-bottom: var(--s-3); color: var(--ink-soft); }

/* ==========================================================================
   Gate / notice screens
   ========================================================================== */
.gate {
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius);
  padding: var(--s-4); max-width: 640px;
}
.notice {
  background: var(--warn-bg); border-left: 3px solid var(--mark);
  padding: var(--s-2) var(--s-3); border-radius: var(--radius); margin-bottom: var(--s-4);
}

/* Sign-in / register ------------------------------------------------------
   The panel styling matches the account forms, so signing in and managing an
   account look like the same site. */
/* Sign in and sign up are one form each on their own page, so this is a
   single centred column rather than the two-up layout WooCommerce needed. */
.bet-auth--single {
  max-width: 26rem;
  margin-inline: auto;
}
/* The notices live inside the column now, so they line up with the form
   rather than spanning the wrapper above a narrow box. */
.bet-auth--single .notice { margin-bottom: var(--s-3); }
.bet-auth__panel { margin-top: 0; }
/* Invalid fields -----------------------------------------------------------
   The border alone is not the message: colour is not available to everyone,
   and "something on this page is red" does not say what to change. The reason
   is written under the field it belongs to and tied to it with
   aria-describedby, so it is announced when the field takes focus. */
.bet-input.is-invalid {
  border-color: var(--danger);
  background: var(--danger-bg);
}
/* Stated after, and with the class, so it outranks the shared :focus rule —
   which paints the accent (pine green). A field the browser had just focused
   for being invalid was coming out green, which is the opposite of the
   message. */
.bet-input.is-invalid:focus,
.bet-settings__content input.is-invalid:focus {
  outline: 2px solid var(--danger);
  border-color: var(--danger);
}
.field-error {
  display: block;
  margin-top: 0.3rem;
  color: var(--danger);
  font-size: var(--step--1);
  text-align: left;
}

/* Agreement tickbox. The box and its sentence are one target, aligned at the
   top so a wrapping sentence does not drag the box down the page with it. */
.bet-check {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
  cursor: pointer;
}
.bet-check input[type="checkbox"] {
  flex: 0 0 auto;
  margin: 0.15rem 0 0;
  accent-color: var(--accent);
}
.bet-check a { text-decoration: underline; }
.bet-check input.is-invalid {
  outline: 2px solid var(--danger);
  outline-offset: 2px;
}

.bet-auth__title {
  font-size: var(--step-2);
  margin: 0 0 var(--s-3);
}

/* The fields read as a normal left-aligned form. Only the submit button and
   what follows it are centred, so the card ends on its actions rather than
   centring labels over left-aligned values. */
.bet-auth__panel .bet-account-box__actions { justify-content: center; }
.bet-auth__foot { text-align: center; }
.bet-auth__remember label {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-weight: 400; color: var(--ink-soft);
}

/* The way across to the other form. Always visible, because the failure
   message deliberately will not say whether an account exists. */
/* Inside the form now, under the password reminder, so it reads as part of
   the same block and is left-aligned with everything else in it. */
.bet-auth__switch {
  margin: var(--s-2) 0 0;
  padding-top: var(--s-2);
  border-top: 1px solid var(--rule);
  color: var(--ink-soft);
  font-size: var(--step--1);
  text-align: center;
}
.bet-auth__nudge { display: block; margin-top: 0.35rem; font-size: var(--step--1); }


.bet-machine-id-form .input-text:focus { background: var(--surface); outline: 2px solid var(--accent); outline-offset: 1px; }
.bet-machine-id-form .input-text:disabled { background: var(--surface-2); color: var(--ink-faint); }

/* This class is on two different things: the classic checkout field, which
   wants separating from the order notes above it, and the License panel,
   which does not — it gets its spacing from the account content wrapper like
   every other tab. Without the :not() the License page sat 22px lower than
   Account and Address. */
.bet-machine-id-field:not(.bet-account-box) { margin-top: var(--s-3); }
.bet-machine-id-field input { font-family: var(--font-data) !important; }
.bet-field-help { display: block; font-size: var(--step--1); color: var(--ink-faint); margin-top: 0.3rem; }
.bet-account-box {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: var(--s-3); margin-bottom: var(--s-4);
}
.bet-key {
  font-family: var(--font-data); font-size: 0.85rem; background: var(--surface-2);
  border: 1px solid var(--rule); border-radius: var(--radius); padding: 0.5rem 0.65rem;
  display: block; word-break: break-all;
}
.bet-account-box__actions { margin-top: var(--s-2); display: flex; flex-wrap: wrap; gap: 0.5rem; }
/* Earlier add-on builds, folded under the Download button. */
.bet-previous-releases { margin-top: var(--s-3); }
.bet-previous-releases summary { cursor: pointer; font-weight: 600; }
.bet-previous-releases ul { margin: var(--s-1) 0 0; padding-left: 1.2rem; }
.bet-previous-releases li { margin: 0.25rem 0; }
.bet-previous-releases .bet-field-help { display: inline; margin-left: 0.5rem; }
.bet-plan-change__state { margin-bottom: var(--s-2); }
.bet-plan-change__note { font-size: var(--step--1); color: var(--ink-faint); margin-bottom: 0; }

/* A plan change Stripe is holding until the period ends. Deliberately not
   faint like the note above it: it is a statement about the customer's own
   plan, and the whole point is that it does not get skimmed past. */
.bet-plan-change__pending { font-size: var(--step--1); color: var(--ink); margin: 0 0 var(--s-2); }
/* Cancel sits below a rule so it reads as a separate, deliberate action
   rather than another option in the upgrade block. */
.bet-plan-change__cancel {
  margin-top: var(--s-3); padding-top: var(--s-2);
  border-top: 1px solid var(--rule);
}
/* Cancelled plans state the end date as a facts row. That row carries no
   bottom margin (it is normally the last thing in a panel), so the button
   that follows it here has to supply its own gap. */
.bet-plan-change .bet-license-meta + form { margin-top: var(--s-3); }

/* License facts. Two columns on desktop, stacked on narrow screens; the
   values use the data face because they are literally data. */
.bet-license-meta {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 0.4rem var(--s-3); margin: var(--s-3) 0;
}
.bet-license-meta dt { color: var(--ink-soft); font-size: var(--step--1); }
.bet-license-meta dd { margin: 0; }
@media (max-width: 560px) {
  .bet-license-meta { grid-template-columns: 1fr; gap: 0.15rem; }
  .bet-license-meta dd { margin-bottom: 0.6rem; }
}

/* Page content is a sibling of .section__head rather than a child of it: the
   head is the title block, this is the body, and each carries its own spacing.
   (Both are full wrapper width now — the head used to be capped at --measure,
   which was the original reason for the split.) Prose inside is still held to
   the reading measure; tables, grids and editor blocks get the full width. */
.bet-page-content { margin-bottom: var(--s-4); }
/* Editor content runs the full wrapper width too — see the note on p above. */
.bet-page-content > * + * { margin-top: var(--s-2); }
.bet-page-content img,
.bet-page-content table,
.bet-page-content figure { max-width: 100%; }

/* Wide editor tables scroll inside their own wrapper rather than pushing the
   page sideways.

   Scoped to the editor's own figure, NOT to bare `table`. When WooCommerce
   still rendered Cart, Checkout and My Account through page.php, their markup
   landed inside .bet-page-content too — and display:block on a table detaches its rows from
   the table box, so they shrink-wrap to their content instead of filling the
   width. That is what squashed the cart's Product/Total columns into ~270px of
   a 714px table. */
.bet-page-content .wp-block-table { overflow-x: auto; }

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer { background: var(--ink); color: #b9c2d0; padding-block: var(--s-5) var(--s-4); }
.site-footer a { color: #dfe4ec; text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: underline; }
.footer-grid {
  display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: var(--s-4);
  padding-bottom: var(--s-4); border-bottom: 1px solid rgba(255,255,255,.12);
}
@media (max-width: 860px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: 1fr; } }

/* Stacked brand: mark on top, name beneath, set like the tagline in the
   master lockup — mono, letterspaced, muted — so it reads as part of the logo
   rather than as a second heading repeating what the mark already says. */
/* The footer mark is one colour, and it takes it from here: the SVG paints
   both the disc and the wordmark in currentColor, and the chevron is a hole in
   the disc rather than a shape painted the background colour — so it keeps
   blending in if the footer background ever changes. */
.site-footer .brand--footer { color: #fff; }
.site-footer .brand--footer:hover { color: #dfe4ec; }
.footer-brand .brand__mark svg,
.footer-brand .brand__mark img,
.footer-brand img.brand__mark { height: 46px; }
.footer-brand p { font-size: 0.9rem; margin-top: var(--s-3); max-width: 34ch; }
/* The strapline sits under the mark, close enough to read as part of the
   lockup rather than as the first line of a paragraph. */
.footer-brand__blurb {
  margin-top: var(--s-2);
  font-size: 0.92rem;
  line-height: 1.45;
  color: #9aa4b2;
  max-width: 26ch;
}
.footer-col h4 { color: #fff; font-size: 0.9rem; margin-bottom: var(--s-2); }
.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { padding: 0.22rem 0; font-size: 0.92rem; }

.footer-social { display: flex; align-items: center; gap: 0.5rem; margin-bottom: var(--s-2); }
.footer-social a { display: inline-flex; }
.footer-social svg { width: 26px; height: 26px; fill: #dfe4ec; }
.footer-social a:hover svg { fill: #fff; }

.footer-bottom {
  padding-top: var(--s-3); display: flex; justify-content: space-between;
  gap: var(--s-2); flex-wrap: wrap; font-size: 0.85rem; color: #8d99ac;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* Welcome page ---------------------------------------------------------------
   The two "what next" panels sit side by side on desktop and stack on narrow
   screens. They reuse .bet-account-box so a new customer meets the same panel
   treatment here that they will see on every account page afterwards. */
.bet-welcome__next {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3);
  margin-top: var(--s-4);
}
.bet-welcome__next .bet-account-box { margin: 0; }
.bet-welcome__actions { margin-top: var(--s-3); }
@media (max-width: 700px) {
  .bet-welcome__next { grid-template-columns: 1fr; }
}

/* Risk disclaimer ------------------------------------------------------------
   Sits on the Pricing page between the promotion banner and the plan panels.

   Small print that has to be readable, not decorative: --ink-soft rather than
   --ink-faint so it holds contrast on the page background.

   The paragraphs run the full wrapper width rather than the reading measure.
   The base p rule caps prose at --measure, which is right for body copy but
   left this stranded down the left of a full-width banner and a full-width
   plan grid, reading as an aside rather than as terms that apply to the
   purchase below it. */
.bet-disclaimer { margin: var(--s-4) 0; }
.bet-disclaimer__title {
  font-size: var(--step-0); font-weight: 700; letter-spacing: 0;
  margin-bottom: var(--s-2);
}
.bet-disclaimer p {
  font-size: var(--step--1); color: var(--ink-soft);
  max-width: none; margin-bottom: var(--s-2);
}
.bet-disclaimer__links { margin-bottom: 0; }

/* Opening line of a page's prose. Sized up so the page has somewhere to start
   the eye, without needing a second heading under the title. */
.bet-page-content > p.bet-lead {
  font-size: var(--step-1); color: var(--ink-soft); line-height: 1.45;
}

/* Prose pages: About, Terms, Privacy ---------------------------------------
   32px headings stacked over short paragraphs read as a series of
   announcements rather than something to sit and read. Stepped down to just
   above body size and carried by weight instead, which is what the FAQ
   accordion already does with its questions — same 600 weight, same measure.

   Terms runs to 25 headings and Privacy nests h3 under h2. At this scale the
   two levels are a single pixel apart, so the sub-level is separated by
   colour and spacing rather than size; making h3 smaller than body text to
   win the argument would be worse than the problem. */
.bet-page-prose .bet-page-content h2 {
  font-size: 1.0625rem;
  line-height: 1.5;
  font-weight: 600;
  margin-top: var(--s-4);
}
.bet-page-prose .bet-page-content h3 {
  font-size: 1rem;
  line-height: 1.5;
  font-weight: 600;
  color: var(--ink-soft);
  margin-top: var(--s-3);
}
.bet-page-prose .bet-page-content > p.bet-lead {
  font-size: 1rem;
  line-height: 1.6;
}

/* Business address in the footer contact column. font-style:normal because
   <address> is italic by default in every browser, and this is a postal
   address rather than an aside. */
.footer-address {
  font-style: normal; font-size: 0.85rem; line-height: 1.5;
  color: #9aa4b5; margin-top: var(--s-2);
}

/* Standalone account page (Stripe backend) ---------------------------------- */
.bet-credentials-form .form-row { margin-bottom: var(--s-3); }
.bet-credentials-form label { display: block; margin-bottom: 0.3rem; font-size: var(--step--1); color: var(--ink-soft); }
.bet-credentials-form .input-text { width: 100%; }
.bet-field-note { display: block; margin-top: 0.3rem; font-size: var(--step--1); color: var(--ink-faint); }

/* Two fields on one row. The pair carries the spacing so the columns inside
   it do not add their own, and it collapses to a single column when there is
   not room for two side by side. */
.bet-field-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-3);
}
.bet-field-pair .form-row,
.bet-settings__content .bet-field-pair .form-row { margin-bottom: 0; }
.bet-field-pair__note { margin-top: 0.3rem; }
@media (max-width: 560px) {
  .bet-field-pair { grid-template-columns: 1fr; gap: var(--s-2); }
}

/* ==========================================================================
   Settings (account) — navigation + panels
   ========================================================================== */
.bet-settings {
  display: grid; grid-template-columns: 13rem 1fr; gap: var(--s-4);
  align-items: start;
  /* A floor, so a short tab reads like the rest of the site.
     Download and Discord are a paragraph and a button; without this the whole
     panel collapsed to a few centimetres under a full-width heading while
     every other page filled the screen. Only where the two columns sit side by
     side — on a phone the tabs stack and the height is the content's own. */
  min-height: 24rem;
}
.bet-settings__nav ul {
  list-style: none; margin: 0; padding: 0;
  border-top: 1px solid var(--rule);
}
.bet-settings__nav li { border-bottom: 1px solid var(--rule); }
.bet-settings__nav a {
  display: block; padding: 0.65rem 0.7rem;
  border-left: 2px solid transparent;
  color: var(--ink-soft); font-size: 0.95rem; text-decoration: none;
  transition: color .12s ease, background-color .12s ease, border-color .12s ease;
}
.bet-settings__nav a:hover { color: var(--ink); background: var(--surface-2); }
.bet-settings__nav .is-active a {
  color: var(--ink); font-weight: 600;
  border-left-color: var(--accent); background: var(--surface);
}

/* The panels carry no heading here, so the first one needs no top margin. */
.bet-settings__content > .bet-account-box:first-child { margin-top: 0; }

/* One input treatment everywhere.
   The machine-ID field used WooCommerce's classes and the credentials form
   used its own, so the two looked like different sites. WooCommerce and its
   stylesheet are gone now, and these rules are what holds the field up. */
.bet-input,
.bet-settings__content input[type="text"],
.bet-settings__content input[type="email"],
.bet-settings__content input[type="password"] {
  width: 100%; box-sizing: border-box;
  padding: 0.55rem 0.7rem;
  font-family: inherit; font-size: 0.95rem; line-height: 1.4;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--rule); border-radius: var(--radius);
}
.bet-input:focus,
.bet-settings__content input:focus {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}
.bet-settings__content label {
  display: block; margin-bottom: 0.3rem;
  font-size: var(--step--1); color: var(--ink-soft);
}
.bet-settings__content .form-row { margin-bottom: var(--s-3); }

@media (max-width: 780px) {
  .bet-settings { grid-template-columns: 1fr; gap: var(--s-3); min-height: 0; }
  .bet-settings__nav ul { display: flex; flex-wrap: wrap; border-top: 0; }
  .bet-settings__nav li { border-bottom: 0; }
  .bet-settings__nav a { border-left: 0; border-bottom: 2px solid transparent; padding: 0.5rem 0.6rem; }
  .bet-settings__nav .is-active a { border-left: 0; border-bottom-color: var(--accent); background: transparent; }
}

/* Licence panel matches the machine-ID form directly above it ---------------
   Label above value, same vertical rhythm, no leading margin now that the tab
   navigation supplies the heading. The default two-column facts grid is right
   when a panel stands alone; stacked under a form it reads as a second,
   competing layout in the same column.

   The numbers here are the ones that actually render, not the ones in the
   .bet-machine-id-form block above: inside .bet-settings__content the shared
   .form-row / label / input[type] rules outrank it, so the real rhythm is
   --s-3 between groups and 0.3rem under a label. */
.bet-settings__content .bet-license-meta {
  display: block; margin: 0 0 var(--s-3);
}
.bet-settings__content .bet-license-meta dt {
  display: block; margin-bottom: 0.3rem;
  font-size: var(--step--1); color: var(--ink-soft);
}
.bet-settings__content .bet-license-meta dd { margin: 0; }

/* Box metrics of the machine-ID input, so the key lines up with the field
   above it. The tinted fill stays: the key is read-only, and matching the
   input's background too would invite a click that does nothing. */
.bet-settings__content .bet-key {
  padding: 0.55rem 0.7rem; font-size: 0.95rem; line-height: 1.4;
}

/* How long the promotional price lasts. Sits under the cycle line, quiet
   enough not to compete with the price but present on every discounted plan —
   the panel shows the discounted figure as the price, so this is the part
   that stops that from being a promise we don't keep. */
.plan__promo-terms {
  margin-top: 0.35rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* The machine-ID step that sits between choosing a plan and paying. Spans the
   wrapper like every other panel; no width of its own. */
/* The panel's own title. Sized like a page heading rather than a panel
   heading, because it is the page heading — it just lives inside the box. */
.bet-checkout-step__title {
  margin: 0 0 var(--s-3);
}
.bet-checkout-step__plan {
  margin: 0 0 var(--s-3);
  padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--rule);
  font-weight: 600;
}
.bet-checkout-step__note {
  margin: var(--s-3) 0 0;
  font-size: var(--step--1);
  color: var(--ink-soft);
}
.bet-field-help {
  margin: 0 0 var(--s-3);
  font-size: var(--step--1);
  color: var(--ink-soft);
}
.notice--error {
  border-left: 3px solid var(--danger, #b3261e);
}

/* Shown instead of the key while the vendor call is still in flight. */
.bet-key-pending {
  margin: 0;
  padding: 0.55rem 0.7rem;
  font-size: 0.95rem;
  color: var(--ink-soft);
  background: var(--surface-2);
  border: 1px dashed var(--rule);
  border-radius: var(--radius);
}

/* A button standing in for one that is not available yet. Looks like the
   button it will become, but reads as unavailable and does not respond. */
.btn.is-disabled {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}

/* Staff area -------------------------------------------------------------- */
/* The Manage header: where you are on the left, where you can go on the right.
   Wraps to two rows on a narrow screen rather than squeezing the buttons. */
.bet-staff-head h1 { margin: 0; }
/* The trail sits above; the title and the two ways through share the row under
   it, and wrap rather than squeeze on a narrow screen. */
.bet-staff-head__row {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s-2); margin-top: var(--s-1);
}
.bet-staff-head__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0; }
/* .section__head p paints its children grey; the buttons bring their own. */
.bet-staff-head__actions .btn { color: inherit; }
/* --accent is this site's "active", per the note beside it at the top, so the
   page you are on reads like the primary action rather than inventing a state. */
.bet-staff-head__actions .btn.is-current {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.bet-staff-head__actions .btn.is-current:hover { background: var(--accent-ink); color: #fff; }

.bet-crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin: 0; padding: 0; list-style: none; }
.bet-crumbs li { display: flex; align-items: center; gap: 0.4rem; font-size: var(--step--1); }
/* The separator is drawn rather than written, so it is never read aloud. */
.bet-crumbs li + li::before { content: ">"; color: var(--ink-soft); }
.bet-crumbs [aria-current="page"] { color: var(--ink-soft); }

.bet-staff-search { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.5rem; margin-bottom: var(--s-3); }
.bet-staff-search .bet-input { max-width: 22rem; }

/* The reason a search was ignored belongs under the box, not beside the
   button, so it drops to its own line rather than sharing the row. */
.bet-staff-search .field-error { flex-basis: 100%; margin-top: 0; }

/* The account dropdown. Anchored to the input rather than the form, so it
   opens under the box and not under the Search button, and positioned rather
   than in flow so opening it does not push the table down the page. */
.bet-combo { position: relative; flex: 0 1 22rem; }
.bet-combo .bet-input { max-width: none; width: 100%; padding-right: 4.25rem; }
/* One way out of a search, not two: the browser draws its own cross inside a
   search field, and next to a Clear button that reads as two different
   controls doing the same thing. */
.bet-combo .bet-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* Clearing the box is how you leave a search, so it sits on the box. */
.bet-combo__clear {
  position: absolute; top: 50%; right: 0.35rem; transform: translateY(-50%);
  padding: 0.15rem 0.5rem; border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--surface-2); color: var(--ink-soft);
  font-size: var(--step--1); line-height: 1.6; text-decoration: none; white-space: nowrap;
}
.bet-combo__clear:hover,
.bet-combo__clear:focus { background: var(--surface); color: var(--ink); border-color: var(--ink-faint); }
.bet-combo__list {
  position: absolute; z-index: 20; top: calc(100% + 0.25rem); left: 0; right: 0;
  margin: 0; padding: 0.25rem; list-style: none;
  max-height: 17rem; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.bet-combo__option {
  display: flex; flex-direction: column; gap: 0.1rem;
  padding: 0.45rem 0.55rem; border-radius: var(--radius); cursor: pointer;
}
/* Hover and keyboard share one appearance: a list where the mouse highlights
   one row and the arrow keys highlight another reads as two selections. */
.bet-combo__option:hover,
.bet-combo__option.is-active { background: var(--surface-2); }
.bet-combo__email { font-family: var(--font-data); font-size: 0.85rem; word-break: break-all; }
.bet-combo__name { font-size: var(--step--1); color: var(--ink-soft); }
.bet-combo__note {
  padding: 0.45rem 0.55rem; font-size: var(--step--1); color: var(--ink-soft);
}

.bet-staff-note { margin: 0 0 var(--s-3); color: var(--ink-soft); font-size: var(--step--1); }

.bet-staff-facts {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 0.5rem var(--s-3); margin: 0 0 var(--s-4);
  padding-bottom: var(--s-3); border-bottom: 1px solid var(--rule);
}
.bet-staff-facts dt { color: var(--ink-soft); font-size: var(--step--1); }
.bet-staff-facts dd { margin: 0; }
/* The row number beside the address: still worth having, no longer the thing
   being read. */
.bet-staff-facts dd .bet-staff-note { display: inline; margin-left: 0.4rem; font-size: var(--step--1); }

/* Each action is its own form, so each gets its own boundary — these change
   money and access, and a shared edge invites clicking the wrong button. */
.bet-staff-actions { display: grid; gap: var(--s-3); }
.bet-staff-form {
  padding: var(--s-3);
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--surface-2);
}
.bet-staff-form h3 { margin: 0 0 0.35rem; font-size: 1rem; }
.bet-staff-form label { display: block; margin: var(--s-2) 0 0.3rem; font-size: var(--step--1); color: var(--ink-soft); }
.bet-staff-form .bet-input { max-width: 18rem; }
.bet-staff-form .btn { margin-top: var(--s-2); }
.bet-warn { color: var(--danger, #b3261e); }

.bet-table-scroll { overflow-x: auto; }

/* Under the table, and quiet: the rows are what somebody came to read. The
   spent edge is text rather than a dead link, because a link that goes nowhere
   is a thing people click twice. */
.bet-pager {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--s-2);
  margin-top: var(--s-3); font-size: var(--step--1);
}
.bet-pager__step {
  padding: 0.2rem 0.6rem; border: 1px solid var(--rule); border-radius: var(--radius);
  text-decoration: none; white-space: nowrap;
}
a.bet-pager__step:hover,
a.bet-pager__step:focus { background: var(--surface-2); border-color: var(--ink-faint); }
.bet-pager__step.is-spent { color: var(--ink-faint); border-color: var(--rule); opacity: .55; }

/* A number for every page. The one you are on is the only one that is not a
   link, and it is filled rather than merely bold: at this size weight alone is
   not enough to find at a glance. */
.bet-pager__pages { display: flex; align-items: center; gap: 0.25rem; }
.bet-pager__page {
  min-width: 1.9rem; padding: 0.2rem 0.4rem; text-align: center;
  border: 1px solid transparent; border-radius: var(--radius); text-decoration: none;
}
a.bet-pager__page:hover,
a.bet-pager__page:focus { border-color: var(--rule); background: var(--surface-2); }
.bet-pager__page.is-here {
  background: var(--accent); border-color: var(--accent); color: var(--surface);
  font-variant-numeric: tabular-nums;
}
.bet-pager__gap { padding: 0 0.15rem; color: var(--ink-faint); }
/* ---- one ticket -------------------------------------------------------- */

/* One rhythm down the page. Every section on this view is a heading and then
   a thing, and before this each of those things brought its own margins —
   which is what made the page read as a pile rather than a sequence. */
.bet-staff-detail > h3,
.bet-ticket-split h3 {
  margin: var(--s-4) 0 var(--s-2);
  font-size: 1rem; color: var(--ink-soft);
  text-transform: uppercase; letter-spacing: .04em;
}
.bet-staff-detail > h3:first-of-type,
.bet-ticket-split h3:first-child { margin-top: 0; }
.bet-staff-detail > form { margin-bottom: var(--s-4); }

/* What they wrote on the left, what they sent on the right. A screenshot is
   read against the sentence describing it, and stacked they are never both on
   screen at once — the picture pushes the words off the top exactly when they
   are needed. With nothing attached the conversation takes the whole width:
   an empty second column is worse than no column. */
.bet-ticket-split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 19rem);
  gap: var(--s-4); align-items: start; margin-bottom: var(--s-4);
}
.bet-ticket-split.is-alone { grid-template-columns: minmax(0, 1fr); }
/* The customer's own view of a request, on /support/. Thumbnails in a row:
   they attached these and know what is in them, so the job here is to show
   that they arrived — which is not the job on the staff side, where somebody
   is reading a screenshot they have never seen. Different question, different
   layout, and this is the one that was here first. */
.bet-ticket-shots { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0 0 var(--s-3); }
.bet-ticket-shots img { max-height: 160px; width: auto; border: 1px solid var(--rule); border-radius: var(--radius); }

/* One screenshot at a time, moving sideways. Stacked they put the reply box a
   scroll and a half below the words it answers, and shrunk to fit they are
   unreadable — a licence screen at thumbnail size is a thumbnail nobody can
   use. The track snaps and scrolls with no JavaScript at all; the buttons and
   the counter are the enhancement. */
.bet-shot-carousel__track {
  display: flex; gap: var(--s-2); overflow-x: auto;
  scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: thin;
}
.bet-shot-carousel__item {
  flex: 0 0 100%; scroll-snap-align: start; margin: 0; min-width: 0;
}
.bet-shot-carousel__item img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--rule); border-radius: var(--radius);
}
.bet-shot-carousel__item figcaption {
  margin: 0.35rem 0 0; word-break: break-all;
}
.bet-shot-carousel__nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-2); margin: var(--s-2) 0 0;
}
.bet-shot-carousel__nav .btn { padding: 0.1rem 0.7rem; line-height: 1.5; }
.bet-shot-carousel__nav .btn[disabled] { opacity: .4; cursor: default; }
.bet-shot-carousel__where { font-size: var(--step--1); color: var(--ink-soft); }

@media (max-width: 900px) {
  .bet-ticket-split { grid-template-columns: minmax(0, 1fr); }
  /* Room for the next one's edge, which is what says there is a next one on a
     screen with no hover and no scrollbar to see. */
  .bet-shot-carousel__item { flex-basis: 88%; }
}

@media (prefers-reduced-motion: reduce) {
  .bet-shot-carousel__track { scroll-behavior: auto; }
}

/* The window a screenshot opens into. A picture in a side column is small, and
   a new tab loses the ticket and gives back a bare image with no way to reach
   the next one.

   A real <dialog>, so the focus trap, the Escape key and the inert page behind
   it are the browser's job rather than a pile of listeners that get it nearly
   right. The element IS the backdrop, which is why a click landing on it means
   close. */
.bet-lightbox {
  max-width: min(96vw, 1200px); max-height: 94vh;
  padding: var(--s-2); border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
  overflow: auto;
}
.bet-lightbox::backdrop { background: rgba(20, 27, 42, .72); }
.bet-lightbox__frame { margin: 0; }
/* Whichever runs out first, the picture fits: a tall screenshot must not push
   its own controls off the bottom of the window. */
.bet-lightbox__image {
  display: block; margin: 0 auto;
  max-width: 100%; max-height: calc(94vh - 6.5rem);
  width: auto; height: auto;
  border-radius: var(--radius); background: var(--surface-2);
}
.bet-lightbox__caption {
  margin: var(--s-2) 0 0; font-size: var(--step--1); color: var(--ink-soft);
  text-align: center; word-break: break-all;
}
.bet-lightbox__bar {
  display: flex; align-items: center; justify-content: center;
  gap: var(--s-2); margin: var(--s-2) 0 0;
}
.bet-lightbox__bar .btn { padding: 0.15rem 0.75rem; line-height: 1.6; }
.bet-lightbox__bar .btn[disabled] { opacity: .4; cursor: default; }
.bet-lightbox__count { font-size: var(--step--1); color: var(--ink-soft); font-variant-numeric: tabular-nums; }
/* Away from the stepping, so closing is never the button you meant to press
   twice in a row. */
.bet-lightbox__close { margin-left: auto; }

/* A picture worth opening is worth saying so. */
.bet-shot-carousel__item a,
.bet-ticket-shots a { display: block; cursor: zoom-in; }
/* The two things you can do to this ticket, above the reading: a control you
   reach by scrolling past the conversation is a control you reach after you
   have already decided. The way out is not one of those — it goes at the
   bottom beside the reply, because you leave after answering. */
.bet-staff-detail > .bet-staff-actions { margin: var(--s-3) 0 var(--s-4); }

/* The conversation, oldest at the top, each turn on its own side. Theirs is
   the plain surface and ours carries the accent wash, so who said what is
   answered by looking rather than by reading the line above it. */
.bet-ticket-thread { display: flex; flex-direction: column; gap: var(--s-2); }
.bet-ticket-msg {
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--rule); border-radius: var(--radius);
  max-width: 46rem;
}
.bet-ticket-msg--them { background: var(--surface-2); }
.bet-ticket-msg--us { background: var(--wash-accent); border-color: var(--accent); align-self: flex-end; }
.bet-ticket-msg .bet-staff-note { margin: 0 0 0.35rem; font-size: var(--step--1); }

/* What somebody typed, laid out the way they typed it. Escaped and never
   parsed, so the line breaks are all that survives — but they are the
   difference between a numbered list and one long run-on sentence. */
.bet-ticket-body { white-space: pre-wrap; overflow-wrap: anywhere; }

/* Two across rather than one down. The panels still do not share an edge —
   that is what the gap is for, and it was always the point: each has its own
   border, its own heading and its own button, and none of them acts on a press
   meant for its neighbour. What one column cost was the bottom of the list:
   Role, on an account with a subscription, sat below the fold. */
.bet-staff-actions--columns { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.bet-staff-actions--columns .bet-staff-form { margin: 0; }
.bet-staff-actions--columns .bet-input { max-width: none; width: 100%; }

@media (max-width: 640px) {
  .bet-staff-actions--columns { grid-template-columns: 1fr; }
  .bet-ticket-msg--us { align-self: stretch; }
}


/* While the next table is on its way, the current one is left exactly as it
   is — not faded, not emptied. It is still a true answer to the question asked
   a moment ago, and a table that dims on every keystroke is unreadable at
   typing speed. aria-busy says what is happening for anyone who needs telling;
   on screen the rows simply change when there are new rows. */

/* A row is one record, so the whole row opens it. The reference and the address
   are still real links underneath — this only adds the rest of the row to what
   they already do — but they are drawn as plain text, because fifty underlined
   references read as a page of links rather than as a queue.

   The pointer and the wash are the only things saying the row is clickable, so
   they are not decoration: without them nothing on the page admits it. */
.bet-staff-table tbody tr.bet-row { cursor: pointer; }
.bet-staff-table tbody tr.bet-row:hover { background: var(--surface-2); }
.bet-row__link { color: inherit; text-decoration: none; }
/* Keyboard focus has to be visible somewhere, and the link is the only thing
   in the row that can take it. */
.bet-row__link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px;
}
.bet-row__link:hover { text-decoration: underline; }

/* The letters that were searched for, marked where they landed. Tinted rather
   than the browser's yellow: this is a hint about why a row is here, not a
   warning, and the default fights every other colour on the page. */
.bet-staff-table mark {
  background: var(--search-hit); color: inherit;
  padding: 0 .1em; border-radius: 2px;
}

.bet-staff-table { width: 100%; border-collapse: collapse; font-size: 0.95rem; }
/* What they wrote, on one line. It takes whatever width is left over and the
   rest of the columns keep theirs: a long message should not push the
   reference and the date around. */
.bet-staff-table__gist {
  width: 40%; min-width: 16rem; color: var(--ink-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bet-staff-table th, .bet-staff-table td {
  text-align: left; padding: 0.5rem 0.7rem; border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}
.bet-staff-table th { font-size: var(--step--1); color: var(--ink-soft); font-weight: 600; }

/* The confirmation code box. Wide tracking and a monospaced face so six
   digits read as six digits — a proportional font makes 1 and 7 argue. */
.bet-code-input {
  font-family: var(--font-data);
  font-size: 1.5rem;
  letter-spacing: 0.42em;
  text-align: center;
  padding-inline: 0.6rem;
  /* The tracking adds a trailing gap after the last digit, which throws the
     centring off; half of it back on the left evens it up. */
  text-indent: 0.42em;
}
.bet-verify__lead { margin: 0 0 var(--s-3); color: var(--ink-soft); font-size: var(--step--1); }
.bet-verify-form .bet-account-box__actions { justify-content: center; }

/* A button that has to read as a link, because it does a link's job: it sits
   in a sentence. Only the element is different, and only because the action
   changes something and so must be a POST. */
.bet-linkbtn {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}
.bet-linkbtn:hover { color: var(--accent-ink); }
.bet-linkbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* Two footnotes under one rule, rather than one rule each: the second line is
   an afterthought of the first, not a new section. */
.bet-auth__switch-line { margin: 0 0 var(--s-1); }
.bet-auth__switch-line:last-child { margin-bottom: 0; }

/* Sticky footer --------------------------------------------------------------
   Short pages — sign in, reset a password, confirm an email — did not fill the
   window, so the footer sat halfway up with the page colour below it. The page
   is a column at least as tall as the viewport, and the main region takes up
   whatever slack is left; on a long page it grows past that and the footer
   scrolls away as normal.

   dvh where it exists, because on a phone 100vh is the window with the browser
   chrome *retracted* — using it alone leaves a short page a little taller than
   the screen and scrollable by exactly the height of the address bar. The vh
   line stays first as the fallback.

   The children are the skip link (absolutely positioned, out of flow), the
   header, main, the footer, and a tail of <script> elements the UA stylesheet
   already hides — so nothing else becomes a flex item by accident. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
@supports (min-height: 100dvh) {
  body { min-height: 100dvh; }
}
main { flex: 1 0 auto; }
.site-footer { flex-shrink: 0; }

/* Signed in as staff, WordPress pushes the document down by the height of its
   admin bar. Without this the page is that much taller than the window and
   every short page gains a scrollbar that scrolls nothing. */
body.admin-bar { min-height: calc(100vh - 32px); }
@supports (min-height: 100dvh) {
  body.admin-bar { min-height: calc(100dvh - 32px); }
}
@media screen and (max-width: 782px) {
  body.admin-bar { min-height: calc(100vh - 46px); }
  @supports (min-height: 100dvh) {
    body.admin-bar { min-height: calc(100dvh - 46px); }
  }
}

/* ---------------------------------------------------------------- support */

/* The honeypot. Off-screen rather than display:none on purpose: the crude
   scripts this is meant to catch skip fields that are display:none and fill in
   fields that are merely out of sight. aria-hidden and tabindex="-1" keep it
   away from anybody using a screen reader or a keyboard. */
.bet-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.support-discord { margin-bottom: var(--s-4); }
.support-discord h2,
.support-form h2 { margin-top: 0; }
.support-form textarea.bet-input {
  width: 100%;
  min-height: 9rem;
  resize: vertical;
  font: inherit;
}
.support-alt {
  margin-top: var(--s-3);
  color: var(--ink-soft);
  font-size: var(--step--1);
}

/* Connecting Discord ---------------------------------------------------------
   The settings tab. Two states and no layout of its own: it is a paragraph
   saying which account is connected, a paragraph saying what that has got
   them, and one button. The Disconnect form is separated from the sentences
   above it so it does not read as the next step. */
.bet-discord__note {
  color: var(--ink-faint);
  font-size: var(--step--1);
}
.bet-discord-disconnect {
  margin-top: var(--s-3);
  padding-top: var(--s-2);
  border-top: 1px solid var(--rule);
}

/* ==========================================================================
   NinjaTrader Vendor disclosures (16 September 2026)
   Their guidelines ask for disclosures "in same or similar style text as the
   primary content that is easily visible" — so body size and body colour, not
   the grey small print a footer usually gets.
   ========================================================================== */
.site-disclosures {
  background: var(--surface);
  border-top: 1px solid var(--rule);
  padding-block: var(--s-5);
}
.site-disclosures__title {
  font-size: var(--step-0); font-weight: 700; letter-spacing: 0;
  margin-bottom: var(--s-2);
}
.site-disclosures p {
  font-size: var(--step-0); color: var(--ink-soft);
  max-width: none; margin-bottom: var(--s-2);
}
.site-disclosures p:last-child { margin-bottom: 0; }

/* Beside the hero chart, on the hero's dark ground. Body size and the lede's
   colour, not caption size: NinjaTrader asks for disclosures in text as easy to
   read as the content around them, and this is required reading. */
.shot-disclosure { grid-column: 1 / -1; }
.shot-disclosure p {
  font-size: var(--step-0); color: #c3cad6; line-height: 1.55;
  max-width: none; margin: 0 0 var(--s-2);
}
.shot-disclosure p:last-child { margin-bottom: 0; }
/* The site's link colour is pine, which disappears on the hero's dark ground. */
.shot-disclosure a { color: #fff; text-decoration: underline; text-underline-offset: 2px; }
.shot-disclosure a:hover, .shot-disclosure a:focus-visible { color: #c3cad6; }

/* Where the home page's "Read more" lands: the hypothetical paragraph inside
   the risk disclosure, kept clear of the sticky header. */
.site-disclosures .hypothetical-disclosure { scroll-margin-top: 6rem; }

/* The Platform page: NinjaTrader's and Kinetick's sections from their media
   kit, laid out like their sample — images on the left, copy on the right,
   stacked on a phone. Their kit asks for at least 18px of clear space around
   each logo. Scoped under .bet-page-content on purpose: `.bet-page-content img`
   sets max-width: 100% and outranks a single class, which is how these images
   first rendered the full width of the column. */
.partner {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: var(--s-5); align-items: start;
  margin-block: var(--s-5); padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
}
.partner__media { display: flex; flex-direction: column; align-items: center; }
.bet-page-content .partner__logo {
  display: block; width: 100%; max-width: 280px; height: auto; margin: 24px;
}
.bet-page-content .partner__picture {
  display: block; width: 100%; max-width: 220px; height: auto; margin: 0 auto 24px;
}
.bet-page-content .partner__picture--badge { max-width: 160px; }
.partner__body > h2:first-child { margin-top: 0; }
.partner__cta a { font-weight: 700; font-size: var(--step-1); }
@media (max-width: 760px) {
  .partner { grid-template-columns: 1fr; gap: var(--s-2); }
}
