/* Kostrix — design system stylesheet.

   One look with the marketing site (WG, 25 Sep 2026: "why does the design
   look so different from the home page"): the site's palette, its IBM Plex
   type with serif headings, its mono eyebrow labels and its small corner
   radius, in light and dark. The tokens below mirror website/app/globals.css
   name for name where the two systems overlap; change a colour there and
   here together.

   Deliberate constraints kept from the original sheet:
   - No @import, no CDN. The appliance must render identically in an
     air-gapped VPC and the CSP is default-src 'self'; the three Plex faces
     ship with the binary (static/fonts, SIL OFL 1.1, latin subset) and are
     declared below, with system stacks behind them.
   - No JavaScript. Theming is a server-set cookie rendered as
     <html data-theme="...">; light is the default, dark the override.
     (static/nav.js only centres the active tab and closes the phone menu;
     the shell works the same without it.)

   App-to-site token map (website/app/globals.css). The app keeps its short
   names; the site's names are aliases below so a rule copied across reads
   the same in both:
     --accent      = --primary        --onaccent  = --on-primary
     --surface2    = --surface-2      --line      = --rule
     --ink3        = --ink-3          --field-line = --rule-field
     focus ring    = --focus (the accent)
   Type scale: --fs-2xs 12 / --fs-xs 12 / --fs-sm 13 / --fs-base 14.5 /
   --fs-md 16. 12px is the floor for any text (design audit, 13 Oct 2026:
   11px uppercase mono eyebrows, chips and table headers were hard to read),
   uppercase mono tracks at .08em at most, and form labels and help
   paragraphs are 13px; 16px is what every field uses on a phone so iOS does
   not zoom on focus.
   Breakpoints: <=760 phone (all phone rules), 761-900 tablet header,
   <=980 .cols collapse, <=1100 wide tables scroll themselves, >=1600 the
   nav rejoins the first row as pills. */

@font-face{ font-family:'IBM Plex Sans'; font-style:normal; font-weight:400; font-display:swap; src:url("fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2"); }
@font-face{ font-family:'IBM Plex Sans'; font-style:normal; font-weight:500; font-display:swap; src:url("fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2"); }
@font-face{ font-family:'IBM Plex Sans'; font-style:normal; font-weight:600; font-display:swap; src:url("fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2"); }
@font-face{ font-family:'IBM Plex Sans'; font-style:normal; font-weight:700; font-display:swap; src:url("fonts/ibm-plex-sans-latin-700-normal.woff2") format("woff2"); }
@font-face{ font-family:'IBM Plex Serif'; font-style:normal; font-weight:500; font-display:swap; src:url("fonts/ibm-plex-serif-latin-500-normal.woff2") format("woff2"); }
@font-face{ font-family:'IBM Plex Serif'; font-style:normal; font-weight:600; font-display:swap; src:url("fonts/ibm-plex-serif-latin-600-normal.woff2") format("woff2"); }
@font-face{ font-family:'IBM Plex Mono'; font-style:normal; font-weight:400; font-display:swap; src:url("fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2"); }
@font-face{ font-family:'IBM Plex Mono'; font-style:normal; font-weight:500; font-display:swap; src:url("fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2"); }

/* Light: the site's white paper and near-black ink; petrol is the
   structural colour (links, buttons, the active tab), amber marks what
   needs attention, green is reserved for money. */
:root{
  --canvas:#ffffff; --canvas2:#f4f6f8; --surface:#ffffff; --surface2:#f5f7f9; --raise:#eef1f4;
  --line:#dfe3e7; --line2:#bec6cd;
  --ink:#0b1114; --ink2:#384147; --ink3:#4d565d; --wordmark:#000000;
  --accent:#0e4a51; --accent2:#0a373d; --accent-soft:#e3ecec; --accent-line:rgba(14,74,81,.35);
  --green:#2b6440; --green-soft:#e0ebe1;
  --amber:#8f530d; --amber-soft:#f3e6d0;
  --red:#8a2f28;   --red-soft:#f3ded9;
  --shadow:0 1px 2px rgba(18,23,26,.06), 0 10px 28px -14px rgba(18,23,26,.2);
  --glow:0 0 0 1px var(--line), 0 12px 32px -20px rgba(18,23,26,.25);
  --ui:'IBM Plex Sans',system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --display:'IBM Plex Serif',Georgia,"Times New Roman",serif;
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --onaccent:#f7f5f0;
  --radius:4px; --radius-sm:3px;
  color-scheme:light;
  /* Field borders: --line is 1.3:1 on white, too faint to find an input by;
     this is >=3:1 against both the field and the card. */
  --field-line:#7d868d;
  /* A sixth chart tone, for series that need one more than the semantics. */
  --violet:#6b4fa0;
  /* Page side gutter; the topbar, ticker and main bleed against it. */
  --gutter:18px;
  --fs-2xs:12px; --fs-xs:12px; --fs-sm:13px; --fs-base:14.5px; --fs-md:16px;
  /* Placeholder text: an example, visibly not a value (#8a949b, 3:1 on the
     field; values are --ink). It was --ink3, so an empty billing form read
     as filled in (design audit, 13 Oct 2026). */
  --placeholder:#8a949b;
  /* The site's names for the same tokens (see the map above). Declared on
     the same element as the theme, so they follow it. This also gives the
     older var(--surface-2, ...) uses a real value. */
  --primary:var(--accent); --on-primary:var(--onaccent);
  --surface-2:var(--surface2); --rule:var(--line); --focus:var(--accent);
}
/* Dark: the site's graphite, with its teal in place of petrol. */
[data-theme="dark"]{
  --canvas:#0e1113; --canvas2:#121618; --surface:#171c1f; --surface2:#1e2529; --raise:#1e2529;
  --line:#262d32; --line2:#3b444b;
  --ink:#e9e6df; --ink2:#a7afb5; --ink3:#98a1a8; --wordmark:#ffffff;
  --accent:#74c2c6; --accent2:#a6dcdf; --accent-soft:rgba(116,194,198,.14); --accent-line:rgba(116,194,198,.4);
  --green:#82c08f; --green-soft:#16271b;
  --amber:#d9a25a; --amber-soft:#322619;
  --red:#e08c83;   --red-soft:#2b1a18;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 10px 30px -14px rgba(0,0,0,.7);
  --glow:0 0 0 1px var(--line2), 0 12px 32px -20px rgba(0,0,0,.6);
  --onaccent:#06262a;
  /* Native controls (radios, scroll bars, date pickers) render dark too. */
  color-scheme:dark;
  --field-line:#6b757d;
  --violet:#b39ddb;
  --placeholder:#6f7a82;
}
/* The light block is the default now, so an explicit light stamp needs
   nothing of its own; it is kept as a selector so nothing that targets it
   breaks. */
[data-theme="light"]{ }
/* No stored choice ("auto", the default since the design audit of 13 Oct
   2026): the operating system decides, as it does on the marketing site.
   This repeats the dark block above; change the two together. */
@media (prefers-color-scheme:dark){
  [data-theme="auto"]{
    --canvas:#0e1113; --canvas2:#121618; --surface:#171c1f; --surface2:#1e2529; --raise:#1e2529;
    --line:#262d32; --line2:#3b444b;
    --ink:#e9e6df; --ink2:#a7afb5; --ink3:#98a1a8; --wordmark:#ffffff;
    --accent:#74c2c6; --accent2:#a6dcdf; --accent-soft:rgba(116,194,198,.14); --accent-line:rgba(116,194,198,.4);
    --green:#82c08f; --green-soft:#16271b;
    --amber:#d9a25a; --amber-soft:#322619;
    --red:#e08c83;   --red-soft:#2b1a18;
    --shadow:0 1px 2px rgba(0,0,0,.4), 0 10px 30px -14px rgba(0,0,0,.7);
    --glow:0 0 0 1px var(--line2), 0 12px 32px -20px rgba(0,0,0,.6);
    --onaccent:#06262a;
    color-scheme:dark;
    --field-line:#6b757d;
    --violet:#b39ddb;
    --placeholder:#6f7a82;
    --c1:#74c2c6; --c2:#fb923c; --c3:#c4b5fd; --c4:#86efac; --c5:#f9a8d4; --c6:#93c5fd;
  }
  [data-theme="auto"] svg rect.sv-t-muted, [data-theme="auto"] svg circle.sv-t-muted{ fill:#6b7680; }
  [data-theme="auto"] svg path.sv-t-muted{ stroke:#6b7680; }
  [data-theme="auto"] .chart-legend i.sv-t-muted,
  [data-theme="auto"] .hbars i.sv-t-muted, [data-theme="auto"] .stk-bar i.sv-t-muted,
  [data-theme="auto"] .tl-dot.sv-t-muted, [data-theme="auto"] .vbars i.sv-t-muted{ background:#6b7680; }
}

*{ box-sizing:border-box; }
/* An in-page anchor (#main, a settings section, the authenticator form)
   lands below the sticky header instead of under it. On a phone only the
   44px tab strip stays pinned; above that the whole header does. */
html{ background:var(--canvas); scroll-padding-top:110px; }
@media (max-width:760px){ html{ scroll-padding-top:56px; } }
body{
  margin:0; background:var(--canvas); color:var(--ink);
  font-family:var(--ui); font-size:var(--fs-base); line-height:1.55;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
a{ color:var(--accent); text-decoration:none; }
a:hover{ color:var(--ink); }
::selection{ background:var(--accent-soft); }
/* One focus ring everywhere a keyboard lands: 2px of accent outside the
   element. Fields add a halo of their own (forms, below). */
:focus-visible{ outline:2px solid var(--focus); outline-offset:2px; }
/* "Skip to content": the first thing a keyboard reaches on every page, off
   screen until it is focused. Its target is <main id="main">. */
.skip{
  position:absolute; left:8px; top:-200px; z-index:100;
  padding:10px 16px; border-radius:var(--radius-sm);
  background:var(--accent); color:var(--onaccent);
  font-size:var(--fs-sm); font-weight:600;
}
.skip:focus{ top:8px; color:var(--onaccent); }
@keyframes rise{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }

/* ---------------------------------------------------------------- topbar */
/* The header is two rows: identity (brand, the account under analysis,
   the signed-in user) and, beneath it, the navigation as a tab strip that
   has the whole width to itself. It used to be one 62px row holding all
   ten links, which fit on a wide monitor and on a laptop scrolled
   sideways - the last two tabs (Connect, Settings) lived behind a scroll
   bar nobody noticed. Nothing in the header scrolls now; on a very wide
   window (see the media query below) the strip rejoins the first row. */
.topbar{
  position:sticky; top:0; z-index:40;
  display:flex; flex-wrap:wrap; align-items:center; gap:0 16px;
  min-height:62px; padding:0 var(--gutter);
  background:var(--surface); border-bottom:1px solid var(--line);
}
.topbar > .brand, .topbar > .acctbadge{ margin:8px 0; }
.topbar > .userbox{ margin:8px 0 8px auto; }
.brand{
  display:flex; align-items:center; gap:11px;
  font-family:var(--display); font-size:20px; font-weight:600;
  letter-spacing:-.01em; color:var(--wordmark); white-space:nowrap;
}
.brand b{ font-weight:700; }
/* The mark is a four-colour PNG the brand owns, so it does not inherit the
   text colour. The URL is relative to this stylesheet, which keeps it correct
   under whatever base path the app is mounted on. */
.logo{
  display:inline-block; width:40px; height:33px; flex:none;
  background:url("kostrix-mark.png") center/contain no-repeat;
  font-size:0; color:transparent;
}
.brandtext{ display:flex; flex-direction:column; line-height:1; gap:3px; }
.brandtext .beta{
  font-family:var(--mono); font-size:var(--fs-2xs); font-weight:600;
  letter-spacing:.1em; text-transform:uppercase; color:var(--ink3);
}
/* ---- the account under analysis, in every top bar ----------------------- */
/* This is the largest text in the header on purpose. Every figure on every
   page is a claim about one specific AWS account, and the reader must be able
   to see which one without hunting for it. */
.acctbadge{
  display:flex; flex-direction:column; gap:1px;
  padding:0 14px;
  border-left:1px solid var(--line);
  min-width:0; flex:1 1 auto; max-width:360px;
}
.acct-eyebrow{
  /* the 12px floor at a tighter leading, so the 1280 header keeps its height */
  font-family:var(--mono); font-size:var(--fs-2xs); font-weight:700; line-height:1.25;
  letter-spacing:.08em; text-transform:uppercase; color:var(--ink3);
  white-space:nowrap;
}
.acct-line{ display:flex; align-items:baseline; gap:9px; min-width:0; }
.acct-name{
  font-family:var(--display); font-size:19px; font-weight:700;
  letter-spacing:-.02em; line-height:1.15; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.acct-id{
  font-family:var(--mono); font-size:12.5px; font-weight:600;
  letter-spacing:.01em; color:var(--ink2); white-space:nowrap; flex:none;
}
/* Nothing linked yet is a warning, not a neutral state: the dashboard behind
   it is empty and the reader should not mistake that for a clean account. */
.acctbadge.unset .acct-name{ font-size:15px; color:var(--amber); }
.acctbadge.unset .acct-id{ font-family:var(--ui); font-size:var(--fs-xs); color:var(--ink3); }

/* The tab strip: its own row, full width, never a scroll bar on a desktop.
   Links are underlined tabs here; when the strip rejoins the first row on a
   wide window they become the pills they used to be. At 980px and below it
   is one swipeable row instead (see the tablet/phone header below).
   position:relative makes the nav the tabs' offsetParent, which is what
   static/nav.js measures against to centre the active tab. */
.topbar nav{
  order:10; flex:1 1 100%; display:flex; align-items:stretch; gap:2px;
  margin:0 calc(-1 * var(--gutter)); padding:0 10px; min-height:40px;
  border-top:1px solid var(--line); overflow:visible; flex-wrap:wrap;
  position:relative;
}
.topbar nav a{
  display:inline-flex; align-items:center; padding:0 11px; white-space:nowrap;
  font-size:13.5px; font-weight:600; letter-spacing:-.01em;
  color:var(--ink2); border-bottom:2px solid transparent; margin-bottom:-1px;
  transition:color .16s, border-color .16s, background .16s;
}
.topbar nav a:hover{ color:var(--ink); background:var(--raise); }
.topbar nav a.on{ color:var(--ink); border-bottom-color:var(--accent); }
/* Inside the strip the ring is drawn inward, or the scroll box clips it. */
.topbar nav a:focus-visible{ outline-offset:-2px; }
@media (min-width:1600px){
  .topbar nav{ order:0; flex:1 1 auto; margin:0; padding:0; border-top:0; min-height:0; gap:1px; }
  .topbar nav a{ padding:7px 9px; border-radius:var(--radius-sm); border-bottom:0; margin:0; }
  .topbar nav a.on{ background:var(--accent-soft); box-shadow:inset 0 0 0 1px var(--accent-line); }
}
.userbox{ display:flex; align-items:center; gap:0; flex:none; margin-left:auto; font-size:12.5px; color:var(--ink3); white-space:nowrap; }
/* The links are 36px-tall boxes rather than bare text, so they are a target
   and not a word. The padding replaces the old 12px gap, so the text sits
   where it did; the -6px right margin keeps "Sign out" on the same edge. */
.topbar > .userbox{ margin-right:-6px; }
.userbox a{ display:inline-flex; align-items:center; min-height:36px; padding:0 6px; font-weight:600; color:var(--ink3); }
.userbox a:hover{ color:var(--ink); }
.userbox > .theme-toggle{ margin-right:12px; padding:0; }
.user-email{ max-width:220px; overflow:hidden; text-overflow:ellipsis; color:var(--ink2); }
.userbox > .user-email{ margin-right:6px; }
@media (max-width:980px){
  .user-email{ display:none; }
}
/* The site's sun toggle (website/components/theme-toggle.tsx): a 36px square
   (44 on a phone), the action as its name. One link that steps light ->
   dark -> follow the system (13 Oct 2026). */
.theme-toggle{
  display:inline-flex; align-items:center; justify-content:center; gap:10px;
  width:36px; height:36px; padding:0; flex:none;
  border-radius:var(--radius-sm); border:1px solid var(--line); background:none;
  color:var(--ink2); font-family:var(--ui); font-size:var(--fs-sm); font-weight:600;
  cursor:pointer; transition:border-color .16s, color .16s;
}
.theme-toggle svg{ width:16px; height:16px; flex:none; }
.theme-toggle .theme-word{ display:none; }
.theme-toggle:hover{ border-color:var(--line2); color:var(--ink); }
/* floating toggle for the nav-less auth pages */
.theme-float{ position:fixed; top:18px; right:22px; z-index:50; }
/* On a phone it scrolls away with the page instead of floating over the
   fields and plan tiles, and it is a full 44px target. */
@media (max-width:760px){
  .theme-float{ position:absolute; top:12px; right:16px; }
  .theme-float .theme-toggle{ width:44px; height:44px; }
}

.badge{
  font-family:var(--mono); font-size:var(--fs-2xs); font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; padding:3px 8px; border-radius:var(--radius);
  margin-left:4px; vertical-align:middle; white-space:nowrap;
}
.badge.demo{ background:var(--amber-soft); color:var(--amber); box-shadow:inset 0 0 0 1px var(--amber); }
.badge.org{ background:var(--green-soft); color:var(--green); box-shadow:inset 0 0 0 1px var(--green); }

/* The account menu: on a phone the e-mail, the theme switch, Support,
   Security and Sign out fold into one no-JS <details>; above 760px the
   userbox shows them inline and this is not rendered. */
.usermenu{ display:none; }

/* ------------------------------------------------ tablet + phone header */
/* At 980px and below the badge comes back (it used to be hidden, so a phone
   never said which account a figure was about) in a compact form: the name
   ellipsised, the 12-digit id always. The tabs become one swipeable 44px
   strip rather than wrapping onto two 23px rows. */
@media (max-width:980px){
  .acctbadge{ display:flex; flex:1 1 0; min-width:0; max-width:none; padding-left:10px; }
  /* .acctbadge-qualified: the switcher's base rules sit later in the sheet */
  .topbar > .acctbadge.multi{ max-width:none; }
  .acct-eyebrow, .acctbadge .acct-switch label{ display:none; }
  .acct-line{ min-width:0; }
  .acct-name{ font-size:14px; }
  .acct-id{ font-size:var(--fs-xs); white-space:nowrap; }
  /* "123456789012 - nothing is being scanned" may shrink; a real id never does. */
  .acctbadge.unset .acct-id{ flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; }
  .acctbadge .acct-switch{ min-width:0; }
  .acctbadge .acct-switch select{ height:36px; font-size:var(--fs-md); max-width:100%; min-width:0; }
  /* With 2+ accounts the select is the account display: each option
     already reads "label - 123456789012". A name line above it made the
     768 header 120px tall. */
  .acctbadge.multi .acct-line{ display:none; }
  .acctbadge.multi .acct-switch{ margin:0; }
  .acctbadge.multi .acct-switch select{ width:100%; }
  .acctbadge.multi .acct-switch button{ flex:none; }

  .topbar nav{
    flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden; overscroll-behavior-x:contain;
    scrollbar-width:none; min-height:44px; padding:0 4px; scroll-padding-inline:24px;
    /* the edge fade says "there is more this way" without a scroll bar */
    -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 24px), transparent);
            mask-image:linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 24px), transparent);
  }
  .topbar nav::-webkit-scrollbar{ display:none; }
  .topbar nav a{ min-height:44px; flex:none; }
}

/* Phone: row 1 is 52px (logo, wordmark, the badge, Menu), row 2 the tab
   strip. top:-53px lets row 1 and the strip's top rule scroll away, so
   only the 44px strip (and the ticker while a scan runs) stays pinned. The
   bottom rule is a shadow, not a border, so the pinned part is exactly
   44px. The topbar's own gutter is 12px; nav and ticker bleed against it. */
@media (max-width:760px){
  .topbar{
    --gutter:12px;
    top:-53px; gap:0 10px; padding:0 var(--gutter); min-height:0;
    border-bottom:0; box-shadow:0 1px 0 var(--line);
  }
  .topbar > .brand, .topbar > .acctbadge{ margin:0; }
  .brand{ height:52px; font-size:17px; gap:8px; flex:none; }
  .logo{ width:28px; height:24px; }
  .brandtext .beta, .brand .badge.demo{ display:none; }
  .acctbadge{ padding:0 0 0 10px; border-left:1px solid var(--line); }
  /* name over id: on a 320px phone a name beside the id had ~40px left */
  .acct-line{ flex-direction:column; align-items:flex-start; gap:0; }
  .acct-name{ max-width:100%; line-height:1.2; }
  .acct-id{ line-height:1.35; max-width:100%; }
  .acctbadge.unset .acct-name{ font-size:13.5px; line-height:1.2; }
  .topbar nav{ padding:0 4px; }
  .topbar nav a{ padding:0 12px; font-size:14px; }
  .acctbadge .acct-switch select{ padding:0 20px 0 6px; }
}
/* The Menu: at 980px and below the account items and every section fold
   into one no-JS <details> (it was phone-only, and held only the account
   items). */
@media (max-width:980px){
  .userbox{ display:none; }

  .usermenu{ display:block; position:relative; flex:none; margin-left:auto; }
  .usermenu > summary{
    list-style:none; display:inline-flex; align-items:center; justify-content:center;
    min-width:44px; height:44px; padding:0 10px;
    border:1px solid var(--line); border-radius:var(--radius-sm); background:var(--surface2);
    font-size:var(--fs-sm); font-weight:600; color:var(--ink2); cursor:pointer;
  }
  .usermenu > summary::-webkit-details-marker{ display:none; }
  .usermenu[open] > summary{ border-color:var(--accent-line); color:var(--ink); }
  .usermenu > summary:focus-visible{ outline-offset:-2px; }
  .usermenu-sheet{
    position:absolute; right:0; top:calc(100% + 6px); z-index:45; min-width:220px;
    max-width:calc(100vw - 2 * var(--gutter));
    display:flex; flex-direction:column; padding:6px;
    background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
    box-shadow:var(--shadow);
  }
  .usermenu-sheet a, .usermenu-sheet .theme-toggle{
    display:flex; align-items:center; min-height:44px; height:auto; padding:0 12px;
    font-size:var(--fs-base); font-weight:600; color:var(--ink2);
    border:0; border-radius:var(--radius-sm); background:none;
  }
  .usermenu-sheet a:hover{ background:var(--raise); color:var(--ink); }
  .usermenu-sheet .user-email{
    display:block; max-width:none; padding:8px 12px; overflow-wrap:anywhere;
    font-size:var(--fs-xs); color:var(--ink3); border-bottom:1px solid var(--line);
  }
  .usermenu-sheet .badge.demo{ align-self:flex-start; margin:8px 12px 2px; }
  /* Every section, grouped, above the account items; a divider between. */
  .usermenu-sheet{ max-height:calc(100vh - 120px); max-height:calc(100dvh - 120px); overflow-y:auto; min-width:240px; }
  .usermenu-sheet > *{ flex-shrink:0; }
  .menu-sections{ display:flex; flex-direction:column; padding-bottom:6px; margin-bottom:4px; border-bottom:1px solid var(--line); }
  .menu-group{ padding:10px 12px 2px; font-family:var(--mono); font-size:var(--fs-2xs); font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--ink3); }
  .usermenu-sheet a.on{ color:var(--ink); background:var(--accent-soft); box-shadow:inset 3px 0 0 var(--accent); }
  .usermenu-sheet .theme-toggle{ width:auto; justify-content:flex-start; }
  .usermenu-sheet .theme-toggle .theme-word{ display:inline; }
}
/* With 2+ accounts the select is the account display and each option
   starts with the 12-digit id. Below 380px the id would not fit beside the
   wordmark (the native arrow takes ~16px more than the padding), so the
   wordmark gives way; the logo still links home. Without JavaScript the
   Switch button shares the row, hence the wider query. */
