/* Fucini Coverage Studio — shared site styles */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=JetBrains+Mono:wght@100..800&display=swap');

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --bg:          #050a14;
  --bg2:         #0b1525;
  --bg3:         #0f1e35;
  --card-bg:     #0b1829;
  --accent:      #00d4ff;
  --accent2:     #0077ff;
  --green:       #00e676;
  --amber:       #ffb300;
  --red:         #ff5252;
  --text:        #e8f0fe;
  --muted:       #7a90b0;
  --border:      rgba(0,212,255,.15);
  --card-border: rgba(0,212,255,.22);
  --glow:        0 0 30px rgba(0,212,255,.25);
  --radius:      14px;
  --font:        'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono:        'JetBrains Mono', ui-monospace, 'Cascadia Code', Consolas, monospace;
}

html { scroll-behavior: smooth; }
body { background: var(--bg); color: var(--text); font-family: var(--font); line-height: 1.65; overflow-x: hidden; }

body::before {
  content: '';
  position: fixed; inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");
  pointer-events: none; z-index: 0; opacity: .6;
}

.grid-bg {
  position: fixed; inset: 0;
  background-image:
    linear-gradient(rgba(0,212,255,.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,212,255,.04) 1px, transparent 1px);
  background-size: 60px 60px;
  pointer-events: none; z-index: 0;
}

a { color: var(--accent); }
.wrap { position: relative; z-index: 1; }

/* ── NAV ── */
nav {
  position: sticky; top: 0; z-index: 100;
  display: flex; align-items: center; justify-content: space-between;
  padding: .9rem 6%;
  background: rgba(5,10,20,.85);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--border);
}
.logo { display: flex; align-items: center; gap: .7rem; text-decoration: none; color: var(--text); }
/* The Fucini Software lockup (the portal header's own file, 2x of 52px), then
   the product name and the page. Since 2026-09-15; before, a small icon and
   "Fucini Coverage Studio" in text. */
.logo-lockup { display: block; height: 40px; width: auto; }
.logo-product { padding-left: .7rem; border-left: 1px solid var(--border); }
.logo-text { font-size: 1.02rem; font-weight: 700; letter-spacing: .02em; line-height: 1.1; white-space: nowrap; }
.logo-sub { font-size: .62rem; font-weight: 500; color: var(--accent); letter-spacing: .14em; text-transform: uppercase; display: block; margin-top: 1px; white-space: nowrap; }
/* After .logo-sub, so it wins: on a phone the lockup, the product name on one
   line, the language menu and the menu button have to share ~360px. */
@media (max-width: 520px) {
  .logo { gap: .5rem; }
  .logo-lockup { height: 32px; }
  .logo-product { padding-left: .5rem; }
  .logo-text { font-size: .88rem; }
  .logo-sub { display: none; }
}
/* Below this even one line of product name pushes the menu button off screen
   (measured at 390px and 360px): the lockup alone, which still leads home. */
@media (max-width: 460px) { .logo-product { display: none; } }
.nav-links { display: none; gap: 1.4rem; align-items: center; }
.nav-links a { color: var(--muted); text-decoration: none; font-size: .82rem; letter-spacing: .02em; transition: color .2s; }
.nav-links a:hover, .nav-links a.active { color: var(--accent); }
@media (min-width: 860px) { .nav-links { display: flex; } }

/* ── mobile navigation ──────────────────────────────────────────────────────
   The rule above hides .nav-links below 860px, and until 2026-08-27 nothing
   took over: on a phone Overview, Features, Pricing and the rest were simply
   unreachable, and the footer carries only legal links. Reported by Ronny
   from an actual phone.

   The button is injected by assets/i18n.js — which all 15 pages already load
   — rather than added to each page's markup. Fifteen copies of the same nav
   is fifteen chances for it to drift. */
.nav-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0;
  background: transparent; color: var(--text);
  border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; transition: color .2s, border-color .2s;
}
.nav-toggle:hover, .nav-toggle[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
.nav-toggle svg { width: 20px; height: 20px; display: block; }
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded="true"] .icon-open { display: none; }
.nav-toggle[aria-expanded="true"] .icon-close { display: block; }
@media (min-width: 860px) { .nav-toggle { display: none; } }

@media (max-width: 859px) {
  /* `nav` is position:sticky, so it is already a containing block for this. */
  .nav-links.open {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    position: absolute; top: 100%; left: 0; right: 0;
    padding: .2rem 0 .5rem;
    /* Solid, unlike the translucent bar above it: page text showing through
       a list of links is the one place on this site where the glass effect
       costs legibility, and backdrop-filter is not reliable everywhere. */
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 12px 24px rgba(0,0,0,.45);
    /* Seventeen nav items on a short screen still have to be reachable. */
    max-height: 75vh; overflow-y: auto;
  }
  .nav-links.open a {
    padding: .8rem 6%; font-size: .95rem;
    border-top: 1px solid rgba(0,212,255,.07);
  }
  .nav-links.open a:first-child { border-top: 0; }
}

