/* /invoice-generator — the free, public, no-login invoice generator.
   Self-hosted only (see Tests\Feature\Controller\PublicLayoutAssetsTest): the
   layout has no Bootstrap CSS to lean on (unlike the portal, which loads it
   from a CDN), so every input, card and grid rule a public page needs is
   defined here rather than assumed. Palette and the --brand variable come
   from /css/public.css, loaded first by layout.public. */

/* ===== HERO =====
   The palette, the glow and the type scale are /pricing's and the landing
   page's, so the three public pages read as one product. The height is not:
   /pricing spends 5rem/9rem because its cards are the page, while here the
   tool is the page and has to be visible without scrolling.

   No card overlap here, unlike /pricing: this section's grey background would
   simply cover whatever it was lifted over, because it is the section that is
   coloured and not the cards. A crisp dark-to-grey edge does the same job of
   separating the pitch from the tool, in half the height. */
.gen-hero {
    padding: 2.5rem 0 2.75rem;
    background: #070b1e;
    text-align: center;
    position: relative;
    overflow: hidden;
}
.gen-hero-glow {
    position: absolute;
    top: -140px; left: 50%; transform: translateX(-50%);
    width: 900px; height: 560px;
    background: radial-gradient(ellipse, rgba(37,99,235,.20) 0%, rgba(124,58,237,.11) 45%, transparent 70%);
    pointer-events: none;
}
.gen-hero .container { position: relative; }
.gen-badge {
    display: inline-block;
    background: rgba(74,222,128,.10);
    color: #86efac;
    /* .28 alpha is what clears 3:1 against #070b1e for a non-text boundary,
       the same figure /pricing's own pill uses. */
    border: 1px solid rgba(134,239,172,.28);
    border-radius: 999px;
    padding: .3rem .875rem;
    font-size: .8125rem;
    font-weight: 500;
}
.gen-hero h1 {
    font-size: clamp(1.875rem, 4.5vw, 2.75rem);
    font-weight: 700;
    letter-spacing: -.03em;
    line-height: 1.15;
    margin: .875rem 0 .75rem;
    color: #fff;
}
.gen-hero-sub {
    font-size: 1.0625rem;
    color: rgba(255,255,255,.65);
    max-width: 560px;
    margin: 0 auto;
    line-height: 1.7;
}
.gen-hero-sub strong { color: #fff; font-weight: 600; }

/* ===== TOOL LAYOUT =====
   Same two-column shape as the portal editor (form + sticky preview), kept
   independent of invoice-editor.css: that file is portal-only and this page
   loads no other stylesheet besides /css/public.css. */
.gen-tool {
    padding: 1.75rem 0 3rem;
    background: #f6f8fa;
}
.gen-layout {
    display: flex;
    align-items: flex-start;
    gap: 2rem;
    flex-wrap: wrap;
    padding-top: 0;
}
.gen-form-col {
    flex: 1 1 560px;
    min-width: 0;
}
.gen-preview-col {
    flex: 0 1 560px;
    min-width: 320px;
    position: sticky;
    top: 76px;
    /* The document's tables (line items, bank grid) carry no width caps of
       their own — the portal's editor gets away with that because its
       preview column sits well clear of the viewport edge, but this pane is
       narrower and on the first screen of the page the whole organic-search
       programme is aimed at, so it needs to scroll sideways rather than blow
       out the page's own layout. */
    overflow-x: auto;
}
@media (max-width: 1099.98px) {
    .gen-preview-col {
        position: static;
        flex: 1 1 100%;
    }
}

/* ===== CARDS =====
   Same recipe as the portal editor's .card-clean (app/views/layout/portal.dark.php):
   white on the page's #f6f8fa, a hairline border and a barely-there shadow for
   depth rather than a heavier one that would compete with the preview column. */
.gen-card {
    background: #fff;
    border: 1px solid #e9ecf0;
    border-radius: 10px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
    padding: 1.25rem;
    margin-bottom: 1rem;
}
.gen-card h2 {
    font-size: .875rem;
    font-weight: 600;
    color: #1a1d21;
    margin: 0 0 1rem;
}
.gen-subheading {
    font-size: .8125rem;
    font-weight: 600;
    margin: 1.25rem 0 .25rem;
}
.gen-hint {
    font-size: .75rem;
    color: #6b7280;
    margin: 0 0 .75rem;
}
/* The owner's own complaint: this rule was only noticed once a 1 MB+ file
   was already rejected. It sits in the same spot the plain .gen-hint above
   already puts it (right under the control), so the fix is contrast, not
   position — a size limit is worth reading before it turns into an error. */
.gen-hint-logo {
    margin-top: .375rem;
    font-weight: 500;
    color: #4a5058;
}

/* The file input and the one control that empties it, on one line. The button
   is drawn only while there is a logo to take back out (invoice-generator.js),
   so the row is a plain input on its own the rest of the time. */
.gen-logo-row {
    display: flex;
    align-items: center;
    gap: .5rem;
}
.gen-logo-row .gen-input {
    flex: 1 1 auto;
    min-width: 0;
    margin-bottom: 0;
}

/* Quiet until hovered, like .gen-btn-remove-row: it throws work away and must
   not compete with Download for attention. Text rather than a glyph — it
   appears next to a control whose own label is the file name, where a bare ×
   would be ambiguous about which of the two it empties. */
.gen-btn-clear-logo {
    flex: 0 0 auto;
    border: 0;
    border-radius: 7px;
    padding: .5rem .625rem;
    background: transparent;
    font: inherit;
    font-weight: 600;
    color: #4a5058;
    cursor: pointer;
    transition: color .15s, background .15s;
}
.gen-btn-clear-logo:hover { background: #fee2e2; color: #dc2626; }
.gen-btn-clear-logo[hidden] { display: none; }

/* ===== FORM CONTROLS =====
   No Bootstrap form-control on this page (see the file header) — plain rules
   for every control the form uses. */
.gen-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: .875rem 1rem;
}
@media (max-width: 480px) {
    .gen-grid { grid-template-columns: 1fr; }
}
.gen-span-2 { grid-column: span 2; }
@media (max-width: 480px) {
    .gen-span-2 { grid-column: span 1; }
}
.gen-field {
    display: flex;
    flex-direction: column;
    gap: .3rem;
}
.gen-field label {
    font-size: .8125rem;
    font-weight: 500;
    /* Matches the portal's --text-label. */
    color: #4a5058;
}
.gen-field .req { color: #dc2626; }
/* Same #6b7280 as .gen-hint, not the lighter grey this started as: "(optional)"
   is text a sighted user is meant to read, and #9ca3af on white is 2.5:1 —
   under half the 4.5:1 floor, on the one word that tells someone they can skip
   a field. It still reads as secondary to the label beside it, because the
   label is darker (#4a5058) *and* heavier (500 against this 400); the weight
   was always doing most of that work, so nothing about the hierarchy changes. */
.gen-field .opt,
.gen-hint .opt { color: #6b7280; font-weight: 400; }

.gen-input,
.gen-select,
.gen-textarea {
    width: 100%;
    font-size: .875rem;
    padding: .5rem .625rem;
    border: 1px solid #d9dee3;
    border-radius: 7px;
    background: #fff;
    color: #1a1d21;
}
/* Matches the portal editor's own house idiom
   (app/views/layout/portal.dark.php's `.form-control:focus`): a restrained
   border-color change plus a soft box-shadow ring, not a thick brand-coloured
   outline on every field. Border alone would be too weak a signal for a
   keyboard user on a white background, which is why the ring stays — it is
   just quieter than an outline. `outline: none` only removes the UA default
   on this specific pairing; buttons keep their own :focus-visible outline
   below. */
.gen-input:focus,
.gen-select:focus,
.gen-textarea:focus {
    outline: none;
    border-color: #676f7a;
    box-shadow: 0 0 0 3px rgba(103, 111, 122, .12);
}
.gen-textarea { resize: vertical; }

/* The UA's own dropdown arrow sits hard against the right edge of the control,
   because the padding above is the *text's* padding and the arrow is drawn
   outside it — so eleven selects on this page each ended with a native triangle
   jammed into the border. Drawing it instead buys the gap back (the arrow is now
   positioned like everything else) and, more to the point, it is the same
   chevron the FAQ opens with: one arrow, drawn one way, everywhere on the page.
   Both -webkit- and -moz- prefixes stay — Safari ignores the unprefixed
   property on <select> to this day, and without it the native arrow is still
   painted on top of this one. */
.gen-select {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding-right: 2.125rem;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right .625rem center;
    background-size: .875rem;
}

/* 16px on touch devices, and 16px exactly because that is iOS Safari's
   threshold: focus an input whose text is smaller and the browser zooms the
   page in to compensate, leaving the visitor scrolled sideways on a form with
   ~40 fields, with the preview column pushed off-screen and no way back except
   pinching out after every single tap. It is not a font-size preference, it is
   the difference between the page working and not working on a phone.

   `pointer: coarse` rather than a width breakpoint: the zoom is a property of
   the touch devices, not of narrow windows, and a tablet wide enough to keep
   the two-column layout zooms just the same. Desktop keeps the denser .875rem,
   which is what the portal editor uses and what the row heights were drawn
   for. */
@media (pointer: coarse) {
    .gen-input,
    .gen-select,
    .gen-textarea,
    .gen-input-suffix { font-size: 1rem; }
}
.gen-mb-2 { margin-bottom: .5rem; }

.gen-input-group {
    display: flex;
    align-items: stretch;
}
.gen-input-group .gen-input {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}
.gen-input-suffix {
    display: inline-flex;
    align-items: center;
    padding: 0 .75rem;
    background: #f6f8fa;
    border: 1px solid #d9dee3;
    border-left: 0;
    border-top-right-radius: 7px;
    border-bottom-right-radius: 7px;
    font-size: .875rem;
    color: #6b7280;
}

/* ===== LINE ITEMS ===== */
.gen-items-wrap { overflow-x: auto; }
.gen-items-table {
    width: 100%;
    min-width: 640px;
    border-collapse: collapse;
    font-size: .8125rem;
}
.gen-items-table th {
    text-align: left;
    font-weight: 600;
    color: #6b7280;
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    padding: 0 .5rem .5rem;
    border-bottom: 1px solid #e9ecf0;
}
.gen-items-table td {
    padding: .5rem;
    vertical-align: top;
    border-bottom: 1px solid #f1f3f5;
}
.gen-items-table .gen-input { margin-bottom: .375rem; }
.gen-items-table .gen-input:last-child { margin-bottom: 0; }
.gen-input-num { text-align: right; }
/* Name and rate side by side, not stacked: two short fields sharing one
   column read as one "tax" control at a glance, the way the portal's own
   tax picker reads as a single control in its cell. The generic stacking
   rule above (margin-bottom on every td> .gen-input) is what put them on
   separate lines; overriding it to a row and zeroing that margin is the
   whole fix. */
.gen-tax-cell {
    min-width: 220px;
    display: flex;
    gap: .375rem;
}
.gen-tax-cell .gen-input { margin-bottom: 0; }
.gen-tax-cell .gen-tax-name { flex: 1 1 auto; min-width: 0; }
.gen-tax-cell .gen-tax-rate { flex: 0 0 4.5rem; text-align: right; }

/* The portal editor's own remove control (.btn-remove-line in
   invoice-editor.css), minus its reveal-on-hover: no border and no fill, a muted
   glyph that turns red on the same #fee2e2 wash. The bordered white box this
   started as read as a *button* — the same visual weight as Download, for the
   one control that throws work away, repeated down the table.
   The portal can afford to hide it until the row is hovered because its user has
   seen the screen before; a first-time visitor here cannot be asked to discover
   a control that isn't drawn, so it stays visible and goes quiet instead.
   #868d95 is 3.36:1 on white — above the 3:1 non-text floor, which a glyph this
   small has to clear to count as visible at all. */
.gen-btn-remove-row {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: #868d95;
    cursor: pointer;
    transition: color .15s, background .15s;
}
.gen-btn-remove-row:hover { background: #fee2e2; color: #dc2626; }

/* 30px is comfortable with a mouse and too small for a thumb — the row's one
   destructive control, sitting next to two number fields. It reaches the 44px
   floor only where the pointer is coarse. */
@media (pointer: coarse) {
    .gen-btn-remove-row {
        width: 44px;
        height: 44px;
    }
}

/* The "next row goes here" slot: full width, dashed, directly under the last
   row. The dashed edge is decoration rather than the thing that identifies the
   control — the label and the + inside it are at 8:1, so the border is free to
   stay light — and it turns brand-coloured on hover, which is the only colour
   this card ever shows. */
.gen-btn-add-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    width: 100%;
    min-height: 44px;
    margin-top: .75rem;
    padding: 0 .875rem;
    border: 1px dashed #cbd2d9;
    border-radius: 8px;
    background: transparent;
    color: #4a5058;
    font-size: .8125rem;
    font-weight: 500;
    cursor: pointer;
    transition: border-color .15s, color .15s, background .15s;
}
.gen-btn-add-row:hover {
    border-color: var(--brand);
    color: var(--brand);
    background: rgba(37, 99, 235, .04);
}

/* Buttons had no focus style of their own, so a keyboard user following the
   form down to Download or Save landed on whatever the UA happened to draw.
   :focus-visible rather than :focus, so a mouse click does not leave a ring. */
.gen-btn:focus-visible,
.gen-btn-add-row:focus-visible,
.gen-btn-clear-logo:focus-visible,
.gen-btn-remove-row:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}

/* ===== BUTTONS ===== */
.gen-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 1.125rem;
    border-radius: 8px;
    font-size: .875rem;
    font-weight: 500;
    border: 1px solid transparent;
    cursor: pointer;
    text-decoration: none;
    transition: opacity .15s, box-shadow .15s, background .15s;
}
.gen-btn-primary {
    background: linear-gradient(135deg, #2563eb, #7c3aed);
    color: #fff;
    box-shadow: 0 3px 12px rgba(37,99,235,.35);
}
.gen-btn-primary:hover { opacity: .92; box-shadow: 0 5px 20px rgba(37,99,235,.5); color: #fff; }
.gen-btn-secondary {
    background: #fff;
    border-color: #8b9096;
    color: #1a1d21;
}
.gen-btn-secondary:hover { background: #f6f8fa; border-color: #5f6875; }
.gen-btn-submit { width: 100%; margin-top: .25rem; }

/* ===== FORM FEEDBACK =====
   invoice-generator.js's own: a 422 places one of these against the input
   named in the response, a 429 or 500 has no input to blame and shows only
   the banner. */
/* The template offer. Informational rather than an error, so it borrows the
   banner's shape and none of its red — a visitor who arrived from a template
   page has done nothing wrong, they simply have work in progress. */
.gen-preset-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .75rem;
    margin-bottom: .75rem;
    padding: .625rem .875rem;
    border-radius: 8px;
    background: #eff6ff;
    border: 1px solid #bfdbfe;
    color: #1e3a8a;
    font-size: .8125rem;
}
.gen-preset-actions {
    display: flex;
    gap: .5rem;
    margin-left: auto;
}
.gen-btn-preset-apply,
.gen-btn-preset-dismiss {
    border-radius: 6px;
    padding: .3rem .7rem;
    font-size: .78125rem;
    font-weight: 600;
    cursor: pointer;
}
.gen-btn-preset-apply {
    background: #2563eb;
    border: 1px solid #2563eb;
    color: #fff;
}
.gen-btn-preset-dismiss {
    background: transparent;
    border: 1px solid #bfdbfe;
    color: #1e3a8a;
}

.gen-banner {
    margin-bottom: .75rem;
    padding: .625rem .875rem;
    border-radius: 8px;
    background: #fef2f2;
    border: 1px solid #fecaca;
    color: #991b1b;
    font-size: .8125rem;
}
.gen-field-error {
    margin-top: .25rem;
    font-size: .75rem;
    color: #b91c1c;
}
.gen-input-invalid,
.gen-input-invalid.gen-input,
.gen-input-invalid.gen-select {
    border-color: #dc2626;
}

/* ===== SUPPORTING CONTENT =====
   Headings, lead lines and section rhythm are /pricing's (1.5rem / 600 /
   centred, with a muted sub-line under the heading), so a visitor who lands
   here from search and then opens /pricing does not meet two different
   typographies. The measure stays at 700px, the same as /pricing's FAQ column:
   the guideline is 65–75 characters a line and a 720px column of 16px text
   overshoots it. */
.gen-content { padding: 3.5rem 0; }
.gen-content-inner { max-width: 700px; }
.gen-content h2,
.gen-faq h2 {
    font-size: 1.5rem;
    font-weight: 600;
    letter-spacing: -.01em;
    text-align: center;
    margin: 0 0 .5rem;
}
.gen-section-sub {
    text-align: center;
    color: #6b7280;
    font-size: .9375rem;
    line-height: 1.7;
    margin: 0 auto 2rem;
    max-width: 600px;
}
/* One card per topic. Before this the two blocks sat on the same white ground
   separated by margin alone, and because the list rows were themselves white
   cards the whole thing read as a single column of text with two headings
   somewhere in it. A bordered card per topic is the divider the eye was
   looking for, and it is the same card the tool's own sections and the FAQ
   items already use, so the page keeps one vocabulary. */
.gen-content-block {
    background: #fff;
    border: 1px solid #e9ecf0;
    border-radius: 12px;
    padding: 2rem;
}

/* Side by side, and the section widens to 1040px to hold them. Stacked in a
   700px column the two blocks were a single tall ribbon of text down the middle
   of the screen with a field of empty white either side of it — on a page whose
   whole first screen is a dense two-column tool, that reads as the page having
   run out. Two cards in a row restate the tool's own shape, and each column is
   ~470px, which is a *shorter* line than the 700px one they had, so the 65-75
   character measure improves rather than suffers.
   The FAQ below deliberately keeps its own 700px: it is one column of
   accordions, and stretching it to 1040 would only lengthen every line. */
.gen-content > .gen-content-inner {
    max-width: 1040px;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1.5rem;
    /* The blocks are different lengths; stretching keeps the two cards the same
       height so the row reads as a row rather than as two loose panels. */
    align-items: stretch;
}
/* One column again before the pair gets too narrow to read. 860px rather than
   the layout's other breakpoints because that is where ~470px columns stop
   holding a sensible measure, not where anything else on the page changes. */
@media (max-width: 860px) {
    .gen-content > .gen-content-inner {
        max-width: 700px;
        grid-template-columns: 1fr;
    }
}
.gen-content p { color: #374151; line-height: 1.75; margin: 0 0 1rem; }
.gen-content p:last-child { margin-bottom: 0; }
.gen-content-block .gen-list + p { margin-top: 1.25rem; margin-bottom: 0; }

/* The browser's own disc bullet is the giveaway that nobody styled the page.
   The marker is drawn instead, and the rows are separated by a hairline rather
   than by being cards of their own: the block around them is already the card
   (see .gen-content-block), and a white card inside a white card is mush. */
.gen-list { list-style: none; margin: 0; padding: 0; }
.gen-list li {
    position: relative;
    padding: .75rem 0 .75rem 1.5rem;
    border-bottom: 1px solid #f1f3f5;
    color: #374151;
    font-size: .9375rem;
    line-height: 1.65;
}
.gen-list li:last-child { border-bottom: 0; padding-bottom: 0; }
.gen-list li::before {
    content: "";
    position: absolute;
    left: 0;
    /* Aligned to the first line's optical centre rather than the row's, so the
       dot stays put whether the row wraps to one line or three. */
    top: 1.35rem;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--brand);
}
.gen-list li strong { color: #1a1d21; font-weight: 600; }

/* ===== FAQ =====
   <details>/<summary> needs no script, unlike /pricing's Bootstrap accordion. */
/* Matches /pricing's own FAQ block: 4rem of air, grey ground, a 700px column.
   The heading rule lives with the other headings above so the two sections
   cannot drift; there is deliberately no second .gen-faq h2 here. */
.gen-faq { padding: 4rem 0; background: #f6f8fa; }
/* Visually /pricing's Bootstrap accordion, built on <details>/<summary>.
   Every value below is read off that page's own rules rather than guessed:
   the item's 1px #e9ecf0 border and 10px radius, the button's .9375rem/500 in
   #1a1d21 on white, the body's .875rem/#6b7280/1.6, the 1rem × 1.25rem padding
   from --bs-accordion-btn-padding-*, and the chevron and its rotate(-180deg).

   Same look, no accordion library: /pricing loads bootstrap.bundle.min.js and
   says in its own comment that it is the only public page that does. Putting
   that back for a FAQ would spend ~80 KB of blocking JavaScript on the page
   whose LCP the entire organic-search programme was built around — and
   <details> needs none of it, keyboard-works by default, and is open to a
   crawler even when collapsed. */
.gen-faq-item {
    background: #fff;
    border: 1px solid #e9ecf0;
    border-radius: 10px;
    margin-bottom: .5rem;
    overflow: hidden;
}
.gen-faq-item summary {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 1rem 1.25rem;
    font-size: .9375rem;
    font-weight: 500;
    color: #1a1d21;
    cursor: pointer;
    list-style: none;
}
/* Both spellings: WebKit still uses the pseudo-element, everything else honours
   list-style on the summary itself. Without both, the browser's own triangle
   sits next to the chevron drawn below. */
.gen-faq-item summary::-webkit-details-marker { display: none; }
.gen-faq-item summary::after {
    content: "";
    flex-shrink: 0;
    width: 1.25rem;
    height: 1.25rem;
    margin-left: auto;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-size: 1.25rem;
    transition: transform .2s ease-in-out;
}
.gen-faq-item[open] summary::after { transform: rotate(-180deg); }

/* The answer slides open in the same 0.35s ease /pricing's Bootstrap collapse
   uses (.collapsing in public.css) — the two accordions look identical and used
   to behave differently: only the chevron was ever animated here, so the panel
   itself snapped open while the arrow turned, which is what reads as abrupt
   beside the other page.

   ::details-content rather than the obvious .gen-faq-body, because a <details>
   hides its own content the instant `open` is removed — a transition on the body
   would play on the way in and never on the way out. The pseudo-element is the
   one handle the browser gives us on that box, and `content-visibility` with
   `allow-discrete` is what holds it visible for the length of the close.

   Still no JavaScript, and deliberately: these six items share a `name`, so the
   browser closes the previous one itself when another opens. A scripted
   animation would have to intercept both halves of that to avoid the neighbour
   snapping shut mid-slide; a rule keyed on [open] animates the neighbour for
   free, because it is the same state change.

   interpolate-size is what makes `auto` an animatable length. A browser without
   it (or without ::details-content) ignores these rules and opens instantly —
   exactly what it does today, so this is a gain where supported and a no-op
   everywhere else. */
:root { interpolate-size: allow-keywords; }
.gen-faq-item::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size .35s ease, content-visibility .35s allow-discrete;
}
.gen-faq-item[open]::details-content { block-size: auto; }

@media (prefers-reduced-motion: reduce) {
    .gen-faq-item summary::after,
    .gen-faq-item::details-content { transition: none; }
}
.gen-faq-item summary:hover { background: #fbfcfd; }
.gen-faq-item summary:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}
.gen-faq-body {
    padding: 0 1.25rem 1rem;
    font-size: .875rem;
    color: #6b7280;
    line-height: 1.6;
}

@media (prefers-reduced-motion: reduce) {
    .gen-btn,
    .gen-btn-add-row,
    .gen-btn-clear-logo,
    .gen-btn-remove-row { transition: none; }
}