@media (max-width:379px){
  .topbar[data-accounts="multi"] .brandtext{ display:none; }
}
@media (max-width:980px){
  .topbar[data-accounts="multi"]:has(.acct-switch button:not([hidden])) .brandtext{ display:none; }
}

/* --------------------------------------------------------------- banners */
.banner{
  padding:11px 26px; font-size:12.5px; font-weight:500;
  border-bottom:1px solid var(--line);
}
.banner.warn{ background:var(--amber-soft); color:var(--amber); }
.banner.err { background:var(--red-soft);   color:var(--red); }
.banner.okay, .banner.ok{ background:var(--green-soft); color:var(--green); }
/* Text links in a banner take the banner's colour; a button keeps its own.
   The bare ".banner a" beat ".btn" on specificity, so the locked-account
   one-liner's "Start free trial" / "Choose a plan" button printed amber,
   underlined text on the accent fill - a contrast of 1.1 to 1.6. :where()
   keeps the rule's specificity what it was, so nothing else it used to
   outrank or lose to changes. */
.banner a:where(:not(.btn)){ color:inherit; text-decoration:underline; }
@media (max-width:760px){ .banner{ padding:10px var(--gutter); } }

/* ---------------------------------------------------------------- layout */
/* 96px at the foot at every width: the floating chat button (44px, 18px
   off the edge) never sits on the last line of a page (design audit, 13 Oct
   2026; it covered table values at 1280). */
main{ max-width:1380px; margin:0 auto; padding:34px 26px 96px; animation:rise .3s ease both; }
/* A reading page keeps the shared container and left edge, so the heading
   does not jump sideways between tabs; only the content under the heading
   is held to a reading width, left-aligned (design audit, 13 Oct 2026: the
   centred 820px column put the H1 at x=256 on Finding, License, Support and
   Security). */
main.narrow > :not(.page-head){ max-width:820px; }

.page-head{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:24px; flex-wrap:wrap; margin-bottom:22px;
}
.eyebrow{
  font-family:var(--mono); font-size:var(--fs-2xs); font-weight:500; letter-spacing:.08em;
  text-transform:uppercase; color:var(--ink3); margin-bottom:9px;
}
h1,.pagetitle{
  margin:0; font-family:var(--display); font-size:38px; line-height:1.1;
  font-weight:600; letter-spacing:-.015em; color:var(--ink); text-wrap:pretty;
}
h1.hero{ font-size:clamp(26px, 7vw, 44px); line-height:1.02; }
h1 .pop,.pagetitle .pop{ color:var(--green); }
h2{
  margin:0 0 16px; font-family:var(--display); font-size:25px;
  font-weight:600; letter-spacing:-.015em; color:var(--ink);
}
h3{
  margin:0 0 12px; font-family:var(--ui); font-size:15px;
  font-weight:600; letter-spacing:-.01em; color:var(--ink);
  display:flex; align-items:center; justify-content:space-between; gap:12px;
}
h2 .mini, h3 .mini{ font-weight:500; }
.head-actions{ display:flex; gap:9px; align-items:center; flex-wrap:wrap; }

/* minmax(0,1fr), not 1fr: a 1fr track's minimum is its content's
   min-content, so one unbreakable child (the policy template's pre on
   /connect) widened its column past the viewport at desktop widths too. */
/* stretch, not start (design audit, 13 Oct 2026): paired cards share a
   height, so "Daily spend" no longer ends 150px above its neighbour. The
   grid's gap spaces them, so a card in the grid drops its own margin. */
.cols{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:16px; margin-bottom:16px; align-items:stretch; }
.cols > *{ min-width:0; }
.cols > .card{ margin-bottom:0; }
@media (max-width:980px){ .cols{ grid-template-columns:1fr; } }

/* ------------------------------------------------------------------ KPIs */
/* min(…,100%): a 210px track minimum is wider than a 320px phone's content
   box once the gaps are taken off, and the grid overflowed main. */
.kpis{ display:grid; grid-template-columns:repeat(auto-fit,minmax(min(210px,100%),1fr)); gap:14px; margin-bottom:22px; }
/* Five tiles on a tablet wrapped 3+2 with an empty third slot: on a
   six-track grid the first three take two tracks each and the last two take
   three, so both rows are full (design audit, 13 Oct 2026). */
@media (min-width:761px) and (max-width:1199px){
  .kpis:has(> :nth-child(5):last-child){ grid-template-columns:repeat(6,minmax(0,1fr)); }
  .kpis:has(> :nth-child(5):last-child) > *{ grid-column:span 2; }
  .kpis:has(> :nth-child(5):last-child) > :nth-child(n+4){ grid-column:span 3; }
}
main.narrow .kpis{ grid-template-columns:repeat(auto-fit,minmax(min(150px,100%),1fr)); }
main.narrow .kpi .num{ font-size:28px; }
.kpi{
  display:block; padding:20px 22px 18px; border-radius:var(--radius);
  background:var(--surface); border:1px solid var(--line); box-shadow:var(--shadow);
  color:inherit;
}
.kpi .tag{ font-family:var(--mono); font-size:var(--fs-2xs); font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--ink3); }
.kpi .num{
  font-family:var(--display); font-size:36px; font-weight:600; letter-spacing:-.04em;
  line-height:1.15; margin-top:10px; color:var(--ink);
  font-variant-numeric:tabular-nums; text-transform:capitalize;
}
.kpi.green .num{ color:var(--green); }
.kpi.blue  .num, .kpi.accent .num{ color:var(--accent); }
/* A tile's bar with a target: a tick at 70% (the coverage tiles). */
.kpi .bar.target{ position:relative; overflow:visible; }
.kpi .bar.target > b{ position:absolute; left:70%; top:-4px; width:2px; height:11px; background:var(--ink2); border-radius:1px; }
.kpi.amber .num{ color:var(--amber); }
/* Red and amber tiles: the coverage KPIs take the gauge's threshold tone
   (coverageTone), so a tile never reads calmer than the dial beside it. */
.kpi.red   .num{ color:var(--red); }
.kpi.amber .bar i{ background:var(--amber); }
.kpi.red   .bar i{ background:var(--red); }
.kpi .lbl{ margin-top:4px; font-size:12.5px; font-weight:500; color:var(--ink2); }
.kpi .bar{ margin-top:12px; height:3px; border-radius:3px; background:var(--line); overflow:hidden; }
.kpi .bar i{ display:block; height:3px; border-radius:3px; background:var(--accent); }
.kpi.green .bar i{ background:var(--green); }
a.kpi{ transition:transform .18s cubic-bezier(.2,.8,.3,1), box-shadow .18s, border-color .18s; }
a.kpi:hover{ transform:translateY(-4px); box-shadow:var(--glow); border-color:transparent; }

/* ----------------------------------------------------------------- cards */
.card{
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--radius); box-shadow:var(--shadow);
  padding:18px 22px 20px; margin-bottom:16px;
}
.card.flush{ padding:0; overflow:hidden; }

/* ---------------------------------------------------------------- tables */
table{ width:100%; border-collapse:collapse; }
table.wide{
  display:table; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--radius); box-shadow:var(--shadow); overflow:hidden;
  border-spacing:0; margin-bottom:16px;
}
th{
  text-align:left; padding:11px 14px;
  font-family:var(--mono); font-size:var(--fs-2xs); font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; color:var(--ink3);
  background:var(--surface2); border-bottom:1px solid var(--line); white-space:nowrap;
}
.card table th{ background:transparent; padding-left:8px; padding-right:8px; }
td{ padding:11px 14px; border-bottom:1px solid var(--line); vertical-align:top; font-size:13.5px; color:var(--ink); }
.card table td{ padding-left:8px; padding-right:8px; }
tr:last-child td{ border-bottom:none; }
tbody tr:hover td, table.wide tr:hover td{ background:var(--surface2); }
th:first-child, td:first-child{ padding-left:18px; }
.card table th:first-child, .card table td:first-child{ padding-left:8px; }
td.money{
  text-align:right;
  font-family:var(--mono); font-size:14px; font-weight:700; color:var(--green);
  white-space:nowrap; letter-spacing:-.02em; font-variant-numeric:tabular-nums;
}
td.money a{ color:var(--green); }
table td a{ color:var(--ink); font-weight:600; letter-spacing:-.012em; }
table td a:hover{ color:var(--accent); }
/* :not(.btn): "Subscribe" on Settings > Billing is a .btn inside p.mini, and
   ".mini a" (0,1,1) beat ".btn" (0,1,0), so its label was ink3 on the accent
   fill and all but invisible. :where() as for .banner a above. */
td .mini:where(:not(.btn)), .mini a:where(:not(.btn)){ color:var(--ink3); }
.mini a:where(:not(.btn)):hover{ color:var(--accent); }
/* The Realized drill-down's chip (findings.html) holds the view's way out,
   and an ink3 link inside an ink3 sentence, told apart only by hover, was
   not seen as one (R10-VERIFIED-CHIP-LINK-INVISIBLE, WCAG 1.4.1): the
   accent and an underline, as a link in running text. (0,2,2) beats the
   ".mini a" rule above. */
.filters > p.verified-chip a{ color:var(--accent); text-decoration:underline; text-underline-offset:2px; }
.filters > p.verified-chip a:hover{ color:var(--ink); }

/* -------------------------------------------------------- text + chips */
.mini{ font-size:var(--fs-xs); color:var(--ink3); font-weight:500; }
/* Not a button: "remove" on Settings is a .btn.mini inside a cell, and
   picked up the mono face meant for a cell's sub-line. */
td .mini:not(.btn){ font-family:var(--mono); font-size:var(--fs-xs); margin-top:2px; }
/* A help paragraph or footnote is read, not scanned: 13px. Inline .mini
   (a hint beside a field, a cell's sub-line) stays at 12. */
p.mini{ font-size:var(--fs-sm); }
p{ text-wrap:pretty; }
/* Preformatted text scrolls inside itself at every width: Settings' API
   usage block was 90px wider than a 768px page and dragged it sideways. */
pre{ max-width:100%; overflow-x:auto; }
code{
  font-family:var(--mono); font-size:var(--fs-xs);
  background:var(--canvas2); color:var(--ink2);
  padding:2px 6px; border-radius:var(--radius-sm); border:1px solid var(--line);
  /* a wrapped code keeps its padding and border on every line */
  -webkit-box-decoration-break:clone; box-decoration-break:clone;
}
/* Short identifiers (account ids, regions, dates, API names) never break
   mid-token; only code.arn and free text may break anywhere. */
.nowrap, code.ident{ white-space:nowrap; overflow-wrap:normal; }
/* At every width, not only phones: now that .cols tracks are minmax(0,1fr),
   an unbreakable ARN in a half-width card (/connect's kv-table at 990)
   would otherwise run past the card's edge. */
.card code.arn, td code.arn{ overflow-wrap:anywhere; }
/* A chip may wrap rather than push its box wider than its container; in a
   table row it stays on one line, as before. */
.chip{
  display:inline-block; font-size:var(--fs-2xs); font-weight:700; letter-spacing:.04em;
  text-transform:uppercase; padding:3px 9px; border-radius:var(--radius);
  background:var(--raise); color:var(--ink2); white-space:normal; max-width:100%;
}
td .chip{ white-space:nowrap; }
.chip.ok{ background:var(--green-soft); color:var(--green); }
.chip.warn{ background:var(--amber-soft); color:var(--amber); }
.chip.high, .chip.st-done, .chip.st-active{ background:var(--green-soft); color:var(--green); }
.chip.medium, .chip.mid, .chip.st-planned, .chip.st-read-only, .chip.st-demo{ background:var(--amber-soft); color:var(--amber); }
.chip.low, .chip.st-locked{ background:var(--red-soft); color:var(--red); }
.chip.st-open{ background:var(--accent-soft); color:var(--accent); }
.chip.st-dismissed, .chip.st-snoozed{ background:var(--raise); color:var(--ink3); }
/* AWS's second opinion (13 Oct 2026): three answers, three tones. "Kostrix
   only" is neutral on purpose - it is AWS's silence, not a verdict. */
.chip.opinion-agrees{ background:var(--green-soft); color:var(--green); }
.chip.opinion-kostrix{ background:var(--raise); color:var(--ink2); }
.chip.opinion-aws{ background:var(--accent-soft); color:var(--accent); }
.card.opinion.agrees{ border-left:4px solid var(--green); }
.card.opinion.kostrix{ border-left:4px solid var(--line); }
.card.opinion.aws{ border-left:4px solid var(--accent); }
.card.opinion-card p{ margin:0 0 8px; }

/* ------------------------------------------------------------- compare */
/* The month-vs-month page. Deltas carry a polarity class chosen by the
   template, because "up" is bad for a bill and good for a realized saving;
   the colours are the theme's own. */