.nav-right { display: flex; align-items: center; gap: 1rem; }
.nav-badge {
  font-family: var(--mono); font-size: .68rem; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 99px; padding: .2rem .8rem;
  letter-spacing: .08em; animation: pulse-border 2.5s ease-in-out infinite;
}
@keyframes pulse-border { 0%,100% { box-shadow: 0 0 0 0 rgba(0,212,255,.4); } 50% { box-shadow: 0 0 0 6px rgba(0,212,255,0); } }
/* Portal sign-in, on every page. The account behind a purchase is where the
   company code, the seats and the billing portal live - and the activation
   email that carries that code is exactly what a corporate mail filter eats,
   which makes this link the reliable route to it rather than the convenient
   one. It reads "Log in" whether or not somebody already is: login.php
   redirects a signed-in visitor straight to their pool, so one link serves
   both states without a static page needing to know which it is. */
.nav-login {
  display: none;
  color: var(--muted); text-decoration: none; font-size: .78rem;
  border: 1px solid var(--border); border-radius: 99px; padding: .3rem .9rem;
  white-space: nowrap; transition: color .2s, border-color .2s, background .2s;
}
.nav-login:hover { color: var(--accent); border-color: var(--accent); background: rgba(0,212,255,.08); }
@media (min-width: 860px) { .nav-login { display: inline-block; } }

/* Below 860px the pill is not in the bar at all; a copy rides inside the
   collapsed menu instead, the same place Overview, Features and the rest go.
   That bar already carries the wordmark, the language selector and the
   .nav-toggle hamburger, and on a 360px phone the combination overflows
   before anything is added to it - the hamburger itself is pushed off the
   right edge, which predates this link. A fourth control would have made an
   existing problem worse and cost the wordmark its single line. Collapsing
   costs a phone visitor one extra tap and nothing else. */
.nav-login-inline { display: block; }
@media (min-width: 860px) { .nav-login-inline { display: none; } }

/* The way back out. Every page here is a product page and the wordmark on
   the left returns to the product's own overview, so nothing led up to
   fucini.software itself — the other products and the portal. Reported by
   Ronny 2026-09-06. Same two-part shape as the Log in pill above, for the
   same 360px reason: a pill in the bar from 860px, a row in the collapsed
   menu below it. `/` is the portal's own front door and sends a signed-in
   visitor on to their account, exactly as the portal's brand link does.

   The pill is a house icon alone, the name in its title and aria-label.
   With the text it was 140px, and the bar has nowhere near that: English
   already wraps "User Guide" at 1280px, Ukrainian at 1180px, and German ran
   off the right edge below 1440px. At 32px it costs one link's worth of
   breathing room, which is what the bar can spare. */
.nav-home {
  display: none; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex: none;
  color: var(--muted); border: 1px solid var(--border); border-radius: 99px;
  transition: color .2s, border-color .2s, background .2s;
}
.nav-home:hover { color: var(--accent); border-color: var(--accent); background: rgba(0,212,255,.08); }
.nav-home svg { width: 16px; height: 16px; }
@media (min-width: 860px) { .nav-home { display: inline-flex; } }
.nav-home-inline { display: block; }
.nav-home-inline svg { width: 14px; height: 14px; vertical-align: -2px; margin-inline-end: .5rem; }
@media (min-width: 860px) { .nav-home-inline { display: none; } }

