/* ============================================================================
   Rima public marketing layer
   ----------------------------------------------------------------------------
   Loaded ONLY by unauthenticated/marketing pages, after site.css. Everything
   here is scoped under `body.pub` so the signed-in dashboard keeps the older
   look untouched. site.css tokens are read, never redefined globally.

   Design notes (deliberate, please don't "modernise" these away):
   - Paper is warm off-white, ink is the brand teal. Not #fff on #000: pure
     black/white is a flagged tell and reads cheap at large type sizes.
   - No violet/purple gradients, no gradient-filled headings, no glow shadows.
     Those are the three loudest "an AI made this page" signals.
   - Hierarchy comes from SIZE and WEIGHT, not from colour and not from a
     second typeface. Plex Mono appears only where the content is literally
     machine output: a URL bar, a CLI line, a run id. Mono as a costume for
     "technical" is a tell; it was pulled back out of labels and stats.
   - Structure is asymmetric by default (.split, .lede offset). Centre only the
     hero and the closing CTA, because a page where every section is centred reads
     like a template.
   - No kickers/eyebrows above headings, anywhere. See the note in the Type
     section; this is a hard ban, not a preference.
   - Motion is one authored moment in the hero. Sections below do not animate
     in: the same entrance repeated ten times is scatter, not design.
   ========================================================================== */