.delta{ font-family:var(--mono); font-size:12px; font-weight:700; white-space:nowrap; font-variant-numeric:tabular-nums; }
.delta.bad { color:var(--red); }
.delta.warn{ color:var(--amber); }
.delta.good{ color:var(--green); }
.delta.flat{ color:var(--ink3); font-weight:600; }
.kpi .num .arrow{ color:var(--ink3); font-size:22px; font-weight:400; vertical-align:middle; }
.kpi .num.muted{ color:var(--ink3); font-size:24px; text-transform:none; }
.compare-picker{ gap:12px; }
.compare-picker .picker-field{ display:inline-flex; align-items:center; gap:7px; margin:0; font-size:12px; font-weight:700; color:var(--ink3); }
.compare-picker .picker-field select{ display:inline-block; width:auto; margin:0; height:34px; }
.compare-picker .mini{ flex-basis:100%; }
.notes{ margin:0 0 18px; }
.notes .banner{ border:1px solid var(--line); border-radius:var(--radius); padding:11px 14px; margin-bottom:8px; }
.compare-table td.num{ text-align:right; white-space:nowrap; }
.compare-table tr.total td{ background:var(--surface2); }
.compare-table td.count{ font-family:var(--mono); font-weight:700; font-variant-numeric:tabular-nums; }
.chip.tag-new { background:var(--accent-soft); color:var(--accent); margin-left:6px; }
.chip.tag-gone{ background:var(--raise); color:var(--ink3); margin-left:6px; }
.card.quiet p{ margin:0 0 8px; }
svg .sv-value.sv-muted{ fill:var(--ink3); font-weight:600; }

/* ----------------------------------------------------------------- forms */
.filters{
  display:flex; flex-wrap:wrap; align-items:center; gap:8px;
  padding:12px 14px; margin:0 0 14px;
  border-radius:var(--radius); background:var(--surface);
  border:1px solid var(--line); box-shadow:var(--shadow);
}
/* Fields sit on the card colour with a border that is >=3:1 against it, so
   an empty input reads as an input and not as a faint rectangle. */
input, select, textarea{
  font-family:var(--ui); font-size:var(--fs-sm); font-weight:500; color:var(--ink);
  background:var(--surface); border:1px solid var(--field-line);
  border-radius:var(--radius-sm); padding:0 10px; height:34px;
}
::placeholder{ color:var(--placeholder); opacity:1; }
/* The ring plus a soft halo; the outline survives forced-colours mode,
   where box-shadow is dropped. */
input:focus-visible, select:focus-visible, textarea:focus-visible{
  outline:2px solid var(--focus); outline-offset:0;
  border-color:var(--accent); box-shadow:0 0 0 5px var(--accent-soft);
}
input[type=checkbox]{ height:auto; accent-color:var(--accent); }
input[type=radio]{ accent-color:var(--accent); }
input[type=checkbox]:focus-visible, input[type=radio]:focus-visible{ outline-offset:2px; box-shadow:none; }
form label{ display:block; margin-bottom:12px; font-size:var(--fs-sm); font-weight:600; color:var(--ink2); }
form label input, form label select{ display:block; width:100%; margin-top:5px; height:38px; font-weight:500; }
/* A textarea under a label (support ticket, replies): block and full
   width like an input, but as tall as its rows say and padded on all
   sides, or it renders as a 34-pixel strip beside its label. */
form label textarea{ display:block; width:100%; margin-top:5px; height:auto; min-height:90px; padding:8px 10px; font-weight:500; line-height:1.45; resize:vertical; }
/* checkboxes and radios must not inherit the block/full-width treatment above */
form label input[type=checkbox],
form label input[type=radio]{
  display:inline-block; width:auto; height:auto; margin-top:2px; flex:none;
}
select{ cursor:pointer; }

button, .btn{
  display:inline-flex; align-items:center; justify-content:center;
  height:36px; padding:0 15px; border-radius:var(--radius-sm);
  border:1px solid transparent; background:var(--accent); color:var(--onaccent);
  font-family:var(--ui); font-size:13px; font-weight:600;
  cursor:pointer; white-space:nowrap; transition:filter .16s, border-color .16s, color .16s;
}
button:hover, .btn:hover{ background:var(--accent2); color:var(--onaccent); }
.btn.green, button.green{ background:var(--green); }
.btn.ghost, button.ghost{ background:var(--surface); color:var(--ink2); border-color:var(--line); }
.btn.ghost:hover, button.ghost:hover{ filter:none; border-color:var(--accent-line); color:var(--ink); }
.btn.mini, button.mini{ height:30px; padding:0 10px; font-size:var(--fs-xs); }
/* A submit that is working (challenge.js, paywall.js) reads as busy, not dead. */
button:disabled{ opacity:.7; cursor:progress; }
.inline-form{ display:flex; gap:9px; align-items:center; flex-wrap:wrap; margin:10px 0; }
.inline-form + .inline-form{ margin-top:0; }
.spacer{ flex:1; }

/* Layout utilities the templates already name (support, subscribe,
   settings) but that had no rules, so their forms ran together. */
.actions{ display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin-top:14px; }
.stack > * + *{ margin-top:12px; }
.fields.cols-2, .fields.cols-3{ display:grid; gap:0 14px; min-width:0; }
.fields.cols-2{ grid-template-columns:repeat(2, minmax(0,1fr)); }
.fields.cols-3{ grid-template-columns:repeat(3, minmax(0,1fr)); }
.fields > *{ min-width:0; }
@media (max-width:720px){ .fields.cols-2, .fields.cols-3{ grid-template-columns:minmax(0,1fr); } }
/* A checkbox and its sentence: one row, the whole row is the target. */
label.check{ display:flex; align-items:center; gap:10px; min-height:44px; margin-bottom:6px; color:var(--ink2); font-weight:500; }
label.check input{ margin:0; flex:none; }

/* ------------------------------------------------ phone + touch targets */
/* Every field is 16px on a phone (iOS zooms the page on focus below that)
   and every labelled field, button and submit is a 44px target. Secondary
   buttons (.mini) are 40px wherever the pointer is a finger. */
@media (max-width:760px){
  input:not([type=checkbox]):not([type=radio]), select, textarea{ font-size:var(--fs-md); }
  form label{ font-size:var(--fs-sm); }
  form label input:not([type=checkbox]):not([type=radio]), form label select{ height:44px; }
  input[type=checkbox], input[type=radio],
  form label input[type=checkbox], form label input[type=radio],
  label.ack input, label.choice input{ width:18px; height:18px; }
}
@media (max-width:760px), (pointer:coarse){
  .btn.mini, button.mini{ min-height:40px; padding-inline:14px; font-size:var(--fs-xs); }
}

/* ------------------------------------------------------------- auth card */
.authcard{
  width:100%; max-width:440px; margin:8vh auto;
  padding:34px 34px 30px; border-radius:var(--radius);
  background:var(--surface); border:1px solid var(--line); box-shadow:var(--glow);
}
/* The heading and its Beta badge share a line (the badge used to be a 9px
   line of its own under the h1); the logo is a block so it stays above. */
.authcard h1{ display:inline-block; margin-right:10px; vertical-align:middle; font-size:30px; }
.authcard .logo{ display:block; width:64px; height:52px; margin-bottom:18px; }
/* The mark is a link to the site (design audit C17). It stays a block on its
   own line, as the bare logo was: an inline-block link sat on the same line as
   the inline h1, stepping the wordmark down and to the right of the logo
   (WG screenshot, 14 Oct 2026). width:max-content keeps the link - and its
   focus ring - the size of the logo, not the card. */
.authcard .authbrand{ display:block; width:max-content; margin-bottom:18px; border-radius:var(--radius); }
.authcard .authbrand .logo{ margin-bottom:0; }
.authcard .authbrand:focus-visible{ outline:2px solid var(--focus); outline-offset:3px; }
.authcard .beta{
  display:inline-block; vertical-align:middle; padding:2px 7px;
  border:1px solid var(--line2); border-radius:var(--radius-sm);
  font-family:var(--mono); font-size:var(--fs-2xs); line-height:1.4;
  font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--ink3);
}
.authcard .sub{ margin:8px 0 20px; font-size:13.5px; color:var(--ink2); }
/* A line under a form (links, the code's lifetime) sits close to it. */
.authcard form + .sub, .authcard .sub + .sub{ margin:12px 0 12px; }
.authcard button, .authcard .btn{ width:100%; height:42px; font-size:14px; margin-top:6px; }
.authcard form label{ margin-bottom:12px; font-size:12.5px; }
.authcard label.ack input{ width:18px; height:18px; margin-top:1px; }
/* "Send a new code" is the secondary action: the Google button's ghost
   treatment, so it never reads as a second Verify. */
.authcard form.resend{ margin-top:10px; }
.authcard .resend button{ background:var(--surface); color:var(--ink2); border-color:var(--line2); }
.authcard .resend button:hover{ background:var(--surface); color:var(--ink); border-color:var(--accent-line); }
/* The 429 card's two ways out, stacked like the auth buttons. */
.authcard .auth-actions{ display:flex; flex-direction:column; margin:18px 0 0; }
/* The plan picker on sign-up: no fieldset box inside the card. */
.signup-plans{ border:0; padding:0; margin:0 0 18px; min-width:0; }
.signup-plans legend{ padding:0; font-size:13px; font-weight:600; color:var(--ink); }
.signup-plans .po-price{ font-size:var(--fs-sm); font-weight:600; color:var(--ink2); }
@media (max-width:480px){ .signup-plans .plan-grid{ grid-template-columns:minmax(0,1fr); gap:8px; } }
/* Busy (challenge.js): every button in the form is disabled while the
   browser check runs; a small ring says it is working. */
.authcard button:disabled::after{
  content:""; flex:none; width:14px; height:14px; margin-left:9px;
  border:2px solid currentColor; border-right-color:transparent; border-radius:50%;
  animation:spin .8s linear infinite;
}
@keyframes spin{ to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce){ .authcard button:disabled::after{ animation:none; } }
/* Phones: the card is the page. No box, no shadow, a smaller mark and
   heading, so the first field is in the first screen. */