/* ── HERO ── */
.hero {
  position: relative; padding: 4.5rem 6% 2.5rem; text-align: center;
  display: flex; flex-direction: column; align-items: center; overflow: hidden;
}
.hero-glow {
  position: absolute; width: 700px; height: 700px;
  background: radial-gradient(circle, rgba(0,119,255,.16) 0%, transparent 70%);
  top: 0; left: 50%; transform: translate(-50%,-45%); pointer-events: none;
}
.tag-pill {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--mono); font-size: .75rem; color: var(--accent);
  border: 1px solid var(--border); background: rgba(0,212,255,.06);
  border-radius: 99px; padding: .35rem 1rem; margin-bottom: 1.6rem; letter-spacing: .06em;
  position: relative;
}
.tag-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); animation: blink 1.4s step-end infinite; }
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0} }
h1 { font-size: clamp(2rem, 5vw, 3.1rem); font-weight: 900; line-height: 1.1; letter-spacing: -.02em; margin-bottom: 1.1rem; position: relative; }
h1 span, .grad {
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.hero-sub { font-size: clamp(1rem, 1.6vw, 1.15rem); color: var(--muted); max-width: 620px; position: relative; }
.hero-cta { display: flex; gap: .8rem; flex-wrap: wrap; justify-content: center; margin-top: 1.8rem; position: relative; }

/* ── BUTTONS ── */
.btn {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .7rem 1.4rem; background: var(--accent2); color: #fff;
  border-radius: 9px; font-size: .88rem; font-weight: 600; text-decoration: none;
  letter-spacing: .02em; transition: background .2s, transform .15s;
}
.btn:hover { background: #0065e0; transform: translateY(-1px); }
.btn.outline { background: transparent; border: 1px solid var(--accent); color: var(--accent); }
.btn.outline:hover { background: rgba(0,212,255,.08); }

/* ── CONTENT ── */
.container { max-width: 960px; margin: 0 auto; padding: 2rem 6% 4rem; position: relative; z-index: 1; }
.section-eyebrow { font-family: var(--mono); font-size: .72rem; color: var(--accent); letter-spacing: .14em; text-transform: uppercase; margin-bottom: .5rem; }
h2 { font-size: clamp(1.4rem, 3vw, 2rem); font-weight: 800; letter-spacing: -.01em; margin: 2.6rem 0 1rem; }
h3 { font-size: 1.15rem; font-weight: 700; margin: 1.8rem 0 .7rem; color: #cfe0f7; }
/* The closing, qualifying paragraph of a section - the one that says what the
   thing above it does NOT do. Used on index.html and activate.html since before
   this rule existed, which meant both rendered as ordinary body text and the
   qualification read with the same weight as the claim. */
.muted { color: var(--muted); font-size: .92rem; }
/* download.html: the version the button beside it will actually hand you,
   filled in at runtime from updates/latest*.json - the same manifests the
   extension's own update check reads, so the page cannot claim a version it
   is not serving. Stays hidden until it has a real value. */
.ver-badge { display: block; font-family: var(--mono); font-size: .72rem; color: var(--muted); letter-spacing: .04em; margin: -.45rem 0 .75rem; white-space: nowrap; }
/* [hidden] is only a UA-stylesheet display:none, which the display:block above
   outranks -- without this an unresolved badge would hold a blank line open
   under the heading instead of disappearing. */
.ver-badge[hidden] { display: none; }
/* changelog.html: version heading + its date, kept tight together — the gap before
   the NEXT release's heading stays h2's own 2.6rem top margin, unchanged. */
.release-heading h2 { margin-bottom: .25rem; }
.release-heading .section-eyebrow { margin-bottom: 1.4rem; }
p { color: #a9bad4; margin: 0 0 1rem; }
p strong { color: var(--text); }
ul, ol { color: #a9bad4; margin: 0 0 1rem 1.3rem; }
li { margin: .3rem 0; }
code { font-family: var(--mono); font-size: .85em; background: rgba(0,212,255,.08); border: 1px solid rgba(0,212,255,.12); border-radius: 5px; padding: .1rem .35rem; color: #cfe6ff; }
pre { background: rgba(0,0,0,.3); border: 1px solid rgba(0,212,255,.14); border-radius: 10px; padding: 1rem 1.2rem; overflow-x: auto; margin: 0 0 1.4rem; }
pre code { background: none; border: none; padding: 0; font-size: .82rem; line-height: 1.6; color: #cfe6ff; }

/* ── CARDS / GRID ── */
.feature-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1.2rem; margin: 1.5rem 0; }
.card {
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius);
  padding: 1.4rem 1.5rem; box-shadow: 0 8px 40px rgba(0,0,0,.35);
}
.card h3 { margin-top: 0; display: flex; align-items: center; gap: .5rem; }
.card .ico { color: var(--accent); }
.card p { font-size: .9rem; margin-bottom: 0; }

/* ── TABLE ── */
.tbl-wrap { overflow-x: auto; margin: 0 0 1.6rem; border: 1px solid var(--border); border-radius: 10px; }
table { border-collapse: collapse; width: 100%; font-size: .86rem; }
th, td { text-align: left; padding: .65rem .9rem; border-bottom: 1px solid rgba(0,212,255,.08); vertical-align: top; }
th { background: rgba(0,212,255,.05); color: var(--accent); font-weight: 600; letter-spacing: .03em; }
td code { white-space: nowrap; }
tr:last-child td { border-bottom: none; }

/* ── CALLOUTS ── */
.callout { border-left: 3px solid var(--accent); background: rgba(0,212,255,.05); border-radius: 0 10px 10px 0; padding: .9rem 1.2rem; margin: 0 0 1.4rem; }
.callout.warn { border-left-color: var(--amber); background: rgba(255,179,0,.06); }
.callout p:last-child { margin-bottom: 0; }

/* ── FAQ (faq.html) ── */
.faq-item { background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 10px; margin-bottom: .7rem; overflow: hidden; }
.faq-item summary { padding: .9rem 1.2rem; cursor: pointer; font-weight: 600; color: var(--text); list-style: none; display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after { content: '+'; color: var(--accent); font-size: 1.2rem; flex: 0 0 auto; }
.faq-item[open] summary::after { content: '\2212'; }
.faq-item summary:hover { background: rgba(0,212,255,.04); }
.faq-item .faq-a { padding: 0 1.2rem 1.1rem; }
.faq-item .faq-a p:last-child { margin-bottom: 0; }

/* ── NEWS (news.html) ── */
.news-entry { margin-bottom: 2.2rem; }
.news-date { font-family: var(--mono); font-size: .75rem; color: var(--muted); letter-spacing: .05em; text-transform: uppercase; margin-bottom: .3rem; }

/* ── NEWSLETTER SIGNUP FORM (news.html / faq.html) ── */
.newsletter-form { display: flex; gap: .6rem; flex-wrap: wrap; margin: 1rem 0 0; }
.newsletter-form input[type=email] {
  flex: 1 1 240px; padding: .7rem 1rem; border-radius: 8px; border: 1px solid var(--border);
  background: var(--bg2); color: var(--text); font: inherit;
}
.newsletter-form input[type=email]:focus { outline: none; border-color: var(--accent); }
/* Honeypot field — invisible to a real visitor, still present/tabbable to a
   naive bot that fills every input it finds. Not display:none/hidden, which
   some spam scripts specifically skip. Unscoped on purpose: every form that
   carries one gets it hidden, and a visible honeypot is worse than none —
   a real person fills it in and is turned away without being told why. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.newsletter-note { font-size: .82rem; margin-top: .6rem; }
.newsletter-note.ok { color: var(--green); }
.newsletter-note.error { color: var(--red); }

/* ── STACKED FORM (student.html) ──
   One field per row. The label wraps its input, so no `for`/`id` pairs to
   keep in step across 17 translations. */
.form { display: grid; gap: 1.1rem; margin: 1.4rem 0 0; max-width: 34rem; }
.form > label {
  display: grid; gap: .35rem;
  font-size: .82rem; font-weight: 600; letter-spacing: .02em; color: var(--muted);
  text-transform: uppercase;
}
.form input[type=text],
.form input[type=email] {
  width: 100%; padding: .7rem .9rem; border-radius: 8px; border: 1px solid var(--border);
  background: var(--bg2); color: var(--text); font: inherit;
  text-transform: none; letter-spacing: normal;
}
.form input:focus { outline: none; border-color: var(--accent); }
/* :user-invalid, not :invalid — every field here is `required`, so :invalid
   matches all six the moment the page loads and greets a visitor with a form
   already marked wrong. :user-invalid waits until they have actually typed
   something or tried to submit. */
.form input:user-invalid { border-color: var(--red); }
.form .hint {
  font-size: .8rem; font-weight: 400; color: var(--muted);
  text-transform: none; letter-spacing: normal; line-height: 1.5;
}
.form .btn { justify-self: start; margin-top: .3rem; }
.form + .muted { margin-top: 1.6rem; }

/* ── STEPS ── */
.steps { counter-reset: step; list-style: none; margin-left: 0; }
.steps li { counter-increment: step; position: relative; padding-left: 2.6rem; margin: 1rem 0; }
.steps li::before {
  content: counter(step); position: absolute; left: 0; top: -.1rem;
  width: 1.8rem; height: 1.8rem; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent2); color: #fff; font-weight: 700; font-size: .85rem;
}

/* ── SHOT (screenshot frame with graceful fallback) ── */
.shot { margin: 0 0 1.6rem; border: 1px solid var(--card-border); border-radius: 12px; overflow: hidden; background: rgba(0,0,0,.2); }
.shot img { display: block; width: 100%; height: auto; }
.shot .shot-ph { display: none; }
.shot figcaption { padding: .6rem .9rem .7rem; font-size: .84rem; line-height: 1.45; color: var(--muted); border-top: 1px solid var(--card-border); }
.shot.missing { border-style: dashed; border-color: rgba(0,212,255,.3); background: rgba(0,212,255,.03); }
.shot.missing .shot-ph { display: block; padding: 2.5rem 1rem; text-align: center; color: var(--muted); font-family: var(--mono); font-size: .78rem; }
/* A narrow capture — the status-bar card is 428px wide — sits at its own
   width instead of being stretched to the column. The badge is inline
   product output, not a screenshot: rendered at its natural 92×20. */
.shot--narrow { max-width: 428px; }
.badge-sample { margin: 0 0 1.2rem; }
.badge-sample img { display: inline-block; height: 20px; width: auto; vertical-align: middle; }

/* ── PRICING PLAN CARDS ──
   .plans scrolls horizontally, snapped to show at most 3 cards at once
   (each card ~1/3 of the row minus gaps) — stays capped at 3 in view even
   if a 4th individual tier is ever added, rather than squishing a 4th/5th
   card into the same row. .plans-team is the separate, non-scrolling
   Business/Enterprise row below it — centered, sized for exactly 2 cards,
   deliberately not part of the same scroller as the individual plans. */
/* The top padding is load-bearing, not spacing. `overflow-x: auto` makes
   this a scroll container, and CSS resolves the other axis from `visible`
   to `auto` along with it — so this box clips vertically as well, even
   though nothing here asked it to. `.plan-badge` ("14-day free trial") is
   absolutely positioned at `top: -.7rem` so it straddles the card's top
   edge, which put its upper half outside the container and got it sliced
   off — the badge rendered as a partial strip. Reserving that .7rem (plus
   a little) brings the whole badge inside the padding box. The top margin
   is reduced by the same amount, so the spacing above the row is unchanged.
   Keep `padding-top` >= the badge's negative `top` if either ever moves. */
.plans {
  display: flex; gap: 1.2rem; overflow-x: auto; scroll-snap-type: x mandatory;
  margin: 1.2rem 0 2rem; padding: .8rem 0 .6rem;
}
.plans::-webkit-scrollbar { height: 7px; }
.plans::-webkit-scrollbar-track { background: transparent; }
.plans::-webkit-scrollbar-thumb { background: var(--card-border); border-radius: 4px; }
.plans-team {
  display: flex; gap: 1.2rem; flex-wrap: wrap; justify-content: center;
  max-width: 660px; margin: 1.5rem auto 2rem;
}
.plan {
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius);
  padding: 1.6rem 1.4rem; display: flex; flex-direction: column; position: relative;
  box-shadow: 0 8px 40px rgba(0,0,0,.35);
  scroll-snap-align: start;
  flex: 1 1 calc((100% - 2.4rem) / 3); min-width: 250px;
}
.plans-team .plan { flex: 1 1 300px; }
.plan-price-text { font-size: 1.3rem; font-family: var(--font); font-weight: 800; color: var(--accent); }
.plan.featured { border-color: var(--accent); box-shadow: 0 8px 40px rgba(0,212,255,.18); }
/* `white-space: nowrap` was the second half of the clipped-badge bug. English
   ("14-day free trial") fits a card easily, but uppercased with .06em tracking
   several locales do not — uk "14-денний безкоштовний пробний період" and hr
   "14-dnevno besplatno probno razdoblje" run ~36 characters, wider than the
   250px `min-width` a card can shrink to. Unable to wrap, the badge spilled
   past both card edges and was cut by the `.plans` scroll container. It now
   wraps to a second line instead, capped at the card's own width. The `top`
   offset is unaffected: the badge grows downward, so the overhang the
   `.plans` padding compensates for stays .7rem however many lines it takes. */
.plan-badge {
  position: absolute; top: -.7rem; left: 50%; transform: translateX(-50%);
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
  color: #fff; font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: .3rem .9rem; border-radius: 99px;
  max-width: calc(100% - 1.2rem); text-align: center; line-height: 1.25;
}
.plan-name { font-size: 1.1rem; font-weight: 800; margin-bottom: .3rem; }
/* The small outlined chip after a plan name — "+ Visual Studio" on every paid
   plan. The same rule recipes.html carries inline for its format chips. */
.plan-name .fmt-badge { display: inline-block; font-size: .62rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--accent); border: 1px solid var(--accent); border-radius: 4px; padding: .1rem .45rem; margin-left: .5rem; vertical-align: middle; }
.plan-tagline { color: var(--muted); font-size: .84rem; min-height: 2.6em; margin-bottom: 1rem; }
.plan-price { font-family: var(--mono); font-size: 2rem; font-weight: 800; line-height: 1; margin-bottom: .2rem; }
.plan-price .unit { font-size: .9rem; font-weight: 500; color: var(--muted); font-family: var(--font); }
.plan-price-note { font-family: var(--mono); font-size: .7rem; color: var(--muted); margin-bottom: 1.4rem; min-height: 1.4em; }
/* Under the currency selector: what the selector can and cannot do. Quiet, but
   present on first read — a visitor who picks a currency and is then charged in
   another has been surprised, however small the difference. */
.currency-note { font-size: .74rem; color: var(--muted); margin: .6rem 0 0; text-align: center; }

/* Volume pricing table. Narrow and centred: it is a reference the buyer checks
   once, not a second set of plan cards competing with the ones above it. */
.volume-table { max-width: 560px; margin: 2.5rem auto 0; text-align: center; }
.volume-table h2 { margin-bottom: .3rem; }
.volume-table p { font-size: .82rem; margin-bottom: 1rem; }
.volume-table td + td, .volume-table th + th { text-align: right; font-family: var(--mono); }

/* What this many seats actually costs, under the seat picker. Without it the
   volume bands are invisible until Paddle renders the total — which is to say
   they sell nothing, because nobody reaches the overlay to discover a discount
   they were never told about. */
.effective-price { font-family: var(--mono); font-size: .8rem; color: var(--accent2); margin: -.6rem 0 1rem; }
.plan-cta { margin-bottom: 1.2rem; }
/* Secondary contact route under the buy button on the team plans. Deliberately
   quiet: it must not compete with the primary button for the buyer who simply
   wants to pay by card, while staying findable for the one who cannot. */
.plan-cta-alt { display: block; margin-top: .65rem; font-size: .76rem; line-height: 1.45; color: var(--muted); text-decoration: none; }
.plan-cta-alt:hover { color: var(--accent); text-decoration: underline; }
.plan-features { list-style: none; font-size: .84rem; flex: 1; margin: 0; }
.plan-features li { display: flex; gap: .55rem; padding: .4rem 0; color: var(--text); align-items: flex-start; }
.plan-features li svg { flex-shrink: 0; margin-top: .18em; color: var(--green); }
.plan-features li.dim { color: var(--muted); }
.plan-features li.dim svg { color: var(--muted); }

/* ── CURRENCY TOGGLE ── */
/* Wraps because there are eight currencies now, not five: on a narrow screen
   an unwrapped inline-flex row of them pushes the whole page sideways, and a
   pricing page that scrolls horizontally reads as broken. */
.currency-toggle { display: inline-flex; flex-wrap: wrap; justify-content: center; max-width: 100%; gap: .3rem; background: rgba(0,212,255,.06); border: 1px solid var(--border); border-radius: 10px; padding: .3rem; margin: 0 0 1.5rem; }
.currency-toggle button {
  font-family: var(--mono); font-size: .78rem; letter-spacing: .04em; padding: .4rem .8rem;
  border-radius: 7px; border: none; background: transparent; color: var(--muted); cursor: pointer; transition: all .15s;
}
.currency-toggle button:hover { color: var(--text); }
.currency-toggle button.active { background: var(--accent2); color: #fff; }
/* Billing-period toggle sits beside the currency one and borrows its styling. */
#period-toggle { margin-left: .5rem; }
/* Seat count for the per-seat plans. Hidden in the markup and revealed by
   pricing.html's checkout script only for a plan that can actually be bought
   online — so with no JavaScript the card is exactly as it was. */
.seat-picker { display: flex; align-items: center; justify-content: center; gap: .5rem; margin-bottom: 1rem; }
.seat-picker label { font-family: var(--mono); font-size: .7rem; color: var(--muted); }
.seat-picker input {
  width: 5rem; padding: .35rem .5rem; text-align: center;
  font-family: var(--mono); font-size: .85rem;
  color: var(--text); background: rgba(0,212,255,.06);
  border: 1px solid var(--border); border-radius: 8px;
}
.seat-picker input:focus { outline: none; border-color: var(--accent2); }

/* ── FOOTER ── */
/* The form fucini.consulting's footer has — three mono lines: who, the
   registration, the address — so the two sites end the same way. The legal
   links that used to sit on the right are in the quick-links panel now, on
   every page, in view before scrolling. */
footer {
  position: relative; background: var(--bg); border-top: 1px solid var(--border);
  padding: 2rem 6%; text-align: center;
}
.foot-note { margin: 0; font-family: var(--font); font-size: .8rem; color: var(--muted); line-height: 1.7; }
.foot-note-sub { font-size: .74rem; opacity: .6; margin-top: .3rem; }
.foot-note a { color: var(--muted); text-decoration: none; }
.foot-note a:hover { color: var(--accent); }

/* ── QUICK LINKS ── */
/* The product's legal pages, in view before scrolling: a panel pinned to the
   left of the content column on a wide screen, a row of pills above the hero
   on anything narrower. The same panel the portal's front page and legal
   pages show (assets/style.css there), with this product's six pages in it;
   the one you are on is marked, not linked. */
.quick-links { position: relative; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .5rem; padding: 1rem 6% 0; }
.quick-links h2 { font-size: 1rem; font-weight: 800; letter-spacing: -.01em; color: var(--text); margin: 0 .5rem 0 0; }
.quick-links h2 span { background: linear-gradient(135deg, var(--accent), var(--accent2)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.quick-links a { color: var(--muted); font-size: .8rem; padding: .2rem .65rem; border: 1px solid var(--border); border-radius: 999px; white-space: nowrap; text-decoration: none; }
.quick-links a:hover { color: var(--accent); border-color: var(--accent); }
.quick-links a.here { color: var(--text); border-color: var(--accent2); background: rgba(0,119,255,.18); cursor: default; }
@media (min-width: 1360px) {
  .quick-links {
    position: fixed; left: max(1.5rem, calc((100vw - 960px) / 2 - 14.5rem)); top: 6.5rem; z-index: 90; width: 12rem;
    flex-direction: column; align-items: stretch; gap: .35rem; margin: 0; padding: 1rem 1.1rem;
    background: rgba(15,30,53,.8); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 0 30px rgba(0,212,255,.06);
  }
  .quick-links h2 { font-size: 1.15rem; margin: 0 0 .5rem; }
  .quick-links a { border: none; padding: .25rem 0; font-size: .85rem; white-space: normal; }
  .quick-links a.here { background: none; color: var(--accent); font-weight: 600; }
  [dir="rtl"] .quick-links { left: auto; right: max(1.5rem, calc((100vw - 960px) / 2 - 14.5rem)); }
}

@media (prefers-reduced-motion: reduce) { * { animation: none !important; } }

/* ── LANGUAGE SELECTOR ── */
.lang-selector-wrapper { position: relative; display: flex; align-items: center; }
.lang-toggle { display: flex; align-items: center; gap: .4rem; background: rgba(0,212,255,.08); border: 1px solid rgba(0,212,255,.2); border-radius: 8px; padding: .4rem .7rem; cursor: pointer; font-family: var(--font); font-size: .8rem; font-weight: 600; color: var(--accent); transition: all .2s; }
.lang-toggle:hover { border-color: rgba(0,212,255,.4); background: rgba(0,212,255,.12); }
.lang-toggle svg { width: 14px; height: 14px; }
/* Eighteen languages is roughly 700px of options, so on a phone the list is
   always taller than the screen, and the height it gets has to be the height
   that is actually there: a flat 400px hangs off the bottom of a phone held
   sideways, and the part below the edge cannot be scrolled to, because the
   list rides with the sticky bar rather than with the page. `svh` is the
   viewport measured with the browser's own chrome showing — the smaller of
   the two heights a mobile browser alternates between — and the `vh` line
   above it is the fallback for anything that does not know the unit. */
.lang-dropdown { position: absolute; top: 100%; right: 0; margin-top: .5rem; background: var(--bg3); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; min-width: 200px; display: none; flex-direction: column; box-shadow: 0 8px 24px rgba(0,0,0,.3); max-height: min(400px, calc(100vh - 5.5rem)); max-height: min(400px, calc(100svh - 5.5rem)); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; z-index: 1001; }
.lang-dropdown.active { display: flex; }
/* A phone draws its own scrollbar as an overlay that fades out a moment after
   you stop moving, so a list showing nine of eighteen languages looks like the
   whole list until you happen to drag it. Custom ::-webkit-scrollbar styling
   does not reliably survive that on a touch browser, so the native bar is
   hidden (scrollbar-width above) and assets/i18n.js positions this one, which
   is just two divs and stays put for as long as the list is open: the track
   shows how much list there is, the thumb shows where in it you are. */
.lang-dropdown::-webkit-scrollbar { width: 0; height: 0; }
.lang-scrollbar {
  position: absolute; width: 4px; border-radius: 99px;
  background: rgba(0,212,255,.16); pointer-events: none;
  display: none; z-index: 1002;
}
.lang-scrollbar.visible { display: block; }
.lang-scrollbar span {
  position: absolute; left: 0; right: 0; border-radius: 99px;
  background: rgba(0,212,255,.65); display: block;
}
[dir="rtl"] .lang-dropdown { right: auto; left: 0; }
.lang-option { padding: .7rem 1rem; cursor: pointer; border-bottom: 1px solid rgba(0,212,255,.1); transition: background .15s; display: flex; align-items: center; gap: .6rem; white-space: nowrap; font-family: var(--font); font-size: .85rem; }
.lang-option:last-child { border-bottom: none; }
.lang-option:hover { background: rgba(0,212,255,.08); }
.lang-option.active { background: rgba(0,212,255,.15); color: var(--accent); font-weight: 600; }
.lang-flag { width: 22px; height: 16px; border-radius: 2px; display: inline-block; flex-shrink: 0; }
.lang-name { flex: 1; }

/* ── COOKIE / GEO CONSENT MODAL ── */
#cookie-backdrop { display: none; position: fixed; inset: 0; z-index: 2000; background: rgba(0,0,0,.78); backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px); align-items: center; justify-content: center; }
#cookie-backdrop.active { display: flex; }
#cookie-notice { background: var(--bg2); border: 1px solid var(--border); border-radius: 20px; padding: 2.5rem 2rem 2rem; max-width: 420px; width: 90%; box-shadow: 0 24px 64px rgba(0,0,0,.55); text-align: center; font-family: var(--font); animation: cnFadeIn .3s ease; }
@keyframes cnFadeIn { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: translateY(0); } }
.cn-icon { font-size: 2.2rem; margin-bottom: .9rem; display: block; }
.cn-title { font-size: 1rem; font-weight: 700; color: var(--text); margin-bottom: .6rem; letter-spacing: -.01em; }
.cn-text { font-size: .84rem; color: var(--muted); line-height: 1.65; margin-bottom: 1.6rem; }
.cn-text a { color: var(--accent); text-decoration: none; }
.cn-text a:hover { text-decoration: underline; }
.cn-actions { display: flex; gap: .75rem; justify-content: center; }
.cn-btn { font-family: var(--mono); font-size: .73rem; letter-spacing: .06em; padding: .55rem 1.6rem; border-radius: 8px; cursor: pointer; border: 1px solid; transition: all .15s; background: transparent; }
.cn-btn-accept { background: var(--accent2); border-color: var(--accent2); color: #fff; }
.cn-btn-accept:hover { filter: brightness(1.15); }

/* Below 480px this used to make the language list a `position: fixed` bottom
   sheet, which cannot work where the list sits: `nav` carries a
   backdrop-filter, and a filtered element becomes the containing block for
   its fixed-position descendants, so `bottom: 0` meant the bottom of the nav
   *bar*, not of the screen. The sheet grew upwards from there, off the top of
   the viewport, leaving two or three languages showing and no way to reach
   the rest. Turning the phone sideways made it wider than 480px, this block
   stopped applying, and the ordinary dropdown worked — which is exactly how
   Ronny found it on 2026-08-30. No phone-specific positioning any more: the
   dropdown above already fits itself to the screen at every width. */
@media (max-width: 480px) {
  /* The bar's 6% side padding is what the dropdown is positioned against, so
     it can take the rest of the width on a 320px screen without touching an
     edge. The 400px cap is dropped and the rows tighten: eighteen languages at
     this row height come to roughly 690px, so on an ordinary phone held
     upright the whole list is simply on screen and there is nothing to scroll
     at all. A short screen still scrolls, and gets the drawn bar above. */
  .lang-dropdown { max-width: calc(100vw - 12%); max-height: calc(100vh - 5.5rem); max-height: calc(100svh - 5.5rem); }
  .lang-option { padding: .55rem 1rem; }
}

/* ── ACTIVATION PAGE ──
   The post-checkout code panel. The spinner is decoration only: the site
   already disables every animation under prefers-reduced-motion, so the
   wording beside it has to carry the meaning on its own. */
.act-box {
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius);
  padding: 1.6rem 1.4rem; margin: 1.5rem 0 2rem;
}
.act-box h2 { margin-top: 0; }
.act-box p { margin: .6rem 0; }
.act-spinner {
  display: inline-block; vertical-align: -3px; margin-right: .6rem;
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--accent);
  animation: act-spin .9s linear infinite;
}
@keyframes act-spin { to { transform: rotate(360deg); } }
.act-code {
  font-family: var(--mono); font-size: 1.25rem; letter-spacing: .06em; color: var(--accent);
  background: var(--bg2); border: 1px dashed var(--card-border); border-radius: 10px;
  padding: .9rem 1rem; margin: 1rem 0; word-break: break-all; user-select: all;
}
.act-actions { display: flex; flex-wrap: wrap; gap: .6rem; margin: 1rem 0 .4rem; }

/* ── Marketplace reviews (assets/reviews.js) ──────────────────────────────
   Injected client-side, so these rules must stand on their own: nothing in
   any .html references them. */
/* scroll-margin-top clears the sticky nav: without it the shortcut lands the
   heading underneath the bar and the block looks like it starts at its second
   line. */
.rv-section { margin-top: 3.5rem; scroll-margin-top: 5.5rem; }
/* The shortcut in the hero. Same pill shape as .tag-pill so it belongs to the
   hero rather than sitting on top of it, and position:relative because
   .hero-glow is absolutely positioned over this stacking context. */
.rv-jump {
  display: inline-flex; align-items: baseline; gap: .45rem; position: relative;
  margin-top: 1.5rem; padding: .35rem .95rem;
  border: 1px solid var(--border); border-radius: 999px; background: rgba(15,30,53,.6);
  color: var(--muted); font-size: .85rem; text-decoration: none;
}
.rv-jump:hover { color: var(--text); border-color: var(--accent); }
.rv-jump-score { font-weight: 700; color: var(--text); }
.rv-h { font-size: 1.6rem; margin-bottom: .4rem; }
.rv-sub { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
          font-size: .88rem; color: var(--muted); margin-bottom: 1.4rem; }
.rv-score { font-weight: 700; color: var(--text); }
.rv-src { color: var(--accent); text-decoration: none; }
.rv-src:hover { text-decoration: underline; }
.rv-stars { color: var(--amber); letter-spacing: .08em; white-space: nowrap; }
.rv-list { display: grid; gap: 1rem; }
.rv-card { background: var(--card-bg); border: 1px solid var(--card-border);
           border-radius: var(--radius); padding: 1.3rem 1.5rem; }
.rv-head { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; margin-bottom: .6rem; }
.rv-name { font-weight: 600; }
.rv-meta { font-size: .78rem; color: var(--muted); font-family: var(--mono); }
.rv-text { font-size: .92rem; white-space: pre-wrap; margin: 0; }
.rv-reply { margin-top: .9rem; padding-left: .9rem; border-left: 2px solid var(--border); }
.rv-reply-who { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--accent); }
.rv-reply p { font-size: .88rem; white-space: pre-wrap; margin: .2rem 0 0; }
@media (max-width: 600px) { .rv-card { padding: 1.1rem 1.1rem; } }