body.pub {
  /* --- palette ------------------------------------------------------------ */
  --paper: #fbfaf7;          /* warm sheet; the page's true background */
  --paper-2: #f4f2ed;        /* recessed band, e.g. alternating sections */
  --paper-3: #edeae3;        /* hairline fills, inactive chips */
  --ink: #071f26;            /* brand teal, doubles as near-black */
  --ink-2: #33474d;          /* secondary prose */
  --ink-3: #5a6b70;          /* captions; AA at 16px on paper (5.6:1) */
  --accent: #16a34a;         /* brand green, fills and rules only */
  --accent-ink: #0f7038;     /* AA-safe green for TEXT (5.4:1 on paper) */
  --accent-wash: #eaf4ec;
  --amber: #b45309;
  --amber-wash: #fdf3e4;
  --red: #b42318;
  --red-wash: #fdf0ee;

  --rule: rgba(7, 31, 38, 0.14);
  --rule-soft: rgba(7, 31, 38, 0.08);
  --rule-ink: rgba(255, 255, 255, 0.16);

  /* --- type --------------------------------------------------------------- */
  --sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;

  /* Big jumps between steps. A flat scale is what makes a page feel generic. */
  --t-display: clamp(2.4rem, 5.4vw, 4.15rem);
  --t-h2: clamp(1.95rem, 3.9vw, 3.1rem);
  --t-h3: clamp(1.15rem, 1.6vw, 1.35rem);
  --t-lede: clamp(1.06rem, 1.5vw, 1.28rem);
  --t-body: 1.0625rem;   /* 17px. 16 is the floor, this reads better */
  --t-small: 0.9375rem;  /* 15px */
  --t-label: 0.8125rem;   /* 13px. Detector floors functional text at 11px, body at 12px */

  /* --- rhythm ------------------------------------------------------------- */
  /* Varied on purpose: uniform section padding is a flagged "monotonous
     spacing" tell and flattens the read. */
  --bay: clamp(72px, 9vw, 132px);
  --bay-tight: clamp(52px, 6vw, 84px);
  --gutter: clamp(20px, 4vw, 40px);

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-pill: 999px;

  /* Soft, directional, never coloured. A glow around a card is a tell. */
  --lift: 0 1px 2px rgba(7, 31, 38, 0.05), 0 8px 24px -12px rgba(7, 31, 38, 0.16);
  --lift-lg: 0 2px 4px rgba(7, 31, 38, 0.05), 0 28px 60px -28px rgba(7, 31, 38, 0.28);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* site.css paints three fixed radial washes behind every page. On the paper
   background they turn into visible grey smudges, so they're switched off here
   and any depth is drawn per-section instead. */
body.pub::before { display: none; }

body.pub ::selection { background: var(--ink); color: var(--paper); }

/* ---------------------------------------------------------------------------
   Layout primitives
   ------------------------------------------------------------------------ */

.pub .wrap {
  width: 100%;
  max-width: 1220px;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.pub .wrap--narrow { max-width: 820px; }
.pub .wrap--text { max-width: 700px; }

.pub .bay { padding: var(--bay) 0; }
.pub .bay--tight { padding: var(--bay-tight) 0; }
.pub .bay--ruled { border-top: 1px solid var(--rule-soft); }
.pub .bay--sunk { background: var(--paper-2); }

/* Dark bay. Text is white / 72% white, never grey-on-colour, which fails AA
   in a way that looks fine to a designer and terrible to a screen reader. */
.pub .bay--ink {
  background: var(--ink);
  color: #fff;
}
.pub .bay--ink p { color: rgba(255, 255, 255, 0.74); }
/* .display hard-codes ink so it survives on paper; inside a dark bay that made
   the closing headline ink-on-ink: invisible, and a 1:1 contrast failure. */
.pub .bay--ink :is(.display, .title, .sub, h1, h2, h3) { color: #fff; }
.pub .bay--ink .note { color: rgba(255, 255, 255, 0.6); }
.pub .bay--ink a:not(.act) { color: #fff; }

/* Asymmetric two-column. The default marketing grid: copy left, artefact
   right, copy column deliberately narrower so the page isn't two equal slabs. */
.pub .split {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}
.pub .split--flip > :first-child { order: 2; }
.pub .split--top { align-items: start; }

.pub .cols-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.pub .cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.pub .cols-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }

/* ---------------------------------------------------------------------------
   Type
   ------------------------------------------------------------------------ */

/* NOTE: there is deliberately no `.eyebrow` / kicker style here.
   A small tracked-uppercase label sitting as its own block above a heading is
   the default AI-SaaS section header, and Impeccable's detector rejects it
   outright (`kicker-above-heading`, `hero-eyebrow-chip`). An earlier draft of
   this file had one and every section used it; they were removed rather than
   restyled. If a section needs the words, put them in the heading or the lede.
   Please don't reintroduce it. */

.pub .display {
  font-size: var(--t-display);
  font-weight: 600;
  line-height: 1.04;
  letter-spacing: -0.032em;
  color: var(--ink);
  text-wrap: balance;
}

.pub h2.title,
.pub .title {
  font-size: var(--t-h2);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.024em;
  color: inherit;
  text-wrap: balance;
}

.pub h3.sub,
.pub .sub {
  font-size: var(--t-h3);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.012em;
}

.pub .lede {
  font-size: var(--t-lede);
  line-height: 1.62;
  color: var(--ink-2);
  max-width: 56ch;      /* long measures are a readability flag */
  margin-top: 20px;
}

/* 58ch, not 68. The `ch` unit is the width of "0", which in Plex Sans runs
   ~11px at 17px type while the average character is ~8.5px, so a 68ch cap
   actually renders about 89 characters a line. 58ch lands near 76. */
.pub .prose { color: var(--ink-2); max-width: 58ch; line-height: 1.75; }
.pub .prose + .prose { margin-top: 16px; }

.pub .note {
  font-size: var(--t-label);
  letter-spacing: normal;
  color: var(--ink-3);
}

/* Marks a single word in a headline. Painted as a background gradient on the
   span itself rather than an absolutely-positioned pseudo-element: the box
   then tracks the text exactly, including across a line wrap, where the
   absolute version drifts onto the line below at tight leading. */
.pub .mark {
  background-image: linear-gradient(
    to top,
    rgba(22, 163, 74, 0.26) 0.14em,
    rgba(22, 163, 74, 0.26) 0.3em,
    transparent 0.3em
  );
  background-repeat: no-repeat;
  padding-inline: 0.04em;
}

/* ---------------------------------------------------------------------------
   Buttons
   ------------------------------------------------------------------------ */

.pub .act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 52px;
  padding: 0 26px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-family: var(--sans);
  font-size: var(--t-small);
  font-weight: 600;
  letter-spacing: -0.006em;
  text-decoration: none;
  cursor: pointer;
  /* transform/opacity only. Transitioning box/layout properties janks */
  transition: background-color 180ms var(--ease), color 180ms var(--ease),
    border-color 180ms var(--ease), transform 180ms var(--ease);
}
.pub .act:hover { text-decoration: none; transform: translateY(-1px); }
.pub .act:active { transform: translateY(0); }
.pub .act:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.pub .act svg { width: 17px; height: 17px; flex: 0 0 auto; }

.pub .act--solid { background: var(--ink); color: #fff; }
.pub .act--solid:hover { background: #0d3441; color: #fff; }

.pub .act--green { background: var(--accent); color: #fff; }
.pub .act--green:hover { background: #128040; color: #fff; }

.pub .act--line { background: transparent; color: var(--ink); border-color: var(--rule); }
.pub .act--line:hover { background: rgba(7, 31, 38, 0.05); border-color: var(--ink); color: var(--ink); }

.pub .bay--ink .act--solid { background: #fff; color: var(--ink); }
.pub .bay--ink .act--solid:hover { background: rgba(255, 255, 255, 0.88); color: var(--ink); }
.pub .bay--ink .act--line { color: #fff; border-color: var(--rule-ink); }
.pub .bay--ink .act--line:hover { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.4); color: #fff; }
.pub .bay--ink .act:focus-visible { outline-color: #fff; }

.pub .acts { display: flex; flex-wrap: wrap; gap: 12px; }

/* Quiet inline link with a moving underline. */
.pub .tug {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 3px;
  transition: border-color 180ms var(--ease), gap 180ms var(--ease);
}
.pub .tug:hover { text-decoration: none; border-color: var(--ink); gap: 11px; }
.pub .tug svg { width: 15px; height: 15px; }

/* ---------------------------------------------------------------------------
   Surfaces
   ------------------------------------------------------------------------ */

/* One border weight, one radius, no coloured left-edge tabs. The "accent
   stripe down the side of every card" pattern is the single most recognisable
   generated-UI tell. */
.pub .panel {
  background: #fff;
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-md);
  padding: 26px;
}
.pub .panel--flat { background: transparent; border-color: var(--rule-soft); }
.pub .bay--ink .panel {
  background: rgba(255, 255, 255, 0.05);
  border-color: var(--rule-ink);
}

/* Icons sit BESIDE their heading, never stacked above it in a rounded square:
   tile-over-heading is the universal generated feature-card silhouette
   (`icon-tile-stack`). No container either: the glyph runs in flow, sized to
   the heading it labels. */
.pub .icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  color: var(--accent-ink);
  flex: 0 0 auto;
}
.pub .icon-tile svg { width: 22px; height: 22px; }
.pub .bay--ink .icon-tile { color: #6ee7a0; }

/* Heading row: glyph and title on one line, body copy below both. */
.pub .panel--iconed {
  display: grid;
  grid-template-columns: 22px 1fr;
  grid-template-areas: "icon title" ". body";
  gap: 12px 12px;
  align-content: start;
}
.pub .panel--iconed > .icon-tile { grid-area: icon; margin-top: 2px; }
.pub .panel--iconed > :is(h3, .sub) { grid-area: title; margin: 0; }
.pub .panel--iconed > p { grid-area: body; margin: 0; }

/* Browser chrome around a real screenshot. Sells "this is a real product"
   far harder than a bare cropped image. */
.pub .shell {
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  background: #fff;
  overflow: hidden;
  box-shadow: var(--lift-lg);
}
.pub .shell__bar {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 46px;
  padding: 0 16px;
  background: var(--paper-2);
  border-bottom: 1px solid var(--rule-soft);
}
.pub .shell__dots { display: flex; gap: 7px; flex: 0 0 auto; }
.pub .shell__dots i {
  width: 10px; height: 10px; border-radius: 50%;
  background: rgba(7, 31, 38, 0.18);
}
.pub .shell__url {
  flex: 1 1 auto;
  min-width: 0;
  height: 26px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  border-radius: var(--r-pill);
  background: #fff;
  border: 1px solid var(--rule-soft);
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pub .shell img { display: block; width: 100%; height: auto; }
.pub .shell--crop img { height: clamp(280px, 38vw, 440px); object-fit: cover; object-position: top left; }

.pub .bay--ink .shell { border-color: var(--rule-ink); }
.pub .bay--ink .shell__bar { background: rgba(255, 255, 255, 0.06); border-bottom-color: var(--rule-ink); }
.pub .bay--ink .shell__dots i { background: rgba(255, 255, 255, 0.24); }
.pub .bay--ink .shell__url { background: rgba(255, 255, 255, 0.08); border-color: var(--rule-ink); color: rgba(255, 255, 255, 0.66); }

/* ---------------------------------------------------------------------------
   Repeating blocks
   ------------------------------------------------------------------------ */

/* Numbered steps. The number is mono and oversized: it carries the sequence so
   the heading doesn't have to say "Step 1". */
.pub .steps { display: grid; gap: 1px; background: var(--rule-soft); border-block: 1px solid var(--rule-soft); }
.pub .step {
  background: var(--paper);
  padding: 34px clamp(20px, 2.4vw, 34px);
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.pub .step__n {
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--accent-ink);
}
.pub .step h3 { font-size: var(--t-h3); font-weight: 600; letter-spacing: -0.012em; }
.pub .step p { color: var(--ink-2); font-size: var(--t-small); line-height: 1.68; }
.pub .step figure { margin-top: auto; padding-top: 8px; }
/* 280 rather than 210: the step-two shot is a UI panel whose labels have to
   stay readable, and at 210 it scaled to roughly 9px type. The taller box also
   matches that crop's aspect closely enough that `cover` trims almost nothing. */
.pub .step figure img {
  display: block; width: 100%; height: 280px;
  object-fit: cover; object-position: top center;
  border: 1px solid var(--rule-soft); border-radius: var(--r-sm);
  background: #fff;
}
/* Wide, short source images (a cropped UI detail rather than a full screen)
   get letterboxed instead of cropped, because `cover` magnifies them into blurry
   fragments at this height. */
.pub .step figure img.fit {
  object-fit: contain;
  object-position: center;
  background: var(--paper-2);
  padding: 14px;
}

/* A cropped panel of product UI, where every label has to survive. `cover` here
   trimmed ~22px off each side and ate the first letter of two labels ("age
   shows this text"). Contain letterboxes instead; the bars are invisible because
   the panel's own ground is white. */
.pub .step figure img.panel-shot {
  object-fit: contain;
  object-position: center;
  background: #fff;
}

/* Stat / claim row. Mono numerals, hairline dividers, no boxes. */
.pub .claims {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--rule-soft);
  border-block: 1px solid var(--rule-soft);
}
.pub .claim { background: var(--paper); padding: 26px 22px; }
.pub .claim b {
  display: block;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 6px;
}
.pub .claim span { display: block; font-size: var(--t-small); color: var(--ink-3); line-height: 1.55; }

/* Plain feature/benefit item: no card chrome, just a rule. Avoids the
   nested-card problem when these sit inside a panel. */
.pub .items { display: grid; gap: 0; }
.pub .item { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 14px; padding: 22px 0; border-top: 1px solid var(--rule-soft); }
.pub .item > * { min-width: 0; }
.pub .item:last-child { border-bottom: 1px solid var(--rule-soft); }
.pub .item .icon-tile { margin-bottom: 0; margin-top: 2px; }
.pub .item h3 { font-size: 1.02rem; font-weight: 600; margin-bottom: 5px; }
/* Capped on the paragraph, not the list: a cap on the container still leaves
   the text track as wide as the column minus the icon gutter. */
.pub .item p { font-size: var(--t-small); color: var(--ink-2); line-height: 1.65; max-width: 56ch; }

/* Small mono chips for tech/scope tags. */
.pub .chips { display: flex; flex-wrap: wrap; gap: 8px; }
.pub .chip {
  font-size: 0.8125rem;
  letter-spacing: normal;
  padding: 7px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--rule-soft);
  background: #fff;
  color: var(--ink-2);
}
.pub .bay--ink .chip { background: rgba(255, 255, 255, 0.06); border-color: var(--rule-ink); color: rgba(255, 255, 255, 0.8); }

/* ---------------------------------------------------------------------------
   FAQ: heading parked left, questions right (from the reference layouts)
   ------------------------------------------------------------------------ */

.pub .faq-split {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.pub .faq-split__aside { position: sticky; top: 96px; }

.pub .qa { border-top: 1px solid var(--rule-soft); }
.pub .qa details { border-bottom: 1px solid var(--rule-soft); }
.pub .qa summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 0;
  cursor: pointer;
  list-style: none;
  min-height: 44px;
}
.pub .qa summary::-webkit-details-marker { display: none; }
.pub .qa summary > :is(h2, h3) {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.pub .qa summary:hover > :is(h2, h3) { color: var(--accent-ink); }
.pub .qa summary:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.pub .qa summary::after {
  content: "";
  flex: 0 0 auto;
  width: 11px; height: 11px;
  margin-top: 6px;
  border-right: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3);
  transform: rotate(45deg);
  transition: transform 200ms var(--ease);
}
.pub .qa details[open] summary::after { transform: rotate(-135deg); }
.pub .qa details > p,
.pub .qa .qa__a {
  margin: 0;
  padding: 0 0 24px;
  max-width: 66ch;
  color: var(--ink-2);
  font-size: var(--t-small);
  line-height: 1.8;
}
.pub .qa a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* ---------------------------------------------------------------------------
   Closing CTA
   ------------------------------------------------------------------------ */

.pub .closer { text-align: center; padding: clamp(60px, 8vw, 104px) var(--gutter); }
.pub .closer .display { font-size: clamp(2.1rem, 4.4vw, 3.4rem); }
.pub .closer .lede { margin: 20px auto 0; text-align: center; }
.pub .closer .acts { justify-content: center; margin-top: 32px; }

/* ---------------------------------------------------------------------------
   Navbar, restyled in place
   ----------------------------------------------------------------------------
   partials/navbar.ejs is shared with the signed-in app, so nothing there is
   edited. These overrides only bite under body.pub: on marketing pages the bar
   goes light and recedes, letting the hero carry the first impression. The
   dark bar stays exactly as-is everywhere else.
   ------------------------------------------------------------------------ */

body.pub .navbar {
  background: rgba(251, 250, 247, 0.86);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms var(--ease), background-color 200ms var(--ease);
}
/* Hairline only once the page has moved. A permanent rule under a transparent
   bar looks like a mistake at scroll position 0. Toggled by pub.js. */
body.pub .navbar.is-stuck {
  background: rgba(251, 250, 247, 0.96);
  border-bottom-color: var(--rule-soft);
}
body.pub .navbar-inner { min-height: 72px; max-width: 1220px; }

body.pub .navbar-brand { color: var(--ink); font-weight: 600; font-size: 1.12rem; letter-spacing: -0.02em; }

/* logo.webp is a dark-surface lockup: the magnifier's ring and tick are green,
   but its handle and baseline are pure white. That was correct while the navbar
   was dark. On this light bar the handle disappeared and the baseline read as
   a smudge under a floating ring. logo-ink.webp is the same artwork with only
   those white pixels remapped to --ink; the green is byte-identical.
   Swapped here rather than in partials/navbar.ejs because that partial is
   shared with the signed-in app, whose navbar is still dark. The footer and the
   login/register side panels are dark too and keep the original. */
body.pub .navbar .navbar-brand img {
  height: 26px;
  content: url("/assets/images/logo-ink.webp");
}
body.pub .footer-brand .navbar-brand img { height: 28px; }

body.pub .navbar-links { gap: 2px; }
body.pub .navbar-links a {
  color: var(--ink-2);
  font-size: var(--t-small);
  font-weight: 500;
  padding: 9px 14px;
  border-radius: var(--r-pill);
}
body.pub .navbar-links a:hover { color: var(--ink); background: rgba(7, 31, 38, 0.05); }
body.pub .navbar-links a.active {
  color: var(--ink);
  font-weight: 600;
  background: rgba(7, 31, 38, 0.06);
  box-shadow: none; /* kill the inset accent underline from site.css */
}

body.pub .nav-btn-signup {
  color: var(--ink-2);
  font-size: var(--t-small);
  padding: 10px 14px;
  border-radius: var(--r-pill);
}
body.pub .nav-btn-signup:hover { color: var(--ink); background: rgba(7, 31, 38, 0.05); }

body.pub .nav-btn-login {
  background: var(--ink);
  color: #fff;
  border-color: var(--ink);
  border-radius: var(--r-pill);
  font-size: var(--t-small);
  padding: 11px 22px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
body.pub .nav-btn-login:hover { background: #0d3441; color: #fff; }

body.pub .hamburger { color: var(--ink); }
body.pub .hamburger:hover { background: rgba(7, 31, 38, 0.06); }

/* Signed-in visitors browsing marketing pages still get the workspace / profile
   controls; recolour them for the light bar. */
body.pub .navbar-user,
body.pub .nav-ws-trigger {
  background: rgba(7, 31, 38, 0.05);
  border-color: var(--rule-soft);
  color: var(--ink-2);
}
body.pub .navbar-user:hover,
body.pub .nav-ws-trigger:hover { background: rgba(7, 31, 38, 0.09); color: var(--ink); }
body.pub .navbar-user strong,
body.pub .nav-ws-trigger { color: var(--ink); }
body.pub .navbar-user .nav-caret,
body.pub .nav-ws-trigger .nav-caret { color: var(--ink-3); }

@media (max-width: 768px) {
  body.pub .navbar-links,
  body.pub .navbar-actions { border-top-color: var(--rule-soft); }
}

/* ---------------------------------------------------------------------------
   Footer
   ------------------------------------------------------------------------ */

body.pub .site-footer {
  background: var(--ink);
  border-top: none;
  margin-top: 0;
  padding: clamp(56px, 7vw, 88px) var(--gutter) 32px;
}
body.pub .footer-inner {
  max-width: 1220px;
  grid-template-columns: minmax(0, 1.6fr) repeat(4, minmax(130px, 1fr));
  gap: clamp(24px, 3.5vw, 48px);
}
body.pub .footer-brand .navbar-brand { color: #fff; font-size: 1.12rem; }
body.pub .footer-brand p {
  color: rgba(255, 255, 255, 0.6);
  font-size: var(--t-small);
  line-height: 1.65;
  margin-top: 14px;
  max-width: 30ch;
}
/* Column headings share the section label treatment, so the footer
   reads as part of the system rather than a bolted-on sitemap. */
body.pub .footer-col h2 {
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: rgba(255, 255, 255, 0.52);
  margin-bottom: 16px;
}
body.pub .footer-col ul { gap: 10px; }
body.pub .footer-col a { color: rgba(255, 255, 255, 0.76); font-size: var(--t-small); }
body.pub .footer-col a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
/* The legal links were the only green ones on the page and read as a warning. */
body.pub .footer-col a.footer-link-green { color: rgba(255, 255, 255, 0.76); font-weight: 400; }
body.pub .footer-col a.footer-link-green:hover { color: #fff; }
body.pub .footer-bottom {
  max-width: 1220px;
  margin-top: clamp(40px, 5vw, 64px);
  padding-top: 24px;
  border-top-color: var(--rule-ink);
  font-size: 0.8125rem;
  letter-spacing: normal;
  color: rgba(255, 255, 255, 0.5);
}

/* ---------------------------------------------------------------------------
   Auth pages
   ----------------------------------------------------------------------------
   One vocabulary for all five: log in, sign up, forgot password, reset
   password, resend verification. The two-column shell is only for the pages
   worth selling on (login, register). The three task pages are a single narrow
   column, because someone resetting a password is mid-task, not evaluating.
   ------------------------------------------------------------------------ */

.pub .auth {
  min-height: calc(100dvh - 72px);
  display: flex;
  align-items: center;
  padding: clamp(32px, 5vw, 72px) var(--gutter);
}
.pub .auth-shell {
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(360px, 0.86fr);
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
}

/* Sales panel. Rows sit on hairlines rather than in bordered boxes: a bordered
   box inside a panel is a nested card. */
.pub .auth-pitch {
  background: var(--ink);
  color: #fff;
  border-radius: var(--r-lg);
  padding: clamp(30px, 4vw, 46px);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.pub .auth-pitch h2 {
  font-size: clamp(1.6rem, 2.6vw, 2.2rem);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.022em;
  color: #fff;
}
.pub .auth-pitch > p { color: rgba(255, 255, 255, 0.74); line-height: 1.7; margin-top: 14px; max-width: 42ch; }
.pub .auth-pitch ul { list-style: none; margin: 26px 0 0; padding: 0; }
.pub .auth-pitch li {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: 12px;
  align-items: start;
  padding: 14px 0;
  border-top: 1px solid var(--rule-ink);
}
.pub .auth-pitch li:last-child { border-bottom: 1px solid var(--rule-ink); }
.pub .auth-pitch li svg { width: 20px; height: 20px; color: #6ee7a0; margin-top: 1px; }
.pub .auth-pitch li b { display: block; font-size: 0.95rem; font-weight: 600; }
.pub .auth-pitch li span { display: block; color: rgba(255, 255, 255, 0.7); font-size: var(--t-small); line-height: 1.55; margin-top: 2px; }

/* Form column. */
.pub .auth-form { width: 100%; }
.pub .auth-form--solo { max-width: 460px; margin: 0 auto; }
.pub .auth-form h1 {
  font-size: clamp(1.6rem, 2.6vw, 2rem);
  font-weight: 600;
  letter-spacing: -0.022em;
  line-height: 1.15;
}
.pub .auth-form > p { color: var(--ink-2); font-size: var(--t-small); line-height: 1.65; margin-top: 10px; max-width: 46ch; }
.pub .auth-fields { margin-top: 26px; display: grid; gap: 16px; }

.pub .field label {
  display: block;
  font-size: var(--t-label);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 7px;
  text-transform: none;
  letter-spacing: normal;
}
.pub .field input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  font-size: 1rem;   /* 16px: anything smaller makes iOS zoom on focus */
  font-family: var(--sans);
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  outline: none;
  transition: border-color 160ms var(--ease), box-shadow 160ms var(--ease);
}
.pub .field input::placeholder { color: var(--ink-3); }
.pub .field input:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px rgba(7, 31, 38, 0.1);
}
.pub .field .hint { display: block; font-size: var(--t-label); color: var(--ink-3); margin-top: 8px; padding: 5px 0; line-height: 1.55; }

.pub .pw { position: relative; }
.pub .pw input { padding-right: 46px; }
.pub .pw-toggle {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: var(--r-sm);
  color: var(--ink-3);
  cursor: pointer;
}
.pub .pw-toggle:hover { color: var(--ink); background: rgba(7, 31, 38, 0.05); }

.pub .auth-form .act { width: 100%; margin-top: 24px; }

/* One quiet row of links under the form. Replaces the two stacked inline email
   forms that used to live on the login page. */
.pub .auth-links {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--rule-soft);
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: var(--t-small);
  color: var(--ink-3);
}
.pub .auth-links a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.pub .auth-alt { margin-top: 20px; font-size: var(--t-small); color: var(--ink-3); }
.pub .auth-alt a { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }

/* Back link on the three task pages. */
.pub .auth-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--t-small);
  color: var(--ink-3);
  text-decoration: none;
  margin-bottom: 22px;
}
.pub .auth-back:hover { color: var(--ink); text-decoration: none; }
.pub .auth-back svg { width: 15px; height: 15px; }

@media (max-width: 880px) {
  .pub .auth-shell { grid-template-columns: 1fr; max-width: 460px; }
  /* The pitch is supporting material; on a phone it pushes the form itself
     below the fold, so it steps aside rather than stacking. */
  .pub .auth-pitch { display: none; }
}

/* ---------------------------------------------------------------------------
   Legacy normalisation
   ----------------------------------------------------------------------------
   Every marketing page carries its own inline <style> block, and those blocks
   are parsed AFTER this file, so a bare `.pricing-price .amount` would beat a
   bare `.amount` here. Each rule below is therefore prefixed with `body.pub`
   to out-specify the page's own declaration without editing twenty files.

   Three families of problem are corrected:
     1. Gradient-filled headings:  the loudest generated-UI tell there is,
                                     and it drops real text contrast to zero
                                     wherever background-clip is unsupported.
     2. Accent bars down one edge: the "side-tab" card, second loudest tell.
     3. Ad-hoc green bold kickers: twenty near-identical *-kicker classes,
                                     unified onto the mono eyebrow.
   ------------------------------------------------------------------------ */

/* 1. Gradient text --------------------------------------------------------- */
body.pub .pricing-price .amount,
body.pub .notfound-code {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  -webkit-text-fill-color: currentColor;
  color: var(--ink);
}
body.pub .notfound-code {
  font-family: var(--mono);
  font-weight: 500;
  letter-spacing: -0.02em;
}

/* 2. Side-tab accent borders ---------------------------------------------- */
/* Replaced with a full hairline. A callout still needs to read as a callout,
   so the emphasis moves to a tinted ground instead of a coloured edge. */
body.pub .lr-note,
body.pub .lr-callout,
body.pub .docs-callout,
body.pub .atw-note,
body.pub .wat-note,
body.pub [class*="-callout"],
body.pub [class*="-note"]:not(.note) {
  border-left-width: 1px;
  border-left-style: solid;
  border-left-color: var(--rule-soft);
}

/* 3. Kickers --------------------------------------------------------------- */
/* Removed, not restyled. Each of these is a tracked-caps micro-label sitting on
   its own line above a heading is the shape Impeccable rejects outright. In every
   case the heading underneath already says the same thing ("ABOUT RIMA" over
   "We help teams catch browser bugs before users do"), so hiding them loses no
   information. Hidden rather than deleted from the markup so the pages stay
   diff-clean and the words survive for anyone reading the source. */
body.pub .kicker,
body.pub .about-kicker,
body.pub .alt-kicker,
body.pub .atw-kicker,
body.pub .cmp-kicker,
body.pub .contact-kicker,
body.pub .docs-kicker,
body.pub .invite-kicker,
body.pub .notfound-kicker,
body.pub .pa-kicker,
body.pub .wat-kicker,
body.pub .payment-guide-kicker,
body.pub .section-kicker { display: none; }

/* 4. Page headings --------------------------------------------------------- */
/* Marketing pages each sized their own h1. Route them through the display
   scale so the whole site shares one typographic hierarchy. */
body.pub .page-title,
body.pub .pricing-hero h1,
body.pub .about-hero h1,
body.pub .contact-hero h1,
body.pub .alt-hero h1,
body.pub .cmp-hero h1,
body.pub .wat-hero h1,
body.pub .atw-hero h1,
body.pub .docs-hero h1 {
  font-size: var(--t-h2);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.024em;
  color: var(--ink);
  text-wrap: balance;
}

/* 5. Cards ----------------------------------------------------------------- */
/* site.css gives .card a translucent fill plus a backdrop blur. Over paper that
   turns into a muddy grey rectangle, so marketing pages get a flat white card. */
body.pub .card {
  background: #fff;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-color: var(--rule-soft);
  border-radius: var(--r-md);
  box-shadow: none;
}
body.pub .card:hover { box-shadow: var(--lift); border-color: var(--rule); }

/* 6. Green contrast -------------------------------------------------------- */
/* --accent (#16a34a) is a brand fill, not a text colour. Two failures recur
   across the older pages and both are fixed at the source here:
     · #16a34a text on the pale green wash  -> 2.9:1
     · #ffffff text on a #16a34a fill       -> 3.3:1
   Green TEXT moves to --accent-ink (#0f7038); green FILLS carrying white text
   darken to #0f7038 too, which clears 4.5:1 while staying recognisably brand. */
body.pub .badge-accent,
body.pub .text-accent,
body.pub :is(.pricing-check, .feature-yes, .check-yes) {
  color: var(--accent-ink);
}
body.pub .badge-accent { background: var(--accent-wash); }

body.pub .btn-accent,
body.pub .badge-solid-accent,
body.pub :is(.tag-accent, .pill-accent, .trial-pill) {
  background: var(--accent-ink);
  border-color: var(--accent-ink);
  color: #fff;
}
body.pub .btn-accent:hover { background: #0b5c2c; border-color: #0b5c2c; }

/* Anything the page painted green-on-green: keep the wash, darken the ink. */
body.pub [class*="accent-light"],
body.pub [class*="-success"] { color: var(--accent-ink); }

/* 7. Uppercase, micro-text and cramped boxes on the older pages ------------ */
/* Sentence-length uppercase is a readability failure, not a style: we read by
   word shape, and caps flattens every word to a rectangle. These labels are all
   real words ("Build tests", "Getting started"), not 3-letter tags. */
body.pub :is(.docs-group-title, .docs-tag, .docs-ref-toggle, .cat-label, .doc-label) {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 600;
}
/* Functional text below the 11px floor: group counts, tags, read times. */
body.pub :is(.docs-group-count, .docs-tag, .docs-ref-toggle, .docs-readtime),
body.pub :is(.cmp-cell, .cmp-note, .alt-note) {
  font-size: 0.8125rem;
}
body.pub .docs-group-count { padding: 3px 9px; }
/* Green-on-green pill: 2.9:1. Keep the wash, darken the ink to clear AA. */
body.pub .docs-tag {
  background: var(--accent-wash);
  color: var(--accent-ink);
}
body.pub .docs-group-title { color: var(--ink-2); font-size: 0.9375rem; }
body.pub .docs-ref-toggle { color: var(--accent-ink); }
/* A bordered, filled wrapper whose children touch the border on every side. */
body.pub .cmp-table-wrap { padding: 2px; }
/* Legal pages are one long measure of prose; cap it for readability. */
/* Legal pages run one uninterrupted measure across a 1100px container, about 160
   characters a line. Cap the measure and centre the column; the all-caps
   liability clause stays as written, since that convention is legally
   deliberate rather than a styling choice. */
/* The measure has to be set on the text elements themselves: a `ch` cap on the
   card resolves against the CARD's font-size (17px), while the paragraphs
   inside run at 14.7px, so the cap lands ~15 characters too wide. Sizing up to
   15px at the same time, since legal copy is the text people least want to squint at. */
body.pub .legal-card :is(p, li) { font-size: 0.9375rem; max-width: 68ch; }
body.pub .legal-card :is(h2, h3) { max-width: 68ch; }
body.pub .legal-card a { color: var(--accent-ink); }
body.pub .legal-meta { color: var(--ink-2); }
body.pub .legal-header p { max-width: 60ch; margin-inline: auto; }

/* 8. Browser surfaces ------------------------------------------------------ */
/* The chrome we did not draw still carries the design; left at defaults it is
   the giveaway that a page was assembled rather than built. */
body.pub { caret-color: var(--accent-ink); scrollbar-color: rgba(7, 31, 38, 0.28) transparent; }
body.pub a { text-underline-offset: 3px; text-decoration-thickness: 1px; }
body.pub :focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 3px; }
body.pub ::-webkit-scrollbar { width: 12px; height: 12px; }
body.pub ::-webkit-scrollbar-track { background: transparent; }
body.pub ::-webkit-scrollbar-thumb {
  background: rgba(7, 31, 38, 0.22);
  border: 3px solid var(--paper);
  border-radius: var(--r-pill);
}
body.pub ::-webkit-scrollbar-thumb:hover { background: rgba(7, 31, 38, 0.36); }
/* Numerals in any table or metric line up column-wise. */
body.pub :is(table, .claim b, .report__id) { font-variant-numeric: tabular-nums; }

/* 9. Measure --------------------------------------------------------------- */
/* A cap on every text-bearing element the older pages left running the full
   container width. Set on the elements themselves, not their wrappers, so `ch`
   resolves against the text's own size. Table cells are excluded, because a comparison
   table is scanned in columns and capping cells there just adds ragged rows.
   The prose around them is still capped. */
body.pub :is(.about-body, .about-copy, .alt-body, .cmp-body, .wat-body, .atw-body,
             .docs-article-body, .docs-summary, .contact-body) :is(p, li) {
  max-width: 70ch;
}
body.pub :is(section, article) > :is(p, ul, ol):not([class]) { max-width: 70ch; }
/* The two long-tail SEO pages are mostly unclassed prose in wide containers. */
body.pub :is(.wat-section, .atw-section, .wat-block, .atw-block, .seo-prose) :is(p, li) { max-width: 70ch; }
body.pub main :is(p, li) { max-width: 74ch; }
body.pub main :is(.cmp-table, table) :is(p, li) { max-width: none; }
body.pub .cmp-table :is(td, th) { max-width: 46ch; }

/* Docs sidebar / category labels below the functional-text floor. */
body.pub :is(.docs-nav-group, .docs-side-label, .docs-cat, .docs-crumb) {
  font-size: 0.8125rem;
  text-transform: none;
  letter-spacing: normal;
}

/* 10. Buttons -------------------------------------------------------------- */
body.pub .btn { border-radius: var(--r-pill); font-size: var(--t-small); }
body.pub .btn-lg { min-height: 52px; padding: 0 26px; }
body.pub .btn-primary { background: var(--ink); border-color: var(--ink); }
body.pub .btn-primary:hover { background: #0d3441; }
body.pub .btn-outline { color: var(--ink); border-color: var(--rule); }
body.pub .btn-outline:hover { background: rgba(7, 31, 38, 0.05); border-color: var(--ink); color: var(--ink); }

/* ---------------------------------------------------------------------------
   Motion: entrance only, and only if the visitor allows it
   ------------------------------------------------------------------------ */

/* Content is visible by DEFAULT and only hidden once an inline head script has
   confirmed JS is alive (html.rise-on). See the publicPage block in
   partials/head.ejs. Hiding first and un-hiding from a deferred script means a
   single failed request leaves the whole page blank; this way the worst case is
   no animation. The same head script drops .rise-on again if pub.js never boots. */
/* Only the first viewport animates, and it resolves once. Repeating an
   identical entrance down every section is scattered effect, not motion
   design. The sections below simply are, which is also what a visitor
   scrolling fast actually wants. */
html.rise-on .pub .hero .rise { opacity: 0; transform: translateY(12px); }
html.rise-on .pub .hero .rise.in {
  opacity: 1;
  transform: none;
  /* exponential ease-out, long enough to read as arrival rather than a blink */
  transition: opacity 620ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 620ms cubic-bezier(0.16, 1, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  html.rise-on .pub .hero .rise,
  html.rise-on .pub .hero .rise.in { opacity: 1; transform: none; transition: none; }
  .pub .act:hover,
  .pub .act:active { transform: none; }
  .pub .qa summary::after { transition: none; }
}

/* ---------------------------------------------------------------------------
   Responsive
   ------------------------------------------------------------------------ */

@media (max-width: 1040px) {
  .pub .cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pub .claims { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pub .steps { grid-template-columns: 1fr !important; }
}

@media (max-width: 880px) {
  .pub .split,
  .pub .faq-split { grid-template-columns: 1fr; }
  .pub .split--flip > :first-child { order: 0; }
  .pub .faq-split__aside { position: static; }
  .pub .cols-3 { grid-template-columns: 1fr; }
  .pub .lede { max-width: none; }
}

@media (max-width: 560px) {
  .pub .cols-2,
  .pub .cols-4 { grid-template-columns: 1fr; }
  .pub .claims { grid-template-columns: 1fr; }
  .pub .acts .act { width: 100%; }
  .pub .step figure img { height: 168px; }
}

/* ---------------------------------------------------------------------------
   Mobile corrections
   ----------------------------------------------------------------------------
   The footer override above is a plain `body.pub .footer-inner` rule, which
   out-specifies partials/footer.ejs's own `@media (max-width: 768px)` collapse
   collapse, so the five-column grid survived onto phones and forced ~250px of
   horizontal page scroll on every page. Media queries do not add specificity;
   the override has to restate the collapse itself.
   ------------------------------------------------------------------------ */

@media (max-width: 768px) {
  body.pub .footer-inner { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
  body.pub .footer-inner { grid-template-columns: 1fr; }
}

/* Wide tables scroll inside their own wrapper; they must never widen the page.
   min-width:0 is required for a grid/flex child to be allowed to shrink. */
body.pub :is(.cmp-table-wrap, .table-wrap, .overflow-x) {
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
body.pub :is(main, section, article, .wrap, .container, .container-wide) { min-width: 0; }
body.pub :is(.split, .cols-2, .cols-3, .cols-4, .steps, .claims, .who, .asks, .route) > * { min-width: 0; }
body.pub img { max-width: 100%; }

/* The toast container is position:fixed at right:24px with a percentage width;
   it extends the document's scroll width even though it never scrolls with the
   page. `clip` kills the horizontal scrollbar without trapping vertical scroll
   the way `hidden` on <html> can. */
html:has(body.pub) { overflow-x: clip; }

/* Belt and braces: nothing in the marketing layer may introduce a horizontal
   scrollbar. Vertical scrolling stays untouched. */
body.pub { overflow-x: hidden; }