@media (max-width:480px){
  .authcard{ margin:56px 0 24px; padding:8px 16px 28px; border:0; border-radius:0; box-shadow:none; background:none; }
  .authcard .logo{ width:44px; height:36px; margin-bottom:12px; }
  .authcard .authbrand{ margin-bottom:12px; }
  .authcard h1{ font-size:26px; }
}
.qr{ display:block; background:#fff; padding:8px; border-radius:var(--radius); border:1px solid var(--line); }
code.secret{ font-family:var(--mono, monospace); letter-spacing:.06em; user-select:all; }
/* Two columns only where two fit: at 320 a 12-character code per column
   ran into its neighbour. */
.recovery-codes{ font-family:var(--mono, monospace); font-size:15px; line-height:1.7; letter-spacing:.06em; background:var(--surface2); padding:12px 16px; border-radius:var(--radius); border:1px solid var(--line); user-select:all; white-space:pre; overflow-x:auto; }
@media (min-width:341px){ .recovery-codes{ columns:2; } }
/* "Continue with Google" (google.go): a ghost button under the primary
   one, separated by an "or" rule. */
.authcard .or{ display:flex; align-items:center; gap:10px; margin:14px 0 8px; color:var(--ink3); font-size:12px; }
.authcard .or::before, .authcard .or::after{ content:""; flex:1; border-top:1px solid var(--line); }
.authcard button.google{ background:var(--surface); color:var(--ink); border-color:var(--line2); }
.authcard button.google::before{ content:"G"; display:inline-block; width:20px; height:20px; margin-right:9px; border-radius:50%;
  background:#fff; color:#4285f4; font-weight:800; font-size:13px; line-height:20px; text-align:center; border:1px solid var(--line); }
.authcard button.google:hover{ background:var(--surface); color:var(--ink); border-color:var(--accent-line); }
.authcard .banner{ border:1px solid var(--line); border-radius:var(--radius); padding:11px 14px; margin:14px 0 16px; }
.disclaimer{
  padding:13px 15px; margin:14px 0 18px; border-radius:var(--radius);
  background:var(--amber-soft); border:1px solid var(--line);
  font-size:12px; color:var(--ink2);
}
.disclaimer b, .disclaimer summary{ color:var(--amber); font-weight:700; }
.disclaimer p{ margin:6px 0 0; }
/* Sign-up's disclaimer is a details element, open by default. Above 760
   the summary is just its heading; on a phone it is a 44px row that folds
   the two paragraphs away. */
details.disclaimer > summary{ min-height:0; list-style:none; cursor:default; pointer-events:none; }
details.disclaimer > summary::-webkit-details-marker{ display:none; }
@media (max-width:760px){
  details.disclaimer{ padding-block:0; }
  details.disclaimer > summary{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    min-height:44px; cursor:pointer; pointer-events:auto;
  }
  details.disclaimer > summary::after{ content:"+"; font-size:18px; line-height:1; }
  details.disclaimer[open] > summary::after{ content:"\2212"; }
  details.disclaimer[open]{ padding-bottom:13px; }
}
.trial-card{
  display:flex; flex-direction:column; gap:4px; margin:0 0 12px;
  padding:11px 14px; border:1px solid var(--green); border-radius:var(--radius);
  background:var(--green-soft); color:var(--ink);
}
.trial-card b{ color:var(--green); font-size:13px; }
.paywall .tile-pay{ cursor:pointer; }
/* The tile's call to action fills the tile: it is the target, and at 13px
   inside a 180px tile a 26px pill was too small to aim at. */
.paywall .tile-pay .tile-cta{ display:flex; align-self:stretch; margin-top:10px; min-height:40px; height:auto; padding:6px 12px; font-size:var(--fs-sm); }
.paywall .tile-pay:hover{ border-color:var(--accent); }
.paywall .paywall-fields{ margin-top:14px; }
label.ack{
  display:flex; gap:9px; align-items:flex-start;
  font-size:12px; font-weight:500; color:var(--ink2); margin:14px 0 16px; cursor:pointer;
}
label.ack input{ margin-top:2px; flex:0 0 auto; }
label.ack span{ flex:1 1 auto; line-height:1.55; }
label.ack a{ font-weight:600; }

/* ------------------------------------------------- connect page choices */
label.choice{
  display:flex; gap:11px; align-items:flex-start;
  padding:12px 14px; margin-bottom:9px;
  border:1px solid var(--line); border-radius:var(--radius); background:var(--surface2);
  cursor:pointer; font-size:13px; font-weight:500; color:var(--ink2);
  transition:border-color .14s, background .14s;
}
label.choice:hover{ border-color:var(--accent-line); }
label.choice:has(input:checked){ border-color:var(--accent); background:var(--accent-soft); }
label.choice input{ width:15px; height:15px; margin-top:3px; flex:none; }
label.choice > span{ flex:1; min-width:0; }
label.choice b{ display:block; font-size:13.5px; font-weight:600; color:var(--ink); }
label.choice em{ display:block; margin-top:3px; font-style:normal; font-size:12px; color:var(--ink3); }
.err-note{ color:var(--red); }

/* ---------------------------------------------------------------- footer */
/* Sentence case at a readable size: the second line is a statement about
   how the customer's account is handled, not a label. */
footer{
  padding:26px 26px 88px; text-align:center; border-top:1px solid var(--line);
  font-family:var(--ui); font-size:var(--fs-xs); letter-spacing:0;
  text-transform:none; line-height:1.5; color:var(--ink3);
}
footer p{ margin:0 auto; max-width:760px; }
footer .foot-ver{ font-family:var(--mono); margin-bottom:4px; }
/* 88px at the foot at every width so the floating chat button never sits
   on the last line (it hid the end of the version line at 1280). */
@media (max-width:760px){ footer{ padding:20px var(--gutter) 88px; } }

/* --------------------------------------------------- opportunity blocks */
.section-note{ margin:-10px 0 14px; }
/* min(330px,100%): at 320 a 330px minimum track clipped every card's right
   edge, dollar figures included. */
.blocks{ display:grid; grid-template-columns:repeat(auto-fit,minmax(min(330px,100%),1fr)); gap:14px; margin-bottom:26px; }
.block{
  display:flex; flex-direction:column; min-width:0;
  padding:18px 20px 14px; border-radius:var(--radius);
  background:var(--surface); border:1px solid var(--line); box-shadow:var(--shadow);
  border-left:3px solid var(--accent);
}
.block.green{ border-left-color:var(--green); }
.block.amber{ border-left-color:var(--amber); }
.block.red  { border-left-color:var(--red); }
.block.muted{ border-left-color:var(--line2); }
.block-head{ display:block; color:inherit; }
.block-head:hover .block-title{ color:var(--accent); }
.block-title{
  font-family:var(--ui); font-size:15px; font-weight:600;
  letter-spacing:-.02em; color:var(--ink);
  transition:color .14s;
}
.block-title::first-letter{ text-transform:uppercase; }
.block-amt{
  margin-top:6px; font-family:var(--display); font-size:30px; font-weight:600;
  letter-spacing:-.04em; color:var(--green); font-variant-numeric:tabular-nums;
}
.block-amt span{ font-size:13px; font-weight:500; color:var(--ink3); letter-spacing:0; }
.block-meta{
  display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-top:8px;
  font-size:var(--fs-xs); font-weight:600; color:var(--ink2);
}
.block-meta .pct{
  padding:2px 8px; border-radius:var(--radius);
  background:var(--accent-soft); color:var(--accent); font-weight:700;
}
.block-action{
  margin:12px 0 10px; padding-top:12px; border-top:1px solid var(--line);
  font-size:12.5px; color:var(--ink2);
}
.block-res{ list-style:none; margin:0; padding:0; }
.block-res li + li{ margin-top:2px; }
.block-res a{
  display:flex; align-items:center; gap:10px; padding:5px 8px; margin:0 -8px; min-height:40px;
  border-radius:var(--radius-sm); color:var(--ink2); transition:background .14s;
}
.block-res a:hover{ background:var(--surface2); color:var(--ink); }
/* width:0 drops the code's min-content contribution: an ELB ARN is one
   663px nowrap word, and in an auto-layout table cell (the /findings Pools
   rows) it widened the whole table past the page. It still grows to fill. */
.block-res code{ flex:1 1 0px; width:0; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; background:none; border:none; padding:0; }
.block-res .r-region{ font-family:var(--mono); font-size:var(--fs-2xs); color:var(--ink3); }
.block-res b{ font-family:var(--mono); font-size:12px; color:var(--green); font-variant-numeric:tabular-nums; }
.block-res .more a{ font-size:var(--fs-xs); font-weight:700; color:var(--accent); }

/* ------------------------------------------ server-rendered inline SVG */
/* sparkline / service bars / month bars / relation diagram all emit
   classes rather than literal hex, so they follow the active theme. */
svg.chart{ display:block; width:100%; height:auto; overflow:visible; }
/* Chart type is set in drawing units, so a chart scaled down draws it
   smaller. --k undoes that: --vbw is the drawing width (charts.go puts it on
   every SVG), --cw the width the chart is shown at, rounded down to a step
   by the container queries under "charts: type at any scale" below. With
   no step (a chart at its full width) --k is 1. */
svg.chart{ --k:calc(var(--vbw, 1) / min(var(--vbw, 1), var(--cw, 100000))); }
svg.chart.gauge{ margin:0 auto; }
svg .sv-line  { fill:none; stroke:var(--accent); stroke-width:2; stroke-linejoin:round; stroke-linecap:round; }
svg .sv-area  { fill:var(--accent-soft); stroke:none; }
svg .sv-bar   { fill:var(--accent); }
svg .sv-bar-g { fill:var(--green); }
svg .sv-track { fill:var(--canvas2); }
svg .sv-grid  { stroke:var(--line); stroke-width:1; stroke-dasharray:3 4; }
svg .sv-tick  { fill:var(--ink3); font-family:var(--mono); font-size:calc(12px * var(--k, 1)); letter-spacing:.02em; }
svg .sv-dot   { fill:var(--accent); stroke:var(--surface); stroke-width:2; }
svg .sv-bubble{ fill:var(--accent); fill-opacity:.75; }
/* The scatter's tap area around each bubble (charts.go): painted, so it
   takes the pointer, but never seen. */
svg .sv-hit{ fill:var(--ink); fill-opacity:0; pointer-events:all; }
svg .sv-gauge-track{ stroke:var(--line); }
svg .sv-gauge { stroke:var(--accent); }
svg .sv-gauge-num{ font-family:var(--display); font-size:42px; font-weight:600; letter-spacing:-.03em; fill:var(--ink); }
svg .sv-label { fill:var(--ink2); font-family:var(--ui); font-size:calc(12px * var(--k, 1)); }
svg .sv-value { fill:var(--ink); font-family:var(--mono); font-size:calc(12px * var(--k, 1)); font-weight:700; }
svg .sv-axis  { stroke:var(--line); stroke-width:1; }

/* Semantic mark tones. Filled marks (bars, bubbles) take fill; the gauge is
   a stroked path, and the legend swatch is a plain element background. */
svg rect.sv-t-accent, svg circle.sv-t-accent{ fill:var(--accent); }
svg rect.sv-t-green,  svg circle.sv-t-green { fill:var(--green); }
svg rect.sv-t-amber,  svg circle.sv-t-amber { fill:var(--amber); }
svg rect.sv-t-red,    svg circle.sv-t-red   { fill:var(--red); }
svg rect.sv-t-muted,  svg circle.sv-t-muted { fill:var(--line2); }
svg rect.sv-t-violet, svg circle.sv-t-violet{ fill:var(--violet); }
svg rect.sv-t-prior,  svg circle.sv-t-prior { fill:var(--ink3); }
/* Dark: line2 is 1.6:1 on the track; this grey is >=3:1, so a "later"
   bucket or a muted segment is still a mark. */
[data-theme="dark"] svg rect.sv-t-muted, [data-theme="dark"] svg circle.sv-t-muted{ fill:#6b7680; }
[data-theme="dark"] svg path.sv-t-muted{ stroke:#6b7680; }
[data-theme="dark"] .chart-legend i.sv-t-muted{ background:#6b7680; }
svg path.sv-t-accent{ stroke:var(--accent); }
svg path.sv-t-green { stroke:var(--green); }
svg path.sv-t-amber { stroke:var(--amber); }
svg path.sv-t-red   { stroke:var(--red); }
svg path.sv-t-muted { stroke:var(--line2); }
svg path.sv-t-violet{ stroke:var(--violet); }
svg text.sv-t-accent{ fill:var(--accent); }
svg text.sv-t-green { fill:var(--green); }
svg text.sv-t-amber { fill:var(--amber); }
svg text.sv-t-red   { fill:var(--red); }
svg text.sv-t-muted { fill:var(--ink2); }
svg a:hover rect.sv-bar, svg a:hover circle.sv-bubble{ filter:brightness(1.18); }
/* The scatter's bubble follows its link (charts.go) and lets the pointer
   through to the link's hit circle beneath it. */
svg.chart.scatter .sv-bubble{ pointer-events:none; }
svg.chart.scatter a:hover + circle.sv-bubble{ filter:brightness(1.18); }
svg a:hover .sv-text, svg a:hover .sv-label{ fill:var(--accent); }

.chart-legend{ display:flex; flex-wrap:wrap; gap:14px; margin-top:10px; }
.chart-legend .lg{ display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-xs); font-weight:600; color:var(--ink2); }
.chart-legend i{ width:9px; height:9px; border-radius:3px; background:var(--accent); }
.chart-legend i.sv-t-green{ background:var(--green); }
.chart-legend i.sv-t-amber{ background:var(--amber); }
.chart-legend i.sv-t-red  { background:var(--red); }
.chart-legend i.sv-t-muted{ background:var(--line2); }
.chart-legend i.sv-t-violet{ background:var(--violet); }
.chart-legend i.sv-t-prior{ background:var(--ink3); }
.chart-empty{ margin:18px 0; font-size:12.5px; color:var(--ink3); font-style:italic; }
svg .sv-node  { fill:var(--surface2); stroke:var(--line2); stroke-width:1; }
svg .sv-node-hi{ fill:var(--accent-soft); stroke:var(--accent); stroke-width:1.5; }
svg .sv-edge  { stroke:var(--line2); stroke-width:1.5; fill:none; }
svg .sv-text  { fill:var(--ink); font-family:var(--ui); font-size:calc(12px * var(--k, 1)); font-weight:600; }
svg .sv-sub   { fill:var(--ink3); font-family:var(--mono); font-size:calc(12px * var(--k, 1)); }
svg a:hover .sv-bar{ filter:brightness(1.15); }

/* relation diagram on the finding page — containers keep their semantic
   roles (VPC / AZ / focal resource) but take their colour from the theme.
   Per-kind node badge colours stay as inline attributes. */
svg .dg-zone   { fill:var(--accent-soft); stroke:var(--accent); }
svg .dg-zone-t { fill:var(--accent); font-family:var(--ui); }
svg .dg-az     { fill:var(--surface2); stroke:var(--green); }
svg .dg-az-t   { fill:var(--green); font-family:var(--ui); }
svg .dg-focus  { fill:var(--amber-soft); stroke:var(--amber); }
svg .dg-focus-t{ fill:var(--amber); font-family:var(--display); }
svg .dg-node   { fill:var(--surface2); }

/* (The navigation is on its own row at every width below 1600px now - see
   .topbar nav above - so nothing here needs to move it.) */
@media (max-width:760px){
  :root{ --gutter:16px; }
  /* 96px at the foot: room for the floating chat button over the last line */
  main{ padding:24px var(--gutter) 96px; }
  h1,.pagetitle{ font-size:30px; }
}

/* ---- sortable tables (server-rendered; the header is just a link) ------- */
table.sortable th{ padding:0; }
table.sortable th a{
  display:block; padding:10px 12px; color:inherit; text-decoration:none;
  font:inherit; letter-spacing:inherit; text-transform:inherit;
}
table.sortable th a:hover{ color:var(--accent); background:var(--surface2); }
th.num, td.num{ text-align:right; }
table.sortable th.num a{ text-align:right; }
.sort-arrow{ color:var(--accent); font-size:var(--fs-2xs); }
table.sortable td a{ color:inherit; text-decoration:none; }
table.sortable td a:hover{ color:var(--accent); text-decoration:underline; }
tr.row-hl > td{ background:var(--accent-soft); }

/* ---- inline policy template on the Connect page ------------------------ */
.policy-view{ margin-top:16px; }
.policy-view summary{
  cursor:pointer; font-size:12.5px; font-weight:650; color:var(--accent);
  padding:8px 0;
}
.policy-view summary:hover{ text-decoration:underline; }
pre.code{
  min-width:0; max-width:100%;
  margin:10px 0 0; padding:14px 16px; max-height:460px; overflow:auto;
  background:var(--surface2); border:1px solid var(--line2); border-radius:var(--radius);
  font-family:var(--mono); font-size:var(--fs-xs); line-height:1.55; color:var(--ink2);
  white-space:pre; tab-size:2;
}
pre.code code{ background:none; border:none; padding:0; font-size:inherit; color:inherit; }

/* Scan in progress. The dot is the only animation on the page: it says the
   appliance is working, which is a different statement from a zero. */
[hidden] { display: none !important; }
.scanning { display: inline-flex; align-items: center; gap: .5rem; margin-top: .6rem; }
.scanning::before {
  content: "";
  width: .5rem; height: .5rem; border-radius: 50%;
  background: currentColor;
  animation: scan-pulse 1.4s ease-in-out infinite;
}
@keyframes scan-pulse {
  0%, 100% { opacity: .25; transform: scale(.8); }
  50%      { opacity: 1;   transform: scale(1.15); }
}
@media (prefers-reduced-motion: reduce) {
  .scanning::before { animation: none; opacity: .8; }
  /* No page rise, no lifting cards; state changes still show, just fast. */
  main { animation: none; }
  a.kpi:hover { transform: none; }
  *, *::before, *::after { transition-duration: .01s !important; }
}

/* ---------------------------------------------------------------- scan ticker
   Rides under the top bar on every page while a scan runs. The bar's fill
   is the share of checks done; the stripe moving through it is what says
   "still working" between polls, which matters most during the one region
   that takes twenty minutes. */
/* min-width:0 on the ticker, its row and its text: without them the
   one-line status set the header's min-content width and a 320px phone
   scrolled sideways while a scan ran. The text ellipsises on one line so
   the pinned height never jumps between polls. */
.ticker{
  order:20; flex:1 1 100%; min-width:0; margin:0 calc(-1 * var(--gutter));
  background:var(--surface); border-top:1px solid var(--line);
}
.ticker[hidden]{ display:none; }
.ticker-bar{ position:relative; height:4px; background:var(--accent-soft); overflow:hidden; }
.ticker-fill{
  position:absolute; left:0; top:0; bottom:0; width:2%;
  background:var(--accent); transition:width .8s ease;
}
.ticker-fill::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(90deg, transparent 0%, rgba(255,255,255,.55) 50%, transparent 100%);
  background-size:180px 100%; background-repeat:no-repeat;
  animation:ticker-sweep 1.6s linear infinite;
}
@keyframes ticker-sweep{ from{ background-position:-180px 0; } to{ background-position:calc(100% + 180px) 0; } }
.ticker-row{
  display:flex; align-items:center; gap:10px; min-width:0; padding:6px var(--gutter);
  font-size:12.5px; color:var(--ink2); font-variant-numeric:tabular-nums;
}
.ticker-dot{
  width:8px; height:8px; border-radius:50%; background:var(--accent); flex:none;
  box-shadow:0 0 0 0 var(--accent-line); animation:ticker-pulse 1.4s ease-out infinite;
}
@keyframes ticker-pulse{ 0%{ box-shadow:0 0 0 0 var(--accent-line);} 100%{ box-shadow:0 0 0 8px transparent;} }
.ticker-text{ flex:1 1 auto; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
@media (max-width:760px){ .ticker-row{ padding-block:4px; } }
@media (prefers-reduced-motion: reduce){ .ticker-fill::after, .ticker-dot{ animation:none; } }

/* The brand is a link now; it must look exactly as it did as a div. */
a.brand{ color:var(--wordmark); text-decoration:none; }
a.brand:hover .brandtext b{ color:var(--accent); }

/* ============================================================ settings layout
   The Settings form, grouped into titled sections with related fields on one
   row. Appended as a block so nothing above it is restructured. Every rule is
   scoped under .settings-form / .cols.settings / .recipient-list. */
.cols.settings{ grid-template-columns:minmax(0,3fr) minmax(0,2fr); }
@media (max-width:980px){ .cols.settings{ grid-template-columns:1fr; } }
.settings-form fieldset.section{
  border:0; border-top:1px solid var(--line); margin:0; padding:16px 0 4px; min-width:0;
}
.settings-form fieldset.section:first-of-type{ border-top:0; padding-top:0; }
.settings-form legend{
  float:left; width:100%; margin:0 0 10px; padding:0;
  font-family:var(--ui); font-size:var(--fs-base); font-weight:600; color:var(--ink);
}
.settings-form legend + *{ clear:both; }
/* minmax(0,1fr), not 1fr: a 1fr track grows to its widest child (a long
   recipient list, the API usage block) and pushed the card past a phone. */
.settings-form .fields{ display:grid; grid-template-columns:minmax(0,1fr); gap:0 14px; min-width:0; }
.settings-form .fields.cols-2{ grid-template-columns:repeat(2,minmax(0,1fr)); }
.settings-form .fields.cols-3{ grid-template-columns:repeat(3,minmax(0,1fr)); }
@media (max-width:720px){
  .settings-form .fields.cols-2, .settings-form .fields.cols-3{ grid-template-columns:minmax(0,1fr); }
}
.settings-form .fields > label, .settings-form .fields > p{ min-width:0; }
.settings-form .fields > p.mini{ margin:-4px 0 12px; }
.settings-form .field-label{ font-size:var(--fs-sm); font-weight:600; color:var(--ink2); margin-bottom:6px; }
.settings-form .field-label .mini{ display:block; font-weight:500; margin-top:2px; }
.settings-form .form-actions{ margin-top:18px; padding-top:14px; border-top:1px solid var(--line); }

/* Recipients: one line per address with its confirmation state. */
.recipient-list{ list-style:none; margin:-4px 0 10px; padding:0; display:flex; flex-direction:column; gap:6px; }
.recipient-list li{ display:flex; align-items:center; gap:4px 10px; flex-wrap:wrap; font-size:12px; min-width:0; }
.recipient-list code{ overflow-wrap:anywhere; min-width:0; max-width:100%; }
/* The chip is a state, not a label: sentence case, allowed to wrap. */
.recipient-list .chip{ white-space:normal; text-transform:none; letter-spacing:0; font-size:var(--fs-xs); }
.recipient-list .recipient-detail{ flex-basis:100%; }
.chip.pending{ background:var(--amber-soft); color:var(--amber); }

/* Service budgets: a service picker beside its amount, one row per budget. */
.budget-rows{ display:flex; flex-direction:column; gap:8px; margin-bottom:10px; }
.budget-row{ display:grid; grid-template-columns:minmax(0,3fr) minmax(0,1fr); gap:8px; }
.budget-row input{ width:100%; height:36px; font-weight:500; }
/* The amount keeps its own 112px column on a phone rather than dropping
   under the service name, so a row still reads as one budget. */
@media (max-width:480px){ .budget-row{ grid-template-columns:minmax(0,1fr) 112px; } }
.budget-add{ margin-top:2px; }
@media (max-width:760px){
  .budget-add{ min-height:44px; }
  /* Fields outside a <label> miss the generic 44px rule; these are the
     budget rows and the add-a-user line. */
  .budget-row input, .user-add input, .user-add select{ height:44px; }
}

/* ================================================================= billing
   The Billing page (Settings > Billing): the organization form on the left,
   the invoices table on the right. Appended as a block; every rule is scoped
   under .billing / .billing-note / table.invoices. */
.billing-lede{ margin:8px 0 0; }
.billing-note{
  margin:0 0 16px; padding:10px 14px; border-radius:var(--radius);
  background:var(--accent-soft); color:var(--accent); font-size:12.5px; font-weight:600;
}
.cols.billing{ grid-template-columns:minmax(0,3fr) minmax(0,2fr); }
@media (max-width:980px){ .cols.billing{ grid-template-columns:1fr; } }
.billing .form-actions{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
.billing .tablewrap{ overflow-x:auto; }
/* Only the figures and the headings stay on one line: nowrap on every cell
   set the period and number column wider than a phone, and cut the total
   ("USD 180.00") off behind the card's edge. */
table.invoices td{ vertical-align:middle; }
table.invoices td.num, table.invoices th{ white-space:nowrap; }
table.invoices td code{ font-size:12px; }
table.invoices .chip{ text-transform:none; }
/* The invoice's actions cell: the PDF button and, when the organization on
   file differs from what the invoice prints, "Revised copy" beside it
   (handlers_invoice_revise.go, 7 Oct 2026). A superseded original keeps its
   PDF and says which copy replaced it. */
table.invoices td.inv-pdf form{ display:inline; }
table.invoices td.inv-pdf .btn + form, table.invoices td.inv-pdf .btn + .btn{ margin-left:6px; }
table.invoices .inv-rel{ display:block; margin-top:2px; }
/* The revised-copy page: what the invoice prints beside what the copy
   will, then the code and the delivery choice. */
.revise-compare{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:16px; margin:12px 0 16px; }
.revise-compare h4{ margin:0 0 4px; font-size:var(--fs-sm); color:var(--ink2); font-weight:600; }
.revise-compare p{ margin:0; }
@media (max-width:560px){ .revise-compare{ grid-template-columns:minmax(0,1fr); } }
fieldset.choices{ border:0; padding:0; margin:0; min-width:0; }
fieldset.choices legend{ padding:0; margin-bottom:6px; font-size:13px; font-weight:600; color:var(--ink); }
fieldset.choices label{ display:flex; align-items:center; gap:8px; padding:6px 0; font-size:var(--fs-sm); }
fieldset.choices input[type=radio]{ margin:0; }
/* The phone field (phone_field.go): the country-code select and the number
   on one row; the select keeps a readable width, the number takes the rest;
   under 480px they stack. The Add-user row on Settings reuses the names. */
.phone-field .phone-row{ display:flex; gap:8px; }
.phone-field .phone-row select{ flex:0 1 13em; min-width:0; }
.phone-field .phone-row input{ flex:1 1 auto; min-width:0; }
@media (max-width:480px){ .phone-field .phone-row{ flex-direction:column; } .phone-field .phone-row select{ flex-basis:auto; } }
.billing p.empty{ margin:6px 0 0; }

/* ================================================================== mobile
   Narrow-viewport containment (390 px phones). Appended as a block.

   Every two-column grid collapsed to "1fr" below 980 px, and a 1fr track's
   minimum is the min-content width of its widest child: an audit table,
   the ladder table, a <pre class=code>, or the invoices table set the
   column to 460-520 px and the whole document scrolled sideways on
   Settings, Billing, Connect (and the Connect lightbox), Findings, Compare
   and the report view. minmax(0,1fr) lets the track be the viewport and
   the child overflow inside its own box; the rules below then give each
   wide thing a horizontal scroll of its own, so the page body never scrolls
   horizontally. */
@media (max-width:980px){
  .cols, .cols.settings, .cols.billing{ grid-template-columns:minmax(0,1fr); }
}
/* Wide tables scroll inside themselves. display:block turns the table into
   a scroll container whose anonymous table box shrinks to fit the viewport
   and scrolls beyond it; the card styling stays on the block. Up to 1100px,
   not 760: at 768 the compare tables and the report view were wider than
   the page and the whole document scrolled sideways. */
@media (max-width:1100px){
  table.wide{ display:block; overflow-x:auto; max-width:100%; -webkit-overflow-scrolling:touch; }
  table.wide > tbody, table.wide > thead{ min-width:100%; }
}
@media (max-width:760px){
  /* Tables inside cards (users, audit trail, the activation ladder, the
     invoices list) do the same; the card itself never grows past its
     column. */
  .card{ min-width:0; max-width:100%; overflow-x:auto; }
  /* ...except the Settings form: a scrolling card is the containing block
     for its sticky Save bar, which then pinned to the card's own foot, 3,000px
     down a phone screen (design audit C34, 13 Oct 2026). Its fields wrap. */
  .card.settings-form{ overflow-x:visible; }
  main{ overflow-x:clip; }
  /* ARNs and free text wrap anywhere instead of setting a minimum width.
     Short identifiers (code.ident, .nowrap) do not: "us-east-1" broken
     over two lines reads as two things. */
  .card code.arn, td code.arn, .thread .msg p{ overflow-wrap:anywhere; }
  /* YAML and JSON keep their indentation, which is their meaning: the block
     scrolls sideways inside itself and is capped in height. */
  pre.code{ white-space:pre; overflow-x:auto; max-height:60vh; font-size:var(--fs-xs); }
  .head-actions{ width:100%; }
  /* Every page's KPI row, main.narrow's included: two tiles a row, and an
     odd last tile takes the whole row rather than sitting alone in half. */
  .kpis, main.narrow .kpis{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
  .kpis > .kpi:last-child:nth-child(odd){ grid-column:1 / -1; }
  .kpi{ padding:12px 14px; min-width:0; }
  .kpi .num, main.narrow .kpi .num{ font-size:24px; margin-top:6px; overflow-wrap:anywhere; }
  .kpi .num.muted{ font-size:18px; }
  .kpi .lbl{ font-size:var(--fs-xs); }
}

/* A section-note directly under a page heading. The note's negative top
   margin is tuned for an h2 that carries 16 px of bottom margin; under an
   h1 (margin 0) it pulled the note up INTO the heading, and at 390 px a
   two-line "No scan has run yet." overlapped it by a full line. */
h1 + .section-note, h1.hero + .section-note{ margin-top:10px; }

/* A wrapper for a table that is wider than a desktop window too (the
   twelve-month bill matrix): the table scrolls inside it at every width. */
.tablewrap{ overflow-x:auto; max-width:100%; margin-bottom:16px; }
.tablewrap > table.wide{ margin-bottom:0; }

/* ---- table tiers (design plan s6) ---------------------------------------
   (a) table.rowcards: a record table becomes one card per row on a phone.
       Each td carries data-label="Column"; a td without one spans the card.
   (b) table.stickyfirst + .scrollcue: a comparison or matrix keeps scrolling,
       with its first column pinned and a shadow on the side that has more.
   (c) a column that adds little on a phone is hidden by the page itself. */
table.stickyfirst th:first-child, table.stickyfirst td:first-child{
  position:sticky; left:0; z-index:1;
  background:var(--surface); box-shadow:1px 0 0 var(--line);
}
table.stickyfirst th:first-child{ background:var(--surface2); }
.card table.stickyfirst th:first-child{ background:var(--surface); }
table.stickyfirst tr:hover td:first-child{ background:var(--surface2); }
/* Scroll shadows that need no script: the two "local" covers move with the
   content and hide the two "scroll" shadows at whichever end is reached. */
.scrollcue{
  background:
    linear-gradient(90deg, var(--surface) 30%, transparent) left center / 40px 100% no-repeat local,
    linear-gradient(270deg, var(--surface) 30%, transparent) right center / 40px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, var(--line2), transparent) left center / 12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--line2), transparent) right center / 12px 100% no-repeat scroll;
  background-color:var(--surface);
}
@media (max-width:760px){
  table.rowcards, table.rowcards > tbody, table.rowcards > tfoot,
  table.rowcards tr, table.rowcards tr > td{ display:block; }
  table.rowcards{ overflow:visible; border:0; background:none; box-shadow:none; }
  table.rowcards > thead, table.rowcards tr:not(:has(> td)){ display:none; }
  table.rowcards tr{
    margin:0 0 10px; padding:12px 14px;
    background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  }
  /* The label hangs in a 110px left margin rather than being a grid cell:
     a cell's content is often text, a chip and a sub-line together, and as
     grid items the second and third of those fell into the label column.
     It floats into that margin (not position:absolute) inside a flow-root
     cell, so a label that wraps to two lines makes its cell taller instead
     of running over the next row's label, and it always wraps: a nowrap
     inherited from the cell (.compare-table td.num) once ran "POTENTIAL
     CHANGE" straight into its figure. A table with longer labels widens the
     slot with --rc-label (the compare tables below). */
  table.rowcards{ --rc-label:110px; }
  .card table.rowcards tr > td, table.rowcards tr > td{
    display:flow-root; position:relative; min-height:22px;
    padding:4px 0 4px calc(var(--rc-label) + 12px); border:0; text-align:left; white-space:normal; background:none;
  }
  table.rowcards tr > td::before{
    content:attr(data-label);
    float:left; width:var(--rc-label); margin:2px 0 0 calc(-1 * (var(--rc-label) + 12px));
    font-family:var(--mono); font-size:var(--fs-2xs); font-weight:600; letter-spacing:.06em;
    text-transform:uppercase; color:var(--ink3); white-space:normal; overflow-wrap:anywhere; line-height:1.4;
    text-align:left;
  }
  /* The compare tables' labels are month names and "Potential change":
     "SEPTEMBER 2026" and "POTENTIAL CHANGE" each need about 125px. */
  table.compare-table.rowcards{ --rc-label:150px; }
  .card table.rowcards tr > td:not([data-label]), table.rowcards tr > td:not([data-label]),
  .card table.rowcards tr > td[data-label=""], table.rowcards tr > td[data-label=""]{ display:block; padding-left:0; }
  table.rowcards tr > td:not([data-label])::before, table.rowcards tr > td[data-label=""]::before{ content:none; }
  table.rowcards td .chip{ white-space:normal; }
  table.rowcards tr:hover td{ background:none; }
  table.rowcards tr.row-hl, table.rowcards tr.active{ background:var(--accent-soft); }
}


/* ---- multi-account (secaudit/MULTI-ACCOUNT-DESIGN.md) - append only below --- */
/* The switcher inside the account badge: a select and, without JavaScript,
   a Switch button (static/accountswitch.js hides it and submits on change). */
.acct-switch{ display:flex; align-items:center; gap:6px; margin-top:4px; }
.acct-switch label{ font-family:var(--mono); font-size:var(--fs-2xs); letter-spacing:.08em; text-transform:uppercase; color:var(--ink3); white-space:nowrap; }
.acct-switch select{ height:24px; font-size:var(--fs-xs); padding:0 22px 0 6px; margin:0; max-width:220px; }
.acctbadge.multi{ max-width:420px; }
/* The dot on the Connect tab while no AWS account is linked. */
.nav-dot{
  display:inline-block; width:7px; height:7px; margin-left:5px; vertical-align:2px;
  border-radius:50%; background:var(--amber); box-shadow:0 0 0 2px var(--amber-soft);
}
/* The dashboard's setup checklist. */
.setup-card{ margin-bottom:18px; }
.setup-steps{ list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:10px 28px; }
.setup-steps li{ display:flex; align-items:center; gap:10px; min-width:0; }
.setup-steps .step-mark{
  display:inline-flex; align-items:center; justify-content:center; flex:none;
  width:24px; height:24px; border-radius:50%; font-family:var(--mono); font-size:var(--fs-xs); font-weight:700;
  background:var(--raise); color:var(--ink2); box-shadow:inset 0 0 0 1px var(--line2);
}
.setup-steps li.done .step-mark{ background:var(--green-soft); color:var(--green); box-shadow:inset 0 0 0 1px var(--green); }
.setup-steps li.current .step-mark{ background:var(--amber-soft); color:var(--amber); box-shadow:inset 0 0 0 1px var(--amber); }
.setup-steps li.running .step-mark{ background:var(--accent-soft); color:var(--accent); box-shadow:inset 0 0 0 1px var(--accent-line); }
.setup-steps li.done b{ color:var(--ink2); font-weight:600; }
/* Account lists on the dashboard and the Connect page. */
.accounts-summary tr.active td, .accounts-list tr.active td{ background:var(--accent-soft); }
.acct-actions{ justify-content:flex-end; gap:6px; margin:0; }
.acct-actions form{ margin:0; }
button.danger, .btn.danger{ color:var(--red); border-color:var(--red-soft); }
button.danger:hover, .btn.danger:hover{ border-color:var(--red); color:var(--red); }
/* A danger button that is not a ghost is the page's destructive submit
   ("Remove this account"): solid red with the on-accent ink. Without this it
   took the base button's accent fill under red text, 1.2:1 in both themes. */
button.danger:not(.ghost), .btn.danger:not(.ghost){ background:var(--red); border-color:var(--red); color:var(--onaccent); }
button.danger:not(.ghost):hover, .btn.danger:not(.ghost):hover{ background:var(--red); color:var(--onaccent); filter:brightness(.9); }
.all-accounts-note{ margin-bottom:14px; }
.billing-accounts{ margin-top:-6px; }

/* The plan card on the Connect page: the plans one can ask for, as radio
   tiles, and the note field. */
.plan-card .mini.warn{ color:var(--amber); }
.plan-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); gap:10px; margin:10px 0 12px; }
.plan-option{
  display:flex; gap:10px; align-items:flex-start; padding:10px 12px; margin:0;
  border:1px solid var(--line); border-radius:var(--radius-sm); cursor:pointer;
  font-size:var(--fs-sm); font-weight:500; color:var(--ink2);
}
/* The tile's text is one column of lines (no <br>s): the name, the price,
   the allowance, the call to action. The signup tiles share these rules. */
.plan-option > span{ display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
.plan-option > span > b{ font-size:15px; font-weight:600; color:var(--ink); }
.plan-option .po-head{ font-size:15px; color:var(--ink); }
/* Prices in the data face, as on the site's pricing and sign-up pages. */
.plan-option .price{ display:block; font-family:var(--mono); font-size:20px; font-weight:600; letter-spacing:-.02em; color:var(--ink); line-height:1.25; }
/* The launch offer (5 Oct 2026): the full price struck through beside the
   price charged, and the tag under it. On a tile the struck figure sits on
   its own line above the price. */
.was{ text-decoration:line-through; color:var(--ink3); font-weight:400; }
.plan-option .was{ display:block; font-family:var(--mono); font-size:13px; line-height:1.2; }
.offer-tag{ color:var(--accent); font-weight:500; }
.plan-option .offer-tag{ display:block; margin-top:2px; }
.chip .was, .billing-accounts .was{ font-size:.9em; }
/* On a selected tile the soft accent fill takes ink3 below AA, so the
   small print steps up to ink2. */
.plan-option:has(input:checked) .mini, label.choice:has(input:checked) em{ color:var(--ink2); }
.plan-option:has(input:focus-visible){ outline:2px solid var(--focus); outline-offset:2px; }
/* The Free trial tile (plan.Trial, WG 24 Sep 2026) reads as the offer it is. */
/* Green marks the offer in its text, not with a border: a green outline on
   an unchecked tile read as a second selection beside the checked one
   (design audit C36, 13 Oct 2026). */
.plan-option.plan-trial b{ color:var(--green); }
.plan-option:hover{ border-color:var(--accent); }
.plan-option:has(input:checked){ border-color:var(--accent); background:var(--accent-soft); }
/* 18px radios at every width, and the whole tile is the label (design audit,
   13 Oct 2026: 13px native controls beside the site's 20px ones). */
.plan-option input[type=radio]{ width:18px; height:18px; margin-top:2px; flex:none; }
.plan-request > label.mini{ display:block; margin-bottom:10px; }
.plan-request > label.mini input{ display:block; width:100%; max-width:520px; margin-top:4px; }
.plan-ask{ margin-top:14px; }
.plan-ask > summary{ cursor:pointer; color:var(--ink3); }
.chip.st-err{ background:var(--red-soft); color:var(--red); }
.payments-head{ margin-top:22px; }
.checkout table{ margin:10px 0 14px; }

/* ---- the getting-started walkthrough inside the setup card ---- */
.setup-tutorial{ margin-top:12px; }
.setup-tutorial summary{ cursor:pointer; font-size:13px; font-weight:600; color:var(--accent); }
.setup-tutorial img{ display:block; margin-top:10px; max-width:100%; border-radius:var(--radius); border:1px solid var(--line); }

/* The subscribe wizard (templates/subscribe.html, WG 11 Sep 2026): three
   numbered steps on one screen, tiles in a row, the billing details folded
   to one line when on file. */
/* Every step title sits straight after its number; a chip or note takes the
   right-hand slot (design audit, 13 Oct 2026: h3's space-between centred
   "Plan" and pushed "Pay" to the far edge, away from its badge). */
.subscribe .step h3{ display:flex; align-items:center; justify-content:flex-start; gap:12px; flex-wrap:wrap; }
.subscribe .step h3 > .chip, .subscribe .step h3 > .mini{ margin-left:auto; }
.subscribe .step-no{ display:inline-flex; width:22px; height:22px; border-radius:50%; background:var(--accent); color:var(--onaccent); font-size:12px; align-items:center; justify-content:center; }
/* auto-fit: five tiles fill the row instead of leaving a sixth track empty. */
.subscribe .tiles{ grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); }
.subscribe .tiles .price{ font-weight:600; }
.subscribe .summary{ margin:4px 0 0; }
.subscribe .plan-option.current{ opacity:.7; }
.subscribe .plan-option.pending{ border-style:dashed; }
.subscribe .wizard .card{ margin-bottom:12px; }

/* ---- the findings page reordered (WG, 12 Sep 2026) ---- */

/* Billed Cost Explorer line items, as sub-rows of the service they roll into.
   A row of the reconciliation is a line on the bill; these are what that line
   is actually made of, so they are indented under it rather than given equal
   weight beside it. The share in a sub-row is of its PARENT ROW and the cell
   prints that denominator: a percentage without one is the defect this
   codebase has a doctrine about. */
.cov-line td{ background:var(--surface2); border-bottom:1px dashed var(--line); font-size:12.5px; }
.cov-line td.money{ font-size:12.5px; font-weight:600; color:var(--ink2); }
.cov-line-name{
  position:relative; padding-left:36px !important;
  font-family:var(--mono); font-size:var(--fs-xs); color:var(--ink2);
  overflow-wrap:anywhere;
}
.cov-line-name::before{
  content:""; position:absolute; left:20px; top:0; bottom:0;
  border-left:2px solid var(--line2);
}

/* Rules that failed on the last scan. Deliberately NOT a table of money: it
   sits under the reconciliation heading as a note, in the amber the rest of
   the product uses for "could not look", so it can never be read as a charge. */
.scan-problems{ border-left:3px solid var(--amber); }
.scan-problems h3{ color:var(--amber); }
.scan-problems ul{ list-style:none; margin:10px 0 0; padding:0; }
.scan-problems li{ padding:8px 0; border-top:1px solid var(--line); }
.scan-problems li:first-child{ border-top:none; }
.scan-problems li .chip{ margin-left:6px; background:var(--amber-soft); color:var(--amber); }
.scan-problems li .mini{ margin-top:3px; }

/* The compact floating scatter (static/findings.js). It is a clone of the
   card at the foot of the page, shown once the reader is past the findings
   table's midpoint or the grouped opportunities, and closable for the session.
   Every colour is a theme token, so it reads correctly in light and dark
   without a second palette. */
/* bottom:72px: clear of the floating chat button beneath it. */
.chart-dock{
  position:fixed; right:18px; bottom:72px; z-index:60; width:340px; max-width:calc(100vw - 36px);
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow); padding:10px 14px 12px;
  animation:dock-in .18s cubic-bezier(.2,.8,.3,1);
}
.chart-dock[hidden]{ display:none; }
.chart-dock .dock-head{ display:flex; align-items:center; gap:8px; }
.chart-dock .dock-head h3{ margin:0; flex:1; font-size:13px; }
.chart-dock .x{
  flex:none; width:24px; height:24px; padding:0; line-height:1;
  display:inline-flex; align-items:center; justify-content:center;
  font-size:16px; font-weight:700;
  background:var(--raise); color:var(--ink2);
  border:1px solid var(--line); border-radius:50%; cursor:pointer;
}
.chart-dock .x:hover{ border-color:var(--accent-line); color:var(--ink); filter:none; }
.chart-dock .x:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.chart-dock .dock-body{ margin:6px 0 4px; }
.chart-dock .dock-body svg{ display:block; width:100%; height:auto; max-width:none; }
.chart-dock .mini{ margin:0; }
@keyframes dock-in{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce){ .chart-dock{ animation:none; } }
/* Below the 1280 desktop shell there is no room for a floating box that does
   not sit on top of something the reader needs: at 768 the 340px dock was 44%
   of the viewport, and up to ~1200 the opportunity grid's right column is no
   wider than the dock, so whole cards and their links vanished under it. From
   1280 a column is ~400px and the dock only ever covers part of one. Below
   that the chart card at the foot of the page is the chart.
   static/findings.js suppresses it at the same width; this is the belt to that
   brace, for a window resized after the panel was already open. */
@media (max-width:1279px){ .chart-dock{ display:none !important; } }

/* The one-line "no active plan" banner (plan_gate.go): sentence and button
   on one row, wrapping on a phone. */
.banner.plan-cta{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px; }
.banner.plan-cta .btn{ height:32px; }
@media (max-width:760px){
  .banner.plan-cta{ gap:8px 12px; }
  .banner.plan-cta .btn{ min-height:44px; }
}

/* At phone width a button's label wraps inside its card. Buttons are
   nowrap with a fixed height, so Connect's "Subscribe - 30 days free ($1.00
   to register the card), then monthly" was 434px wide on a 390px screen and
   cut off mid-sentence. */
@media (max-width:760px){
  button, .btn{ white-space:normal; height:auto; min-height:44px; text-align:center; line-height:1.3; padding-block:8px; }
  .btn.mini, button.mini{ min-height:40px; padding-block:4px; }
}

/* Dashboard scan strip: when the active account was last scanned, and the
   manual "Scan again" (WG, 29 Sep 2026). */
.scan-bar{ display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  padding:10px 14px; margin:0 0 18px; }
/* A block, so the "last scanned" sentence wraps as a sentence; the cadence
   note is its own line under it. */
.scan-bar-text{ display:block; min-width:0; }
.scan-bar-text > .mini:last-child{ display:block; margin-top:2px; }
.scan-bar .inline-form{ margin:0; }
.scan-bar-wait{ white-space:nowrap; }

/* Support: tickets and the chat box (WG, 30 Sep 2026). */
.thread .msg{ padding:10px 12px; border-radius:var(--radius); margin:0 0 10px; border:1px solid var(--line); background:var(--surface); }
.thread .msg.team{ background:var(--accent-soft, var(--surface-2)); border-color:var(--accent-line, var(--line)); }
.thread .msg p{ margin:4px 0 0; white-space:pre-wrap; }
/* The chat box (static/chat.js). Text on the accent is always --onaccent:
   literal white on the dark theme's light teal was 2:1. */
.chatbox{ position:fixed; right:max(18px, env(safe-area-inset-right)); bottom:max(18px, env(safe-area-inset-bottom)); z-index:60; font-family:inherit; }
/* Until the reader scrolls (chat.js place()), the button is docked at the
   foot of the page, in the room main and the footer keep for it, rather
   than over the first screen's controls. The body is its containing block,
   at least a window tall so a short page docks it at the window's foot. */
body:has(> .chatbox){ position:relative; min-height:100vh; }
.chatbox.docked{ position:absolute; }
.chat-toggle{ display:flex; align-items:center; justify-content:center; gap:8px; height:auto; min-height:44px; background:var(--accent); color:var(--onaccent); border:0; border-radius:999px; padding:10px 16px; font-weight:600; cursor:pointer; box-shadow:0 6px 20px rgba(0,0,0,.18); }
.chat-toggle:hover{ background:var(--accent2); color:var(--onaccent); }
.chat-icon{ flex:none; }
.chat-badge{ background:var(--onaccent); color:var(--accent); border-radius:999px; min-width:18px; padding:0 6px; font-size:var(--fs-xs); line-height:18px; text-align:center; }
.chat-badge[hidden]{ display:none; }
/* vh first for older engines, then dvh so a phone's collapsing address bar
   does not push the panel's foot off screen. */
.chat-panel{ position:absolute; right:0; bottom:56px; width:min(360px, calc(100vw - 32px)); height:min(480px, calc(100vh - 100px)); height:min(480px, calc(100dvh - 100px)); display:flex; flex-direction:column; background:var(--surface); color:var(--ink); border:1px solid var(--line); border-radius:var(--radius); box-shadow:0 12px 40px rgba(0,0,0,.22); overflow:hidden; }
.chat-panel[hidden]{ display:none; }
.chat-panel header{ display:flex; flex-direction:column; gap:2px; padding:10px 52px 10px 12px; border-bottom:1px solid var(--line); position:relative; }
.chat-close{ position:absolute; right:2px; top:2px; width:44px; height:44px; min-height:44px; padding:0; display:inline-flex; align-items:center; justify-content:center; background:none; border:0; font-size:22px; line-height:1; color:var(--ink2); cursor:pointer; }
.chat-close:hover{ background:none; color:var(--ink); }
.chat-log{ flex:1; overflow:auto; overscroll-behavior:contain; padding:10px 12px; }
.chat-log .msg{ margin:0 0 8px; max-width:88%; min-width:0; padding:8px 10px; border-radius:var(--radius); background:var(--surface2); border:1px solid var(--line); }
.chat-log .msg.team{ margin-right:auto; }
.chat-log .msg.customer{ margin-left:auto; background:var(--accent-soft); border-color:var(--accent-line); }
/* anywhere: a pasted ARN or token has no break opportunity of its own. */
.chat-log .msg p{ margin:2px 0 0; white-space:pre-wrap; overflow-wrap:anywhere; }
.chat-form{ padding:10px 12px; border-top:1px solid var(--line); display:flex; flex-direction:column; gap:6px; }
/* 16px at every width: below that iOS zooms the page when the field takes
   focus, and the chat box is the same on a phone and a desktop. */
.chat-form textarea, .chat-who input{ width:100%; min-width:0; box-sizing:border-box; font-size:var(--fs-md); }
.chat-form textarea{ height:auto; min-height:64px; padding:8px 10px; line-height:1.45; resize:vertical; }
.chat-who input{ height:44px; }
.chat-who{ display:flex; gap:6px; }
.chat-who[hidden]{ display:none; }
.chat-actions{ display:flex; flex-wrap:wrap; justify-content:space-between; align-items:center; gap:8px; }
.chat-actions .chat-status{ flex:1 1 100%; }
.chat-actions .chat-status:empty{ display:none; }
.chat-actions button{ min-height:44px; margin-left:auto; }
/* Phones: a 48px icon circle (the words stay as its accessible name), and
   the open panel is a bottom sheet across the whole width; the circle hides
   while the sheet is up, the sheet's own close button takes over. */
@media (max-width:760px){
  .chatbox{ right:max(10px, env(safe-area-inset-right)); bottom:max(10px, env(safe-area-inset-bottom)); }
  .chat-toggle{ position:relative; width:48px; height:48px; min-height:48px; padding:0; border-radius:50%; }
  .chat-toggle-label{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
  .chat-icon{ width:22px; height:22px; }
  .chat-badge{ position:absolute; top:-4px; right:-4px; }
  .chat-panel{
    position:fixed; inset:auto 0 0 0; z-index:70; width:100%;
    height:min(85vh, 560px); height:min(85dvh, 560px);
    border-width:1px 0 0; border-radius:var(--radius) var(--radius) 0 0;
    padding-bottom:env(safe-area-inset-bottom);
  }
  .chatbox:has(.chat-panel:not([hidden])) .chat-toggle{ display:none; }
  .chat-who{ flex-direction:column; }
}

/* ============================================================== page blocks
   Design plan pass B (5 Oct 2026): the signed-in pages and their charts at
   phone width. Appended as a block; every rule is scoped to a page or a
   component class those pages use. Phone rules sit under <=760. */

/* ---- headings ---------------------------------------------------------- */
/* A card's title where the card is a section of the page (Reports, Support,
   Coverage, Settings): an h2 in the weight of one, sized for a card. */
/* Sans, 16px, semibold: one card-title style with the h3 card headers
   beside it; the serif is for page headings only (design audit, 13 Oct
   2026: "Users" and "Configuration file" were serif and sans side by side). */
.card > h2.card-title{ font-family:var(--ui); font-size:var(--fs-md); font-weight:600; letter-spacing:-.01em; margin:0 0 12px; display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.card > h2.card-title .mini{ font-family:var(--ui); font-size:var(--fs-xs); letter-spacing:0; }
/* A heading that carries chips wraps them under the words on a phone
   rather than squeezing both onto one 320px line. */
@media (max-width:560px){ h3.chip-head{ flex-wrap:wrap; justify-content:flex-start; } }
@media (max-width:760px){
  h3{ font-size:var(--fs-md); }
  .card > h2.card-title{ font-size:var(--fs-md); }
}
/* Free text inside a mono sub-line (a reason, a region list, advice) reads
   in the UI face: mono at 11.5px with tracking is a code, not a sentence. */
.prose, td .mini.prose, .mini.prose{ font-family:var(--ui); font-size:var(--fs-xs); letter-spacing:0; }

/* ---- charts: horizontal bars as HTML rows (charts.go chartHBars) --------- */
.hbars{ display:flex; flex-direction:column; gap:2px; }
.hb-row{
  /* Each row is its own grid, so the value column has a floor: with "auto"
     alone a short value ("$1.16") gave its row a longer track than its
     neighbours, and the bars no longer shared a scale. */
  display:grid; grid-template-columns:minmax(0,38%) minmax(0,1fr) minmax(4.5rem,auto); align-items:center; gap:4px 12px;
  min-height:36px; padding:4px 8px; margin:0 -8px; border-radius:var(--radius-sm);
  font-size:12.5px; color:var(--ink2);
}
a.hb-row:hover{ background:var(--surface2); color:var(--ink); }
a.hb-row:hover .hb-label{ color:var(--accent); }
.hb-label{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hb-track{ display:block; height:10px; border-radius:5px; background:var(--canvas2); overflow:hidden; }
.hb-track > i{ display:block; height:100%; border-radius:5px; background:var(--accent); }
.hb-val{ font-family:var(--mono); font-weight:700; font-size:12px; color:var(--ink); white-space:nowrap; font-variant-numeric:tabular-nums; text-align:right; }
/* The paired rows on /compare: two tracks, two values, the earlier month's
   value in ink3 like its bar. */
.hbars.pair .hb-row{ padding-block:6px; }
.hb-tracks, .hb-vals{ display:flex; flex-direction:column; gap:5px; min-width:0; }
.hb-val.prior{ color:var(--ink3); font-weight:600; }
/* Tone fills, shared by the bars, the stacked segments and the timeline dots. */
.hbars i.sv-t-accent, .stk-bar i.sv-t-accent, .tl-dot.sv-t-accent{ background:var(--accent); }
.hbars i.sv-t-green,  .stk-bar i.sv-t-green,  .tl-dot.sv-t-green { background:var(--green); }
.hbars i.sv-t-amber,  .stk-bar i.sv-t-amber,  .tl-dot.sv-t-amber { background:var(--amber); }
.hbars i.sv-t-red,    .stk-bar i.sv-t-red,    .tl-dot.sv-t-red   { background:var(--red); }
.hbars i.sv-t-muted,  .stk-bar i.sv-t-muted,  .tl-dot.sv-t-muted { background:var(--line2); }
.hb-track i.sv-t-violet, .stk-bar i.sv-t-violet, .tl-dot.sv-t-violet{ background:var(--violet); }
.hb-track i.sv-t-prior{ background:var(--ink3); }
.stk-bar i.sv-t-prior{ background:var(--ink3); }
/* Categorical account colours (All accounts page, 6 Oct 2026): six hues
   that read apart in both themes - no two teals, no two oranges, and c1 is
   not the UI accent, so the payer's dot is a category, not a control. The
   remainder segment is muted. Past six accounts the handler says the
   colours repeat. */
:root{ --c1:#155e75; --c2:#c2410c; --c3:#5b21b6; --c4:#15803d; --c5:#be185d; --c6:#1d4ed8; }
[data-theme="dark"]{ --c1:#74c2c6; --c2:#fb923c; --c3:#c4b5fd; --c4:#86efac; --c5:#f9a8d4; --c6:#93c5fd; }
.stk-bar i.sv-t-c1, .chart-legend i.sv-t-c1, .acct-dot.sv-t-c1{ background:var(--c1); }
.stk-bar i.sv-t-c2, .chart-legend i.sv-t-c2, .acct-dot.sv-t-c2{ background:var(--c2); }
.stk-bar i.sv-t-c3, .chart-legend i.sv-t-c3, .acct-dot.sv-t-c3{ background:var(--c3); }
.stk-bar i.sv-t-c4, .chart-legend i.sv-t-c4, .acct-dot.sv-t-c4{ background:var(--c4); }
.stk-bar i.sv-t-c5, .chart-legend i.sv-t-c5, .acct-dot.sv-t-c5{ background:var(--c5); }
.stk-bar i.sv-t-c6, .chart-legend i.sv-t-c6, .acct-dot.sv-t-c6{ background:var(--c6); }
.chart-legend i.sv-t-muted{ background:var(--line2); }
.acct-dot{ display:inline-block; width:10px; height:10px; border-radius:50%; margin-right:6px; vertical-align:middle; }
/* The money tables: values stay on one line, account headers may wrap (a
   long alias was a 320px nowrap column that pushed Total off-screen), the
   first column (month, service) stays on one line and is pinned by
   table.stickyfirst inside a .tablewrap.scrollcue. */
.accounts-page table.wide td.num{ text-align:right; white-space:nowrap; }
.accounts-page table.wide th.num{ text-align:right; white-space:normal; overflow-wrap:normal; max-width:11em; vertical-align:bottom; }
.accounts-page table.stickyfirst td:first-child{ white-space:nowrap; }
/* Two sentence cells wrap instead of widening their column: the "Adds up?"
   reconciliation note (a 394px nowrap cell pushed the spend table past its
   wrapper at 1280) and the unlinked member's "no run rate; ... total" line. */
.accounts-page table.wide td.check{ white-space:normal; text-align:left; min-width:14em; max-width:22em; }
.accounts-page table.wide td.num.wrapok{ white-space:normal; max-width:16em; }
.accounts-page .notes li{ margin:4px 0; }
.accounts-page .card.note .notes{ margin-bottom:0; }
/* The gauge keeps its 260px: minmax(0,1fr) lets the plan table overflow in
   its own .tablewrap instead of starving the first track down to 70px. When
   the grid collapses to one column the track is minmax(0,1fr) too: a bare
   1fr cannot shrink below the plan table's min-content (eight nowrap columns
   with 36-character plan ids), which panned the whole page sideways. */
.sp-owner{ display:grid; grid-template-columns:minmax(0,260px) minmax(0,1fr); gap:16px; align-items:start; }
@media (max-width:980px){ .sp-owner{ grid-template-columns:minmax(0,1fr); } }
.sp-share{ display:grid; grid-template-columns:minmax(0,1fr) 72px 170px; gap:10px; align-items:center; padding:8px 0; border-top:1px solid var(--line); }
.sp-share:first-child{ border-top:0; }
.sp-share .share-bar{ height:10px; border-radius:5px; background:var(--line); overflow:hidden; }
.sp-share .share-bar i{ display:block; height:100%; background:var(--accent); }
@media (max-width:560px){ .sp-share{ grid-template-columns:minmax(0,1fr) 64px; } .sp-share > .sp-share-bar{ grid-column:1 / -1; } }
@media (max-width:760px){
  /* In card mode the numeric cells read left-aligned beside their label
     like the rest of the app's cards, and wrap rather than clip. */
  .accounts-page table.rowcards td.num{ text-align:left; white-space:normal; }
  .accounts-page table.rowcards td:first-child{ white-space:normal; }
  /* The sticky column's right rule has no job once the cell spans the card. */
  .accounts-page table.rowcards td:first-child{ box-shadow:none; }
  /* A 36-character plan id breaks across lines rather than making the card
     a sideways scroller. */
  .accounts-page table.rowcards code.ident{ white-space:normal; overflow-wrap:anywhere; }
  /* The services and findings cards label each value with an account alias,
     which is free text: as a hanging absolute label a long alias wrapped to
     five lines over the next rows' labels. These cells hold one value and no
     chip, so the label can be a real grid column and take part in layout. */
  .accounts-page table.stickyfirst.rowcards tr > td[data-label]{
    display:grid; grid-template-columns:110px minmax(0,1fr); column-gap:12px; padding-left:0; align-items:start;
  }
  .accounts-page table.stickyfirst.rowcards tr > td[data-label]::before{ position:static; float:none; width:auto; margin:0; top:auto; padding-top:2px; }
  .accounts-page table.stickyfirst.rowcards tr > td:not([data-label]){ display:block; }
}
[data-theme="dark"] .hbars i.sv-t-muted, [data-theme="dark"] .stk-bar i.sv-t-muted, [data-theme="dark"] .tl-dot.sv-t-muted{ background:#6b7680; }
@media (max-width:760px){
  /* The label and value share the first line; the track runs the full
     width beneath them, so a long service name is not cut to five letters. */
  .hb-row{ grid-template-columns:minmax(0,1fr) auto; min-height:44px; padding-block:6px; gap:4px 10px; }
  .hb-row > .hb-track, .hb-row > .hb-tracks{ grid-column:1 / -1; grid-row:2; }
  .hbars.pair .hb-row{ grid-template-columns:minmax(0,1fr) auto; }
  .hbars.pair .hb-vals{ grid-row:1; grid-column:2; flex-direction:row; gap:8px; }
}

/* ---- charts: stacked bars (chartStacked) -------------------------------- */
.stk{ display:flex; flex-direction:column; gap:2px; }
.stk-row{
  display:grid; grid-template-columns:minmax(72px,28%) minmax(0,1fr) minmax(4.5rem,auto); align-items:center; gap:4px 12px;
  min-height:40px; padding:4px 8px; margin:0 -8px; border-radius:var(--radius-sm); color:var(--ink2);
}
a.stk-row:hover{ background:var(--surface2); }
a.stk-row:hover .stk-label b{ color:var(--accent); }
.stk-label{ display:flex; flex-direction:column; min-width:0; line-height:1.25; }
.stk-label b{ font-size:12.5px; font-weight:600; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.stk-label small{ font-family:var(--mono); font-size:var(--fs-2xs); color:var(--ink3); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Segments sit on the track with 1px of the card colour between them, so
   two neighbouring tones read as two marks. */
.stk-bar{ display:flex; height:14px; border-radius:5px; background:var(--canvas2); overflow:hidden; }
.stk-bar > i{ display:block; height:100%; flex:none; }
.stk-bar > i + i{ box-shadow:-1px 0 0 var(--surface); }
.stk-val{ font-family:var(--mono); font-weight:700; font-size:12px; color:var(--ink); white-space:nowrap; text-align:right; font-variant-numeric:tabular-nums; }
@media (max-width:760px){
  .stk-row{ grid-template-columns:minmax(0,1fr) auto; min-height:44px; padding-block:6px; }
  .stk-row > .stk-bar{ grid-column:1 / -1; grid-row:2; }
  .stk-label{ flex-direction:row; align-items:baseline; gap:8px; }
}

/* ---- charts: timelines (chartTimeline) ---------------------------------- */
/* The list is the phone's timeline; the SVG is the desktop's. */
.tl-list{ display:none; list-style:none; margin:0; padding:0; }
.tl-row{ display:flex; align-items:flex-start; gap:10px; min-height:40px; padding:7px 8px; margin:0 -8px; border-radius:var(--radius-sm); color:var(--ink2); }
a.tl-row:hover{ background:var(--surface2); }
.tl-dot{ flex:none; width:10px; height:10px; margin-top:5px; border-radius:50%; background:var(--accent); }
.tl-text{ display:flex; flex-direction:column; min-width:0; }
.tl-text b{ font-size:13px; font-weight:600; color:var(--ink); overflow-wrap:anywhere; }
.tl-text .mini{ overflow-wrap:anywhere; }
.tl-list li + li .tl-row{ border-top:1px solid var(--line); border-radius:0; }
@media (max-width:760px){
  svg.chart.timeline{ display:none; }
  .tl-list{ display:block; }
}

/* ---- charts: type at any scale ------------------------------------------ */
/* The element that holds a chart is a size container, and each step below
   sets --cw to the narrowest width in its range, so a chart's type renders
   between 11.5px and about 13px whatever it is scaled to: a 242px card at
   320, a half card at 1280, the 312px findings dock. Steps are ~15% apart. */
:where(:has(> svg.chart)){ container-type:inline-size; }
@container (max-width:1059.98px){ svg.chart{ --cw:920; } }
@container (max-width:919.98px){ svg.chart{ --cw:800; } }
@container (max-width:799.98px){ svg.chart{ --cw:700; } }
@container (max-width:699.98px){ svg.chart{ --cw:610; } }
@container (max-width:609.98px){ svg.chart{ --cw:530; } }
@container (max-width:529.98px){ svg.chart{ --cw:460; } }
@container (max-width:459.98px){ svg.chart{ --cw:400; } }
@container (max-width:399.98px){ svg.chart{ --cw:350; } }
@container (max-width:349.98px){ svg.chart{ --cw:305; } }
@container (max-width:304.98px){ svg.chart{ --cw:265; } }
@container (max-width:264.98px){ svg.chart{ --cw:230; } }
@container (max-width:229.98px){ svg.chart{ --cw:200; } }

/* ---- charts: vertical bars (chartVBarsW) -------------------------------- */
/* HTML columns, each a share of the card's width, so every month is on
   screen at any width and the type never scales (design audit, 13 Oct
   2026: the SVG kept a 640px floor in a 320px scroller and opened on the
   oldest month). Once a column is narrower than a label (~48px), a dense
   chart (more than six bars) hides every other value and tick, counted from
   the latest bar; the column's title still carries both. */
.vbars{ display:flex; align-items:stretch; gap:4px; container-type:inline-size; padding-top:4px; }
.vb-col{ flex:1 1 0; min-width:0; display:flex; flex-direction:column; align-items:stretch; color:inherit; border-radius:var(--radius-sm); }
a.vb-col:hover{ background:var(--surface2); }
.vb-plot{ height:170px; display:flex; flex-direction:column; justify-content:flex-end; align-items:center; border-bottom:1px dashed var(--line); }
.vb-plot > i{ display:block; width:56%; max-width:64px; border-radius:4px 4px 0 0; background:var(--accent); }
.vb-val{ margin-bottom:4px; font-family:var(--mono); font-size:var(--fs-xs); font-weight:700; color:var(--ink); white-space:nowrap; font-variant-numeric:tabular-nums; }
.vb-tick .t-narrow{ display:none; }
.vb-tick{ margin-top:6px; text-align:center; font-family:var(--mono); font-size:var(--fs-xs); color:var(--ink3); white-space:nowrap; }
/* A tick wider than its column overflows both sides of it, not only the
   right, so on a phone "Feb '26" no longer runs into "Apr"
   (R6-SPEND-MTD-UNLABELLED); "MTD" under the month to date's tick. */
.vb-tick{ display:flex; flex-direction:column; align-items:center; }
.vb-tick .vb-sub{ font-weight:700; color:var(--ink2); }
.vbars i.sv-t-accent{ background:var(--accent); }
.vbars i.sv-t-green{ background:var(--green); }
.vbars i.sv-t-amber{ background:var(--amber); }
.vbars i.sv-t-red{ background:var(--red); }
.vbars i.sv-t-muted{ background:var(--line2); }
[data-theme="dark"] .vbars i.sv-t-muted{ background:#6b7680; }
/* The month to date: the accent, hatched, because it is partial spend. */
.vbars i.sv-t-mtd, .chart-legend i.sv-t-mtd{ background:repeating-linear-gradient(135deg, var(--accent) 0 5px, var(--accent-soft) 5px 8px); box-shadow:inset 0 0 0 1px var(--accent); }
/* A month to date that keeps its direction colour (month-over-month
   change): a hatch over the red or green (R7-MOM-CHART-MTD-UNMARKED). */
.vbars i.vb-mtd{ background-image:repeating-linear-gradient(135deg, transparent 0 5px, var(--surface) 5px 7px); }
/* A column is ~48px wide at the threshold: n bars in a container under
   48n px (13 is the cap charts.go writes). */
@container (max-width:335.98px){ .vb-n7 .vb-alt .vb-val, .vb-n7 .vb-alt .vb-tick{ visibility:hidden; } .vb-n7 .t-wide{ display:none; } .vb-n7 .t-narrow{ display:inline; } }
@container (max-width:383.98px){ .vb-n8 .vb-alt .vb-val, .vb-n8 .vb-alt .vb-tick{ visibility:hidden; } .vb-n8 .t-wide{ display:none; } .vb-n8 .t-narrow{ display:inline; } }
@container (max-width:431.98px){ .vb-n9 .vb-alt .vb-val, .vb-n9 .vb-alt .vb-tick{ visibility:hidden; } .vb-n9 .t-wide{ display:none; } .vb-n9 .t-narrow{ display:inline; } }
@container (max-width:479.98px){ .vb-n10 .vb-alt .vb-val, .vb-n10 .vb-alt .vb-tick{ visibility:hidden; } .vb-n10 .t-wide{ display:none; } .vb-n10 .t-narrow{ display:inline; } }
@container (max-width:527.98px){ .vb-n11 .vb-alt .vb-val, .vb-n11 .vb-alt .vb-tick{ visibility:hidden; } .vb-n11 .t-wide{ display:none; } .vb-n11 .t-narrow{ display:inline; } }
@container (max-width:575.98px){ .vb-n12 .vb-alt .vb-val, .vb-n12 .vb-alt .vb-tick{ visibility:hidden; } .vb-n12 .t-wide{ display:none; } .vb-n12 .t-narrow{ display:inline; } }
@container (max-width:623.98px){ .vb-n13 .vb-alt .vb-val, .vb-n13 .vb-alt .vb-tick{ visibility:hidden; } .vb-n13 .t-wide{ display:none; } .vb-n13 .t-narrow{ display:inline; } }
@media (max-width:760px){
  #effort-plot{ min-height:180px; }
  /* No 44px target fits 30 bubbles in a 312px plot; the rows under the
     chart are the links, so on a phone the scatter is a picture. */
  svg.chart.scatter a{ display:none; }
}
.cols.gauge-pair{ grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr)); margin-bottom:0; }
/* Low-confidence bubbles are the smallest: an outline keeps them a mark. */
svg circle.sv-low{ stroke:var(--ink2); stroke-width:1; fill-opacity:.55; }

/* ---- dashboard ---------------------------------------------------------- */
/* Effort words that a phone reads in a sub-line, where the column is gone. */
.f-effort-word{ display:none; }
.hero-sub{ display:block; font-family:var(--ui); font-size:.55em; font-weight:600; letter-spacing:-.01em; color:var(--ink2); margin-bottom:6px; line-height:1.25; }
.setup-connect{ margin-top:8px; }
.setup-steps li > span:last-child{ min-width:0; }
.setup-steps li .setup-connect{ display:flex; width:max-content; max-width:100%; }
.setup-finish{ display:inline-block; padding:10px 0; }
.tutorial-full{ display:block; color:inherit; }
.tutorial-full .mini{ display:inline-block; margin-top:6px; color:var(--accent); font-weight:600; }
table.events td.mini{ white-space:nowrap; }
@media (max-width:760px){
  .scan-bar{ padding:8px 12px; }
  .scan-bar .btn{ min-height:40px; }
  .setup-steps{ flex-direction:column; gap:12px; }
  .setup-steps li{ align-items:flex-start; }
  /* Tier (c): the effort is in the sub-line on a phone. */
  table.top-recs th:nth-child(4), table.top-recs td:nth-child(4){ display:none; }
  table.events td.mini{ white-space:normal; }
}
@media (max-width:760px){ table.top-recs .f-effort-word{ display:inline; } }
/* Inline links that act - a breadcrumb in the eyebrow, "all open" beside a
   card title, a KPI tile's link - padded to a 32px target; the negative
   margin keeps the line where it was. */
.page-head .eyebrow a, .card h3 > a.mini, .kpi .lbl a, a.backlink, a.tap{ display:inline-block; padding:9px 0; margin:-9px 0; }

/* ---- scan confirm ------------------------------------------------------- */
/* The warning reads as a note inside the card, like the compare notes,
   not a full-bleed page banner squeezed into it. */
.card > .banner{ border:1px solid var(--line); border-radius:var(--radius); padding:11px 14px; margin-bottom:12px; }
@media (max-width:760px){ .scan-confirm .btn{ min-height:44px; } }

/* ---- license / plan ----------------------------------------------------- */
.plan-name{ display:inline-block; }
.plan-name::first-letter{ text-transform:uppercase; }

/* ---- finding detail ----------------------------------------------------- */
.backlink{ display:inline-block; padding:10px 0; }
.finding-arn code.arn{ display:block; margin-top:4px; overflow-wrap:anywhere; }
label.inline-label{ display:inline-flex; align-items:center; gap:8px; margin:0; }
label.inline-label input{ display:inline-block; width:80px; margin:0; }
table.evidence td.mini{ width:38%; }

/* ---- findings ----------------------------------------------------------- */
/* The findings views as a tab row, not five buttons: underlined tabs with
   the section in view marked (aria-current, static/findings.js), wrapping
   on a phone instead of cutting "Charts" off (design audit, 13 Oct 2026). */
.section-jump{ display:flex; flex-wrap:wrap; gap:0 4px; margin:-4px 0 18px; border-bottom:1px solid var(--line); }
.section-jump a{
  flex:none; display:inline-flex; align-items:center; min-height:36px; padding:0 12px;
  border-bottom:2px solid transparent; margin-bottom:-1px;
  font-size:var(--fs-sm); font-weight:600; color:var(--ink2); white-space:nowrap;
}
.section-jump a:hover{ color:var(--ink); background:var(--raise); }
.section-jump a[aria-current]{ color:var(--ink); border-bottom-color:var(--accent); }
@media (max-width:760px){ .section-jump a{ min-height:44px; } }
details > summary{ min-height:40px; }
/* The folding sections' headings are the summary: the marker sits beside
   the heading, and above 760px there is no fold to draw attention to. */
details.phone-fold > summary{ display:flex; align-items:center; gap:8px; cursor:pointer; list-style:none; }
details.phone-fold > summary::-webkit-details-marker{ display:none; }
details.phone-fold > summary h2{ margin:0 0 16px; }
details.phone-fold > summary::after{ content:"\25BE"; color:var(--ink3); font-size:14px; margin-bottom:16px; }
details.phone-fold:not([open]) > summary::after{ content:"\25B8"; }
details.phone-fold:not([open]){ margin-bottom:16px; }
/* Above a phone the heading is the whole target, not the row: a full-width
   summary put the "Pools" row under the floating chart dock and the chat
   button, which cover the right of the page. */
@media (min-width:761px){ details.phone-fold > summary{ width:fit-content; max-width:100%; } }
/* Pools on a tablet: seven columns in ~716px left the Action prose 131px
   wide and the row 232px tall. Each row is a grid instead: the action reads
   across the full width, and the six short columns sit under it, aligned
   with the header (whose Action cell goes; the bold label says what it is).
   Below 761 the rowcards take over; above 1100 the table has the room. */
@media (min-width:761px) and (max-width:1100px){
  table.pools > tbody{ display:block; }
  table.pools tr{
    display:grid; border-bottom:1px solid var(--line);
    grid-template-columns:minmax(0,1.1fr) minmax(0,.8fr) minmax(0,1.4fr) minmax(0,1.1fr) minmax(0,1.1fr) minmax(0,.8fr);
  }
  table.pools tr:last-child{ border-bottom:0; }
  table.pools tr > th, table.pools tr > td{ border-bottom:0; }
  table.pools tr > th:nth-child(2){ display:none; }
  table.pools tr > td.pool-action{ grid-column:1 / -1; grid-row:1; padding-bottom:2px; }
}
.blocks-wrap{ display:flex; flex-direction:column; }
.blocks-wrap > .blocks{ order:1; }
.blocks-wrap > .blocks-more{ order:2; display:none; margin:-12px 0 24px; }
.blocks-more > summary{ display:inline-flex; align-items:center; cursor:pointer; font-weight:600; color:var(--accent); }
.blocks-more:not([open]) .when-open, .blocks-more[open] .when-closed{ display:none; }
@media (max-width:760px){
  .filters{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px; padding:10px; }
  .filters > select, .filters > button, .filters > .btn{ width:100%; min-height:44px; }
  .filters > .spacer{ display:none; }
  .filters > .mini{ grid-column:1 / -1; }
  /* Only the first six opportunity cards until "Show all" is opened. */
  .blocks-wrap > .blocks-more{ display:block; }
  .blocks-more:not([open]) + .blocks > .block:nth-child(n+7){ display:none; }
  /* All findings as a compact card list: the title across the top, then
     the saving, confidence, status and effort on one line. One bordered
     list rather than 33 separate cards, and the service/region sub-line and
     the category (both filters above) are left to the finding's own page:
     the table was 4,595px tall at 390 and is about half that now. */
  #all-findings{ display:block; border:1px solid var(--line); border-radius:var(--radius); background:var(--surface); box-shadow:var(--shadow); }
  #all-findings tr:has(> td){ display:flex; flex-wrap:wrap; align-items:center; gap:4px 8px; margin:0; padding:8px 12px; border:0; border-radius:0; border-bottom:1px solid var(--line); background:none; }
  #all-findings tr:last-child{ border-bottom:0; }
  #all-findings tr > td{ display:block; padding:0; }
  #all-findings tr > td::before{ content:none; }
  #all-findings td.f-title{ order:-2; flex:1 1 100%; line-height:1.35; }
  #all-findings td.f-title .mini, #all-findings td.f-cat{ display:none; }
  #all-findings td.money{ order:-1; text-align:left; font-size:14px; margin-right:2px; }
  #all-findings td.f-effort{ order:1; font-family:var(--ui); font-size:var(--fs-xs); }
  #all-findings td.f-effort .f-effort-word{ display:inline; }
  #all-findings td.f-chip .mini{ display:inline; margin-left:4px; }
  table.pools td.pool-action summary{ font-size:13px; }
}
@media (max-width:760px){ table.recon{ font-size:12.5px; } }

/* ---- reports ------------------------------------------------------------ */
@media (max-width:760px){
  .report-actions{ flex-direction:column; align-items:stretch; }
  .report-actions .btn{ width:100%; }
}

/* ---- report view: the period as a segmented control ----------------------- */
.seg{ display:inline-flex; }
.seg .btn{ border-radius:0; margin-left:-1px; }
.seg .btn:first-child{ border-radius:var(--radius-sm) 0 0 var(--radius-sm); margin-left:0; }
.seg .btn:last-child{ border-radius:0 var(--radius-sm) var(--radius-sm) 0; }
.btn.ghost.on{ background:var(--accent-soft); border-color:var(--accent); color:var(--ink); position:relative; z-index:1; }
.section-note code{ white-space:nowrap; }

/* ---- compare ------------------------------------------------------------ */
/* Spend is a bill, not a saving: its money cells are ink, not green. */
td.money.spend{ color:var(--ink); }
#compare-kpis .num{ white-space:nowrap; }
@media (max-width:760px){
  #compare-kpis{ grid-template-columns:minmax(0,1fr); }
  #compare-kpis .kpi .num{ font-size:24px; overflow-wrap:normal; }
  #compare-kpis .kpi .num .arrow{ font-size:18px; }
  /* Tier (c): the two Potential columns go; Change beside them stays. */
  table.bucket-table th:nth-child(5), table.bucket-table td:nth-child(5),
  table.bucket-table th:nth-child(6), table.bucket-table td:nth-child(6){ display:none; }
  .compare-picker{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
  .compare-picker .picker-field{ display:flex; flex-direction:column; align-items:stretch; gap:4px; }
  .compare-picker .picker-field select{ width:100%; height:44px; }
  .compare-picker > button, .compare-picker > .btn{ width:100%; }
  .compare-picker .mini{ grid-column:1 / -1; }
}
/* Below 400px two month selects side by side clipped "September 2026"
   under the arrow; one per row. */
@media (max-width:399px){ .compare-picker{ grid-template-columns:minmax(0,1fr); } }

/* ---- spend -------------------------------------------------------------- */
/* The export menu: a no-JS <details> whose sheet drops under its button. */
details.menu{ position:relative; }
details.menu > summary{ list-style:none; }
details.menu > summary::-webkit-details-marker{ display:none; }
details.menu > summary::after{ content:"\25BE"; margin-left:6px; font-size:11px; }
.menu-sheet{
  position:absolute; right:0; top:calc(100% + 6px); z-index:30; min-width:200px;
  display:flex; flex-direction:column; padding:6px;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow);
}
.menu-sheet a{ display:flex; align-items:center; min-height:40px; padding:0 12px; border-radius:var(--radius-sm); font-weight:600; color:var(--ink2); white-space:nowrap; }
.menu-sheet a:hover{ background:var(--raise); color:var(--ink); }
/* The bill matrix: month pinned, every figure a block link filling its
   cell, headings allowed to wrap at 140px. */
table.bill-matrix th{ white-space:normal; max-width:140px; vertical-align:bottom; }
table.bill-matrix td{ padding:0; vertical-align:middle; }
table.bill-matrix td > a{ display:block; padding:11px 14px; }
table.bill-matrix td:first-child > a{ padding-left:18px; }
table.bill-matrix td > .chip, table.bill-matrix td > .mini{ margin:0 14px; }
table.bill-matrix td:first-child{ white-space:nowrap; }
@media (max-width:760px){
  /* The actions wrap onto a second line rather than scrolling: "Export" was
     cut to "Ex" past the viewport edge (design audit, 13 Oct 2026). */
  .page-head .spend-actions{ flex-wrap:wrap; gap:8px; }
  .spend-actions > *{ flex:none; }
  .page-head:has(.spend-actions) .eyebrow{ display:none; }
  table.bill-matrix td > a{ min-height:44px; display:flex; align-items:center; justify-content:flex-end; }
  table.bill-matrix td:first-child > a{ justify-content:flex-start; }
}

/* ---- connect ------------------------------------------------------------ */
.acct-actions{ gap:10px; flex-wrap:wrap; }
/* Remove sits apart from Edit, at the far end of the row. */
.acct-actions > form:has(button.danger){ order:99; margin-left:auto; }
.kv-table code{ user-select:all; }
.stack-how{ margin-top:4px; }
@media (max-width:760px){
  .accounts-list table.rowcards td.num{ text-align:left; }
  .accounts-list .acct-actions{ justify-content:flex-start; margin-top:6px; }
  .accounts-list .acct-actions .btn, .accounts-list .acct-actions button{ min-height:40px; }
  .accounts-summary table.rowcards td.num{ text-align:left; }
}
@media (max-width:560px){
  .stack-buttons{ flex-direction:column; align-items:stretch; }
  .stack-buttons .btn{ width:100%; }
  /* External ID and principal: the label over the value. */
  table.kv-table, table.kv-table tbody, table.kv-table tr, table.kv-table td{ display:block; }
  table.kv-table tr{ padding:6px 0; border-bottom:1px solid var(--line); }
  table.kv-table td{ padding:0 !important; border:0; }
  table.kv-table code{ display:inline-block; max-width:100%; overflow-wrap:anywhere; }
}
/* The Connect page inside a dialog: no page chrome to sit in, so the cards
   and the two-column grid flatten into one column of content. */
body.embed main{ padding:12px 14px 24px; }
/* Kept for a screen reader, not drawn: the dialog's own title says it. */
h3.embed-dup{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
body.embed .cols{ display:block; margin:0; }
body.embed .card{ border:0; box-shadow:none; padding:0; margin:0 0 16px; background:none; }

/* ---- billing ------------------------------------------------------------ */
@media (max-width:760px){
  .billing-back{ display:none; }
  /* An invoice card: the period and number on top, the total and the PDF
     button on one line beneath. */
  /* :has(> td), so the heading row keeps the utility's display:none. */
  table.invoices.rowcards tr:has(> td){ display:flex; flex-wrap:wrap; align-items:center; gap:6px 12px; }
  table.invoices.rowcards tr > td:first-child{ flex:1 1 100%; }
  table.invoices.rowcards td.inv-total{ display:flex; gap:8px; flex:1 1 auto; padding-left:0; font-family:var(--mono); font-weight:700; }
  table.invoices.rowcards td.inv-total::before{ content:none; }
  table.invoices.rowcards td.inv-pdf{ flex:none; text-align:right; }
  table.invoices.rowcards td.num{ text-align:left; }
}

/* ---- settings ----------------------------------------------------------- */
/* The API usage example scrolls inside itself; it is the only thing on the
   page that may. */
pre.api-usage{
  display:block; max-width:100%; overflow-x:auto; margin:6px 0 10px; padding:10px 12px;
  font-family:var(--mono); font-size:var(--fs-xs); line-height:1.55; white-space:pre;
  background:var(--surface2); border:1px solid var(--line); border-radius:var(--radius);
}
.user-add input{ flex:1 1 180px; min-width:0; }
.user-add select{ flex:1 1 160px; min-width:0; }
table.users td.user-email-cell{ overflow-wrap:anywhere; }
/* An audit row's target can be a long unbroken path (/support/ticket/<32 hex>)
   that otherwise widens the table past the page at desktop widths. Only that
   free-text cell may break anywhere: in the 1/3 side card "admin" and
   "127.0.0.1" were split mid-token when every cell could. Who and From are
   .nowrap; a long e-mail in Who ellipsises (full value in the title and the
   CSV) rather than squeezing What to a sliver. */
table.audit-log td.audit-what{ overflow-wrap:anywhere; }
table.audit-log td.audit-who > span{
  display:inline-block; max-width:20ch; overflow:hidden; text-overflow:ellipsis; vertical-align:bottom;
}
.form-actions .err-note{ flex-basis:100%; margin:0 0 8px; }
@media (max-width:760px){
  /* Save stays in reach at the foot of the screen while the long form scrolls. */
  .settings-form .form-actions{
    position:sticky; bottom:0; z-index:5; margin:18px -14px -14px; padding:12px 14px;
    background:var(--surface); box-shadow:0 -1px 0 var(--line);
  }
  .settings-form .form-actions button{ width:100%; }
  table.audit-log tr > td.nowrap:first-child{ font-family:var(--mono); }
}

/* ---- support ------------------------------------------------------------ */
.thread .msg p{ overflow-wrap:anywhere; }
fieldset.bare{ border:0; margin:0; padding:0; min-width:0; }
fieldset.bare[disabled]{ opacity:.6; }
.support-cap a{ font-weight:600; }

/* ---- authenticator ------------------------------------------------------ */
.enrol{ display:flex; flex-direction:column; }
.enrol-key code.secret{ display:block; margin:6px 0 4px; padding:8px 10px; font-size:15px; overflow-wrap:anywhere; }
@media (max-width:760px){
  /* The phone that would scan the QR is usually the phone showing it: the
     key and its Copy button come first, the QR after. */
  .enrol-key{ order:-1; margin-bottom:14px; padding-bottom:14px; border-bottom:1px solid var(--line); }
  .enrol-key .mini{ margin-top:0; }
  .enrol-qr .qr{ width:180px; height:180px; }
}

/* ---- password / security ------------------------------------------------ */
.card > p:first-child{ margin-top:0; }
.security-page .card > h3:first-child{ margin-bottom:10px; }
@media (max-width:600px){ .security-page form.card button[type=submit]{ width:100%; } }

/* ---- plan / subscribe --------------------------------------------------- */
/* The trial card's small print is the ONLY sentence on the subscribe page
   that discloses the one-off ₹1/$1 mandate registration charge and the day
   of the first plan charge. It used to be hidden below 560px to save a
   phone a few lines, which meant a phone user authorised the mandate
   without being told about the charge (functional test round 12). It stays
   at every viewport; on a phone it is tightened, not removed. */
@media (max-width:560px){ .trial-card{ padding:9px 12px; gap:3px; } .trial-card .mini{ line-height:1.4; } }

/* ---- phone tap targets (fix round 1) ------------------------------------ */
/* On a phone every control a thumb is meant to hit is 44px tall: the
   secondary .mini buttons too (they were 40), the disclosure summaries, the
   checkbox rows, and the links that act on their own - a breadcrumb, "all
   open", a KPI's link, "back to findings", a cell whose content is a link,
   a sort heading. Inline links inside running text are left alone. */
@media (max-width:760px){
  .btn.mini, button.mini,
  .accounts-list .acct-actions .btn, .accounts-list .acct-actions button, .scan-bar .btn{ min-height:44px; }
  /* Padding rather than flex: a list-item summary keeps its marker. */
  details > summary{ min-height:44px; }
  :where(details:not(.phone-fold)) > summary{ padding-block:11px; }
  /* The checkbox keeps its place beside the first line; the row's padding
     makes up the 44px, its margins shrink by as much. */
  label.ack{ min-height:44px; padding-block:12px; margin-block:2px 4px; }
  .block-res a{ min-height:44px; }
  .menu-sheet a{ min-height:44px; }
  /* Same line, taller box: the negative margin keeps the text where it was. */
  .page-head .eyebrow a, .card h3 > a.mini, .kpi .lbl a, a.backlink, a.tap{
    display:inline-flex; align-items:center; min-height:44px; min-width:44px; padding-block:0; margin-block:-12px;
  }
  /* A link that is a cell's content - a service on /compare and a month's
     breakdown, a ticket, a finding, the EOL row's "related findings". The
     row grows to fit; :where() leaves a table's own link rule (the bill
     matrix's block links) in charge. */
  :where(table.compare-table, table.sortable, table.rowcards) :where(td) > a:where(:not(.btn)),
  :where(td) > .mini > a:where(:only-child){
    display:inline-flex; align-items:center; min-height:44px; min-width:44px;
  }
  table.sortable th a{ display:flex; align-items:center; min-height:44px; padding-block:0; }
  table.sortable th.num a{ justify-content:flex-end; }
}

/* ============================================================ design audit
   Consensus fixes from the twelve-auditor design audit (13 Oct 2026).
   Appended as a block; each rule names the component it serves. */

/* Read by a screen reader, not drawn (an actions column's heading). */
.sr-only{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }

/* A tertiary action: a button that reads as a link (Dismiss, Snooze). */
.btn.text, button.text{ background:none; border-color:transparent; color:var(--ink2); padding-inline:8px; text-decoration:underline; text-underline-offset:3px; text-decoration-color:var(--line2); }
.btn.text:hover, button.text:hover{ background:none; color:var(--ink); text-decoration-color:currentColor; }
.workflow-actions .btn.text{ margin-left:auto; }
.workflow-snooze{ margin-top:0; }

/* Alerts. One callout for every warning: a tinted box with a left rule, an
   icon, a bold one-line title and the body in normal ink. Amber warns, red
   blocks; neither is the red of a cost rise drawn as bare text. */
.callout{
  position:relative; margin:10px 0 12px; padding:11px 14px 11px 42px;
  border:1px solid var(--line); border-left:3px solid var(--amber); border-radius:var(--radius);
  background:var(--amber-soft); color:var(--ink); font-size:var(--fs-sm); line-height:1.5;
}
.callout::before{
  content:"!"; position:absolute; left:13px; top:12px; width:18px; height:18px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:var(--amber); color:var(--surface); font-family:var(--ui); font-size:12px; font-weight:700; line-height:1;
}
.callout.err{ border-left-color:var(--red); background:var(--red-soft); }
.callout.err::before{ background:var(--red); }
.callout .callout-title{ display:block; font-weight:700; color:var(--ink); }
.callout p{ margin:3px 0 0; color:var(--ink2); }
.callout a{ font-weight:600; }
.callout .btn{ margin-top:8px; }

/* Settings: the Save bar is pinned to the window's foot once the form has
   unsaved changes (static/settings.js), at every width. */
.settings-form form.dirty .form-actions{
  position:sticky; bottom:0; z-index:5; margin-inline:-22px; padding:12px 22px;
  background:var(--surface); box-shadow:0 -1px 0 var(--line), 0 -8px 16px -12px rgba(0,0,0,.25);
}
.form-actions .dirty-note{ margin-left:12px; color:var(--amber); font-weight:600; }
.settings-form .form-actions{ display:flex; flex-wrap:wrap; align-items:center; }

/* The restore picker: the native input sits invisibly inside its label,
   which is styled as a secondary button. */
.file-pick{ position:relative; cursor:pointer; margin:0; }
.file-pick .file-input{ position:absolute; inset:0; width:100%; height:100%; opacity:0; cursor:pointer; margin:0; }
.file-pick:focus-within{ outline:2px solid var(--focus); outline-offset:2px; }
.file-name{ max-width:22ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Settings: the danger zone, last in the side column. */
.card.danger-zone{ border-color:var(--red); box-shadow:inset 3px 0 0 var(--red), var(--shadow); }
.card.danger-zone > h2.card-title{ color:var(--red); }
.danger-row{ display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:8px 16px; padding:12px 0; border-top:1px solid var(--line); }
.danger-row:first-of-type{ border-top:0; padding-top:4px; }
.danger-row > div{ flex:1 1 220px; min-width:0; }
.danger-row p.mini{ margin:4px 0 0; }
.danger-row form{ margin:0; }

/* Settings: the add-user form, labelled like every other form. */
.user-add-title{ margin-top:18px; }
.user-add{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:0 12px; }
.user-add > label.phone-field{ grid-column:1 / -1; }
.user-add-actions{ grid-column:1 / -1; }
.user-add > .user-add-error{ grid-column:1 / -1; margin:0 0 8px; }
@media (max-width:480px){ .user-add{ grid-template-columns:minmax(0,1fr); } }
table.users td.user-actions{ text-align:right; white-space:nowrap; }
table.users td.user-actions form{ margin:0; }

/* Spend pages: every figure is spend, so it is ink with tabular figures;
   green is kept for savings. */
.spend-page td.money, .spend-page td.money a, td.money.spend a{ color:var(--ink); }

/* A table's sort, said in words above it. */
.sort-note{ margin:-6px 0 10px; }

/* The savings pipeline's "Show all N services" fold. */
.stk-more{ margin-top:2px; }
.stk-more > summary{ display:inline-flex; align-items:center; min-height:36px; cursor:pointer; font-size:var(--fs-sm); font-weight:600; color:var(--accent); }
.stk-more > .stk{ margin-top:2px; }

/* The coverage dial's target tick. */
svg .sv-target{ stroke:var(--ink2); stroke-width:3; stroke-linecap:round; }

/* App sign-up: the plan picker takes two columns where the card is wide
   enough, so six plan tiles are three rows, not a 2,600px column. */
.authcard:has(.signup-plans){ max-width:620px; }
@media (min-width:600px){ .signup-plans .plan-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
.signup-plans .po-price{ font-family:var(--mono); }

@media (max-width:760px){
  /* Export's menu opens from the left edge of its own button now that the
     row wraps instead of scrolling. */
  .spend-actions .menu-sheet{ left:0; right:auto; }
  /* The bill matrix as month cards: the figures read left beside their
     labels, and nothing is pinned. */
  table.bill-matrix.rowcards td > a{ display:inline-flex; justify-content:flex-start; min-height:32px; padding:4px 0; }
  table.bill-matrix.rowcards td:first-child > a{ padding:0 0 4px; }
  table.bill-matrix.rowcards td > .chip, table.bill-matrix.rowcards td > .mini{ margin:0; }
  table.stickyfirst.rowcards td:first-child, table.stickyfirst.rowcards th:first-child{ position:static; box-shadow:none; background:none; }
  table.rowcards td.money, table.rowcards td.num{ text-align:left; }
  .compare-table.rowcards tr.total{ background:var(--surface2); }
  .compare-table.rowcards tr.total td{ background:none; }
  .settings-form form.dirty .form-actions{ margin-inline:-14px; padding-inline:14px; }
}
/* A request tile's price: its own line, in the data face like the others. */
.plan-option > span > .po-price{ display:block; font-family:var(--mono); font-size:var(--fs-base); font-weight:600; color:var(--ink); }

/* Settings at phone width: the Save bar is pinned to the foot of the screen,
   and so is the floating chat button (static/chat.js), 10px in from the
   right. The bar keeps the button's width plus a gap clear on its right, so
   the chat circle never sits on the end of "Save settings" (C16, 14 Oct
   2026: at 390px the 48px circle covered x 332-380 of a button ending at
   351). Only when the chat box is on the page. */
@media (max-width:760px){
  body:has(> .chatbox) .settings-form .form-actions,
  body:has(> .chatbox) .settings-form form.dirty .form-actions{
    padding-right:calc(max(10px, env(safe-area-inset-right)) + 48px + 12px);
  }
}

/* A month in progress in a stacked chart: each segment keeps its tone under a
   light hatch, as the Spend chart hatches its current bar (round 5). */
.stk-row.mtd .stk-bar{ position:relative; }
.stk-row.mtd .stk-bar::after{ content:""; position:absolute; inset:0; pointer-events:none; opacity:.55;
  background:repeating-linear-gradient(135deg, transparent 0 5px, var(--surface) 5px 7px); }

/* Free-trial nudges (WG, 16 Oct 2026: no card at sign-up, so the trial
   converts only when the customer comes back and subscribes). The banner on
   every page is calm teal while the trial runs - thirty days of amber would
   read as a fault - amber in the read-only week and red once locked. The
   text and the button wrap on a phone; the button never shrinks. */
.banner.trial{ background:var(--accent-soft); color:var(--accent); }
.banner.trial-banner{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px; }
.banner.trial-banner .trial-banner-text{ flex:1 1 320px; min-width:0; }
.banner.trial-banner .btn{ height:32px; }
.banner.trial-banner .trial-banner-note{ font-weight:500; opacity:.9; }
/* The dashboard card (trial-nudge: .trial-card is the subscribe page's green
   tile): the same numbers and next steps as the reminder mail. A coloured
   left edge carries the phase, like the opinion cards. */
.trial-nudge{ margin-bottom:18px; border-left:4px solid var(--accent); }
.trial-nudge.ended{ border-left-color:var(--amber); }
.trial-nudge.locked{ border-left-color:var(--red); }
.trial-nudge-head{ display:flex; flex-wrap:wrap; align-items:flex-start; justify-content:space-between; gap:12px 18px; }
.trial-nudge-lead{ flex:1 1 360px; min-width:0; }
.trial-nudge-head h3{ margin:2px 0 6px; }
.trial-nudge-head .btn{ flex:0 0 auto; }
.trial-nudge-sum{ margin:0; color:var(--ink2); font-size:var(--fs-sm); }
.trial-nudge-next{ margin:14px 0 4px; font-size:var(--fs-sm); }
.trial-nudge-steps{ margin:0; padding-left:20px; display:grid; gap:7px; font-size:var(--fs-sm); }
.trial-nudge-steps li a{ font-weight:600; }
.trial-nudge-steps .mini{ display:block; }
@media (max-width:760px){
  .trial-nudge-head .btn, .banner.trial-banner .btn{ width:100%; }
}
