/* Mega-menu skin — the presentation layer for Components/Layout/SiteHeader.razor.

   Written as hand-authored CSS rather than Tailwind utilities on purpose: the
   public site is served by the prebuilt Tailwind bundle in wwwroot/_next, which
   was compiled against the old React markup. Any class that bundle does not
   already contain — an arbitrary value, an unused shade — silently resolves to
   nothing, so a redesign expressed in new utilities would render half-styled.
   This file is linked from App.razor after the bundle and is unlayered, so it
   also wins over the Tailwind utilities still on these elements.

   Global, not scoped. Every selector is therefore either qnav- prefixed or a
   descendant of one, so nothing here can reach markup outside the header.
   Doubled classes (.qnav-chip.qnav-chip svg) are deliberate: they hold the
   specificity the old [b-xxxxx] scope attribute used to supply.

   Only presentation lives here. The menu tree, the links and the open/close
   behaviour are unchanged. */

/* ---------------------------------------------------------------- palette */

/* Brand colours. Declared on the header rather than :root so they stay this
   component's own, and matched on .qnav-root rather than the bare `header`
   element so an unrelated <header> elsewhere on the site cannot pick them up.
   Every element below is a descendant of this header, including the
   fixed-position panel and the mobile drawer, so they inherit to all of them. */
.qnav-root {
    --qh-magenta: #a03cd2;   /* PANTONE 2592C */
    --qh-indigo: #5d5de2;    /* PANTONE 2725C — primary */
    --qh-yellow: #f6cd46;    /* PANTONE 129C — accent, sparing */
    --qh-gradient: linear-gradient(135deg, #a03cd2 0%, #5d5de2 100%);

    /* Two points inside the signature gradient, named because several steps
       below need a colour rather than the ramp: the violet a third of the way
       along, and the purple two thirds along. */
    --qh-violet: #7a4ddd;
    --qh-purple: #9040d6;

    /* Indigo darkened to 6.5:1 on white: the brand indigo itself is 5:1, fine
       for the 13px link titles but thin for the 11px descriptions. */
    --qh-ink: #4f4fc0;
    --qh-tint: #f2f2fd;
    --qh-edge: #d7d7f8;
    --qh-shadow: 126, 79, 218;   /* mid-ramp, for rgba() elevation */
}

/* The brand palette, and only the brand palette: the signature gradient,
   magenta, indigo, yellow. AccentClass cycles c0-c3 by column position, so a
   four-group flat menu shows all four swatches across the panel.

   Every surface stays light — white panel, near-white row washes, tints mixed
   at a few per cent. The colour is carried by chips, rules and titles, never by
   a filled background.

   Four roles rather than one accent, because yellow cannot do every job the
   purples can — at 1.7:1 on white it is invisible as text and nearly so under
   a white glyph:

     --qnav-accent      solid fill: tab bar, solid chip, spine, shadow tint
     --qnav-accent-bg   same, where a gradient is allowed (defaults to accent)
     --qnav-glyph       accent as a foreground on a light tint (>=3:1)
     --qnav-ink         accent as text on white (>=4.5:1)
     --qnav-solid       the fill a white glyph sits on (>=3:1 against white)
     --qnav-on-accent   foreground on top of that fill
     --qnav-tint        hover fill under a row
     --qnav-wash        a step below the tint, the rows' rest state

   --qnav-wash has to stay below --qnav-tint: the rows cannot sit on the hover
   fill at rest, or hovering one would do nothing. */

.qnav-c0,
.qnav-c1,
.qnav-c2,
.qnav-c3 {
    --qnav-accent-bg: var(--qnav-accent);
    --qnav-glyph: var(--qnav-accent);
    --qnav-on-accent: #fff;

    /* The filled-chip step, matching --qnav-solid on the .qnav-h* ramp so the
       shared row design (see .qnav-item) resolves the same custom property in
       either layout. --qnav-ink is already this accent taken to 4.5:1 on white,
       which is exactly what a white glyph on the accent needs. */
    --qnav-solid: var(--qnav-ink);
}

/* Signature gradient — the swatch's own 135deg, so the solid chip and the tab
   bar carry the real brand ramp. --qnav-accent is its midpoint, for the slots
   that cannot take a gradient (box-shadow colour, the flat spine). */
.qnav-c0 {
    --qnav-accent: var(--qh-violet);
    --qnav-accent-bg: var(--qh-gradient);
    --qnav-ink: #5b3fc6;
    --qnav-tint: #f3f0fd;
    --qnav-wash: #fbfaff;
    --qnav-edge: #dcd4f8;
}

.qnav-c1 {
    --qnav-accent: var(--qh-magenta);
    --qnav-ink: #8833b3;
    --qnav-tint: #f7effb;
    --qnav-wash: #fdfaff;
    --qnav-edge: #e7cef4;
}

.qnav-c2 {
    --qnav-accent: var(--qh-indigo);
    --qnav-ink: #4f4fc0;
    --qnav-tint: #f2f2fd;
    --qnav-wash: #fafaff;
    --qnav-edge: #d7d7f8;
}

/* Yellow is the one column that needs all four roles to differ. The bar and
   the chip stay the true PANTONE 129C; the title drops to a dark amber and
   the chip's glyph inverts to near-black, which is the only way this column
   is legible rather than merely yellow. */
.qnav-c3 {
    --qnav-accent: var(--qh-yellow);
    --qnav-glyph: #a07c00;
    --qnav-ink: #8a6a00;
    --qnav-tint: #fef8e3;
    --qnav-wash: #fffdf3;
    --qnav-edge: #fceebe;
    --qnav-on-accent: #4a3800;
}

/* The grouped (Products, Solutions) panel runs the same four swatches as the
   flat panel above, in the palette's own order: signature gradient, magenta,
   indigo, yellow. The two panel types finally agree — a visitor moving from
   Products to Solutions sees one system rather than two.

   It used to be a five-step hue ramp — indigo, violet, pink, green, amber — and
   the green and the amber are not brand colours at all.

   Unlike the .qnav-c* accents above, which recolour a whole card, a step here
   mostly paints an icon chip: a tint behind a glyph, so --qnav-glyph only has to
   clear 3:1 for a 17px stroke. --qnav-solid is the exception and the reason each
   step needs two values — it fills the heading chip and colours the heading
   title, so it has to clear 4.5:1 on white.

   HueClass applies the swatch by column position to the heading chips; the
   module chips inside a column take their column's step rather than their own
   row's — see the capture on .qnav-column. */

/* Signature gradient. The heading chip takes the real 135deg ramp (see the
   override below); the rows and the divider follow its midpoint violet, which
   is the one colour in the column a hairline or a 17px glyph can actually be. */
.qnav-h0 {
    --qnav-tint: #f3f0fd;
    --qnav-glyph: var(--qh-violet);
    --qnav-solid: #5b3fc6;
    --qnav-edge: #dcd4f8;
}

.qnav-h1 {
    --qnav-tint: #f9effc;
    --qnav-glyph: var(--qh-magenta);
    --qnav-solid: #8833b3;
    --qnav-edge: #ecd3f6;
}

.qnav-h2 {
    --qnav-tint: #eeeffe;
    --qnav-glyph: var(--qh-indigo);
    --qnav-solid: #4f4fc0;
    --qnav-edge: #d9dafa;
}

/* Yellow, the swatch that cannot play any of these roles at face value: at
   1.7:1 on white it is invisible as a title and as a 17px glyph. The column runs
   on dark amber instead, and the true PANTONE 129C appears in exactly one place
   — the heading chip below — which is what "sparing" means here. */
.qnav-h3 {
    --qnav-tint: #fef8e3;
    --qnav-glyph: #a07c00;
    --qnav-solid: #8a6a00;
    --qnav-edge: #fceebe;
}

/* Only reached by a fifth group: the gradient's midpoint, which is the one
   further point on the brand ramp that is not already a column above. */
.qnav-h4 {
    --qnav-tint: #f6ecfc;
    --qnav-glyph: var(--qh-purple);
    --qnav-solid: #7e35bd;
    --qnav-edge: #e6d2f6;
}

/* The two heading chips whose fill is not simply their own two steps.

   h0 carries the signature gradient itself rather than a ramp built from the
   column's steps — this and the panel's bottom edge are the only places the
   whole 135deg swatch runs.

   h3 stays true yellow, with the glyph inverted to near-black: white on 129C is
   1.7:1, so the default white glyph would leave a bright empty square. The
   shadow is mixed from the yellow for the same reason the others are. */
.qnav-h0 .qnav-chip-solid {
    background: var(--qh-gradient);
}

.qnav-h3 .qnav-chip-solid {
    background: linear-gradient(135deg, var(--qh-yellow) 0%, #edb92f 100%);
    color: #4a3800;
    box-shadow: 0 8px 16px -8px rgba(214, 165, 32, .6);
}

/* --------------------------------------------------------- top-level tabs */

.qnav-bar {
    align-self: stretch;
}

.qnav-tab {
    position: relative;
    align-self: stretch;
    display: flex;
    align-items: center;
}

.qnav-trigger {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.6875rem 1rem;
    border-radius: 0.625rem;
    font-size:1rem;
    font-weight: 600;
    color: #3f4658;
    white-space: nowrap;
    cursor: pointer;
    background: transparent;
    transition: color .18s ease, background-color .18s ease;
}

.qnav-trigger:hover {
    color: var(--qh-ink);
    background: var(--qh-tint);
}

/* Open tab: tinted panel plus the accent rule along its bottom edge. */
.qnav-trigger.is-open,
.qnav-trigger.is-open:hover {
    color: var(--qh-ink);
    background: var(--qh-tint);
}

/* The rule is on every trigger now, not just the open one, so it can grow
   rather than appear. Drawn at zero width and scaled out from the centre: a
   3px bar that pops in at full length reads as a state change, one that opens
   under the label reads as the tab reaching for the panel below it. */
.qnav-trigger::after {
    content: "";
    position: absolute;
    left: 0.75rem;
    right: 0.75rem;
    bottom: 0;
    height: 3px;
    border-radius: 3px 3px 0 0;
    /* 90deg rather than the signature 135deg: on a 3px rule a diagonal ramp
       resolves to a single flat colour. */
    background: linear-gradient(90deg, var(--qh-magenta), var(--qh-indigo));
    transform: scaleX(0);
    transition: transform .2s ease, opacity .2s ease;
}

/* Hover shows the same bar at half strength — the tab acknowledging the
   pointer without claiming to be the open one. Pricing has no panel to open,
   so this is the only state it ever gets. */
.qnav-trigger:hover::after {
    opacity: .45;
    transform: scaleX(1);
}

.qnav-trigger.is-open::after,
.qnav-trigger.is-open:hover::after {
    opacity: 1;
    transform: scaleX(1);
}

/* The tab is the panel's own handle, so a caret ring around it would sit
   between the label and the bar it draws. The bar plus the tint is the focus
   state; the ring only fills in where those are not enough. */
.qnav-trigger:focus-visible {
    outline: 2px solid var(--qh-indigo);
    outline-offset: -2px;
    color: var(--qh-ink);
    background: var(--qh-tint);
}

.qnav-trigger:focus-visible::after {
    opacity: 1;
    transform: scaleX(1);
}

.qnav-chevron {
    width: 0.875rem;
    height: 0.875rem;
    opacity: .65;
    transition: transform .2s ease, opacity .2s ease;
}

.qnav-trigger:hover .qnav-chevron {
    opacity: .85;
}

.qnav-trigger.is-open .qnav-chevron {
    transform: rotate(180deg);
    opacity: 1;
}

/* -------------------------------------------------------- header buttons */

.qnav-login {
    padding: 0.5rem 1.1875rem;
    border: 1px solid #e3e6ef;
    border-radius: 0.625rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #2b3040;
    background: #fff;
    text-decoration: none;
    transition: border-color .18s ease, color .18s ease, box-shadow .18s ease;
}

.qnav-login:hover {
    color: var(--qh-ink);
    border-color: #c3c3ef;
    box-shadow: 0 4px 12px -6px rgba(var(--qh-shadow), .35);
}

.qnav-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5625rem 1.125rem;
    border-radius: 0.625rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #fff;
    text-decoration: none;
    background: var(--qh-gradient);
    box-shadow: 0 8px 18px -8px rgba(var(--qh-shadow), .6);
    transition: box-shadow .2s ease, transform .2s ease;
}

.qnav-cta:hover {
    box-shadow: 0 12px 24px -8px rgba(var(--qh-shadow), .7);
    transform: translateY(-1px);
}

/* One of only two places the yellow appears — a 16px glyph on the gradient,
   which is about as sparing as the accent gets while still being present. */
.qnav-cta svg {
    width: 1rem;
    height: 1rem;
    color: var(--qh-yellow);
}

/* ---------------------------------------------------------------- panel */

/* Full-bleed band flush under the header — 81px is the md:h-20 row plus its
   1px border. The tinted fill spans edge to edge; only the content inside is
   constrained, so the panel still reads as part of the header bar. */
.qnav-shell {
    position: fixed;
    top: 81px;
    left: 0;
    right: 0;
    z-index: 50;
}

.qnav-panel {
    position: relative;
    width: 100%;
    overflow: hidden;
    /* Plain white: the columns are separated by rules rather than raised as
       cards, so there is nothing for a tinted backdrop to lift. */
    background: #fff;
    /* Two-stop shadow rather than one: the tight stop draws the seam where the
       panel meets the page, the wide one is the weight that makes it read as a
       sheet in front of the content rather than a band drawn on it. */
    box-shadow: 0 1px 0 #ece8f7,
                0 24px 48px -20px rgba(28, 26, 74, .3);
    animation: qnav-drop .18s ease-out;
}

/* The brand ramp closing the bottom edge, in place of the flat lilac border it
   replaces. Full-bleed like the panel, and the one place the whole 135deg
   gradient runs at viewport width — the tab above draws a 90deg slice of the
   same ramp, so the open tab and the panel edge are visibly one mark. Held at
   half strength so it edges the light panel rather than boxing it in. */
.qnav-panel::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--qh-gradient);
    opacity: .5;
}

@keyframes qnav-drop {
    from {
        opacity: 0;
        transform: translateY(-6px);
    }
}

.qnav-body {
    position: relative;
    width: 100%;
    max-width: 1720px;
    margin: 0 auto;
    padding: 1.5rem 2rem 1.75rem;
    max-height: calc(100vh - 100px);
    overflow-y: auto;
    /* A short laptop is exactly where the four long columns overflow, and the
       platform scrollbar is a grey slab down the middle of a white panel. Thin
       and brand-tinted, and gutter-stable so the columns do not shift by 15px
       between a menu that scrolls and one that does not. */
    scrollbar-width: thin;
    scrollbar-color: var(--qh-edge) transparent;
    scrollbar-gutter: stable;
}

.qnav-body::-webkit-scrollbar {
    width: 8px;
}

.qnav-body::-webkit-scrollbar-track {
    background: transparent;
}

.qnav-body::-webkit-scrollbar-thumb {
    border-radius: 999px;
    background: var(--qh-edge);
}

.qnav-body::-webkit-scrollbar-thumb:hover {
    background: #c3c3ef;
}

/* ---------------------------------------------------------------- columns */

/* Always four tracks, as in the reference. Fixed rather than auto-fit on
   purpose: a menu with only two or three groups keeps them at the same width
   the four-group Products menu gets and leaves the remaining tracks empty,
   instead of stretching two columns of 13px rows across half the viewport. */
/* No gap and stretched tracks: the columns are divided by a rule on each one's
   leading edge, and a rule only reads as a divider if it runs the full height
   of the panel — which it cannot do if the tracks are only as tall as their
   own content. */
.qnav-columns {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    align-items: stretch;
}

/* The panel only ever opens at md and up, but four columns at 768px would be
   170px wide — too narrow for an icon, a title and a description side by side. */
@media (max-width: 1279px) {
    .qnav-columns {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Two tracks put columns 3 and 4 on a second row, where the third column's
       divider is no longer between anything — it lands hard against the left
       edge of the panel. The rule belongs to the track boundary, not to the
       source order, so it comes off every column that starts a row. */
    .qnav-column:nth-child(odd)::before {
        display: none;
    }

    /* Rows wrapping onto a second line need something holding them apart, and
       the divider that used to do it is gone above. */
    .qnav-column:nth-child(n + 3) {
        margin-top: 1.25rem;
        padding-top: 1.25rem;
        border-top: 1px solid #eef0f6;
    }
}

/* The divider goes on the leading edge, so the first column has none and the
   panel keeps a clean left margin. */
.qnav-column {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 0 1.5rem 0.75rem;

    /* Snapshot of this column's own hue, under names nothing further down
       redefines. var() resolves where it is declared, so these three compute
       here against the column's .qnav-h class and inherit as finished colours —
       a row re-declaring --qnav-tint on itself cannot reach back and change
       them.

       That is what makes a column one colour. The rows still carry a per-row
       .qnav-h class from HueClass, and the panel used to let each row paint its
       own chip: sixteen chips in five hues, arranged in neither rows nor
       columns of colour, so the eye found no pattern and read it as noise. A
       column that is one hue from its heading down is a group you can see the
       edges of. */
    --qnav-col-tint: var(--qnav-tint);
    --qnav-col-glyph: var(--qnav-glyph);
    --qnav-col-solid: var(--qnav-solid);
    --qnav-col-edge: var(--qnav-edge);
}

/* A gradient hairline instead of a border, and in the hue of the column it
   opens rather than in grey. Three of these run down the panel and they are the
   only full-height marks in it, so leaving them neutral wasted the one element
   that could tell a visitor how far the colour they are following extends.

   The rule has to run the full height to read as a divider, but a solid line
   doing that ends in two hard ticks against the panel's padding — six marks
   with nothing to align to. Fading it out over the first and last eighth keeps
   the division and loses the ticks; at these hues the fade also keeps a
   saturated 300px line from reading as a border on a box. */
.qnav-column + .qnav-column::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 1px;
    background: linear-gradient(180deg,
                                transparent 0,
                                var(--qnav-col-edge) 10%,
                                var(--qnav-col-glyph) 45%,
                                var(--qnav-col-edge) 80%,
                                transparent 100%);
    opacity: .55;
}

/* The panel drops as one block; the columns settle into it left to right a
   frame apart. Staggered by column rather than by row — sixteen rows each
   arriving on their own beat is a performance, four columns is just the panel
   filling in. The whole run is under a tenth of a second, so a visitor who
   already knows which tab they want never sees it finish. */
.qnav-column {
    animation: qnav-column-in .22s ease-out both;
}

.qnav-column:nth-child(2) {
    animation-delay: .03s;
}

.qnav-column:nth-child(3) {
    animation-delay: .06s;
}

.qnav-column:nth-child(4) {
    animation-delay: .09s;
}

@keyframes qnav-column-in {
    from {
        opacity: 0;
        transform: translateY(4px);
    }
}

/* Top-aligned, not centred: the heading is two lines of type beside a 46px
   chip, and centring it hangs the chip halfway down the description instead of
   squaring it against the title.

   The hairline is back, now that the heading is a block rather than one line —
   it closes the group statement off from the modules that answer it, which is
   the one horizontal division in this panel that separates two different kinds
   of thing rather than just two rows. */
.qnav-column-head {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    padding: 0 0 1rem;
    border-bottom: 1px solid #e9ebf3;
}

/* The heading title takes the column's hue, which the module titles below it
   never do — that difference is what makes it read as a heading rather than a
   bigger first row. Safe here where it is not on the rows: --qnav-col-solid is
   the step of the ramp that clears 4.5:1 on white, so green and amber hold up
   the same as indigo does. */
.qnav-column-title {
    display: block;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: -.01em;
    color: var(--qnav-col-solid, var(--qh-ink));
}

/* What the group is for, in one line the modules under it cannot say
   individually. Deliberately the same size as the module descriptions rather
   than a step up: the two levels are already told apart by the coloured title
   above this one and the chip beside it, and scaling this up as well would
   give a column two competing paragraphs. Grey, and it sits above the rule, so
   it reads as part of the heading rather than as a first row without an icon. */
.qnav-column-desc {
    display: block;
    margin-top: 0.3125rem;
    font-size: 0.875rem;
    line-height: 1.5;
    color: #6b7280;
}

/* Filled, not tinted — the one solid block of colour in the panel, and the
   thing a visitor's eye lands on first in each column. A heading and its rows
   now differ by fill as well as by size: sixteen tinted squares with one
   slightly larger tinted square on top of them made the heading look like the
   first item of its own list.

   The fill is a 135deg ramp between the hue's two steps rather than one flat
   colour, so it carries the same diagonal the brand gradient does at a size
   where a diagonal still resolves. */
.qnav-chip-solid {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 2.875rem;
    height: 2.875rem;
    border-radius: 0.875rem;
    background: linear-gradient(135deg,
                                var(--qnav-glyph) 0%,
                                var(--qnav-solid) 100%);
    color: #fff;
    /* Cast in the chip's own hue. A neutral drop shadow under a saturated
       block reads as grey haze; this reads as the colour sitting on the page.
       color-mix is progressive — a browser without it simply draws no shadow,
       and the chip is a filled block either way. */
    box-shadow: 0 8px 16px -8px color-mix(in srgb, var(--qnav-solid) 55%, transparent);
}

.qnav-chip-solid.qnav-chip-solid svg {
    width: 1.375rem;
    height: 1.375rem;
}

/* 36px against the heading's 46px: the gap between the two sizes is what ranks
   them, and closing it left the heading looking like a row that had been
   nudged. The col-* fallbacks are how one chip serves both layouts — inside a
   .qnav-column they resolve to the column's captured hue, and in a flat menu,
   where no column exists, they fall through to the accent class on the row
   itself. */
.qnav-chip {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.6875rem;
    background: var(--qnav-col-tint, var(--qnav-tint));
    color: var(--qnav-col-glyph, var(--qnav-glyph));
    /* Hairline in the chip's own hue, drawn inside so it costs no layout. At
       rest it is nearly invisible against the tint; once the row hover fills
       the chip it is the only thing keeping the glyph from floating. */
    box-shadow: inset 0 0 0 1px var(--qnav-col-edge, var(--qnav-edge, transparent));
    transition: background-color .18s ease, box-shadow .18s ease,
                color .18s ease, transform .18s ease;
}

.qnav-chip.qnav-chip svg {
    width: 1.0625rem;
    height: 1.0625rem;
}

/* ------------------------------------------------------------------ items */

.qnav-list {
    display: flex;
    flex-direction: column;
    /* Tighter than the old boxed rows needed: with the borders gone (see
       below) the rows are separated by whitespace alone, and half a rem of it
       between borderless rows reads as four loose items rather than one list.
       The hover fill is what marks the row edges now, so it has to be able to
       reach its neighbours. */
    gap: 0.25rem;
    padding: 1.125rem 0 0;
    /* Pull the rows out to the column's padding edge so the hover fill spans
       the full track instead of leaving a stripe of white down both sides. */
    margin: 0 -0.625rem;
}

/* One row design for both layouts. The flat menus — Resources, Solutions,
   Company — used to be a grid of bordered cards, which meant the site had two
   mega-menus that shared a palette and nothing else: a visitor moving from
   Products to Resources landed on a different component. The row below is the
   Products row, and the two layouts now differ only in how they arrange it,
   which is the one thing their content actually forces.

   Borderless and unfilled at rest. In a column that already sits between two
   hairline rules, boxing every row framed the panel three deep — a rule, a card
   border, and the chip's own edge — and the wash under each row turned four
   columns into sixteen faintly tinted blocks. The row has one job at rest:
   carry a chip, a title and a description. Everything else arrives on hover.

   Top-aligned, because a three-line description would otherwise centre the chip
   against the middle of the paragraph instead of the title. */
.qnav-item {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    padding: 0.625rem 0.625rem 0.625rem 0.75rem;
    border: 1px solid transparent;
    border-radius: 0.625rem;
    background: transparent;
    text-decoration: none;
    transition: border-color .18s ease, background-color .18s ease,
                box-shadow .18s ease, transform .18s ease;
}

/* Nudged down a hair so a 36px chip squares against a 15px title rather than
   against the top of its line box. */
.qnav-item .qnav-chip {
    margin-top: 0.0625rem;
}

/* The spine replaces the old translateX nudge. Sliding the whole row sideways
   moved the chip out of the column's icon rail, so four hovered rows never
   lined up with the twelve resting ones; a mark that grows in place says the
   same thing without disturbing the grid. Scaled from the centre, so it opens
   out of the row's midline rather than dropping in from the top. */
.qnav-item::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.4375rem;
    bottom: 0.4375rem;
    width: 2px;
    border-radius: 999px;
    background: var(--qnav-col-glyph, var(--qnav-glyph));
    opacity: 0;
    transform: scaleY(.35);
    transition: opacity .18s ease, transform .18s ease;
}

.qnav-item:hover::before,
.qnav-item:focus-visible::before {
    opacity: 1;
    transform: none;
}

/* Flat fill, no lift: these rows sit close together, and a drop shadow on one
   would fall across the two below it. */
.qnav-item:hover,
.qnav-item:focus-visible {
    background: var(--qnav-col-tint, var(--qnav-tint));
    border-color: transparent;
    box-shadow: none;
    transform: none;
}

/* The chip inverts on hover — tint fill under a coloured glyph becomes the
   solid fill under a white one, which is the heading chip's treatment arriving
   on the row being read. It is the strongest hover state in the panel and only
   ever appears once at a time. */
.qnav-item:hover .qnav-chip,
.qnav-item:focus-visible .qnav-chip {
    /* Flat colour, not the heading's gradient: a gradient is a background-image
       and cannot be transitioned, so it would snap in while the row tint behind
       it faded. One colour and the whole state moves together.

       The solid step rather than the glyph step, because this is now white on
       the hue rather than the hue on white — the amber and green glyph values
       carry a 19px stroke at 3:1 against a tint, but not a white one. */
    background: var(--qnav-col-solid, var(--qnav-solid));
    color: #fff;
    box-shadow: 0 6px 12px -6px color-mix(in srgb,
                                          var(--qnav-col-solid, var(--qnav-solid)) 55%,
                                          transparent);
    transform: scale(1.04);
}

/* Keyboard focus draws the hover state above, which is fill only — fine for a
   pointer, not enough to find a caret with. The ring is the column's own hue,
   so tabbing down a column tracks the same colour its chips do. */
.qnav-item:focus-visible {
    outline: 2px solid var(--qnav-col-glyph, var(--qnav-glyph));
    outline-offset: -2px;
}

.qnav-item-text {
    min-width: 0;
    flex: 1 1 auto;
}

/* Sits over two or three lines of description and has to hold rank against
   them, which is why it is heavier than a card title would need to be. */
.qnav-item-title {
    display: block;
    font-size: .85rem;
    font-weight: 650;
    line-height: 1.3;
    letter-spacing: -.005em;
    color: #1f2533;
    transition: color .18s ease;
}

/* The row hue is an icon colour, never a text colour: three of the five steps
   (green, amber, pink) sit under 4.5:1 on their own tint at 15px. The solid
   step is each hue taken down until it clears that bar, so the hovered title
   shifts by the same amount in every column. */
.qnav-item:hover .qnav-item-title,
.qnav-item:focus-visible .qnav-item-title {
    color: var(--qnav-col-solid, var(--qnav-solid, var(--qh-ink)));
}

/* A module name on its own — "Payroll", "Leave", "People" — tells a buyer
   nothing, so every row prints menu_desc under its title. 1.55 rather than a
   tighter leading because the difference between two lines and three is read
   as one block of text, and at 13px a tight leading closes it up. */
.qnav-item-desc {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.8rem;
    line-height: 1.55;
    color: #6b7280;
    transition: color .18s ease;
}

/* Grey enough to sit behind the title at rest, which is right for sixteen
   resting rows and a shade too quiet for the one being read. */
.qnav-item:hover .qnav-item-desc,
.qnav-item:focus-visible .qnav-item-desc {
    color: #5b6479;
}

/* Seventeen chevrons standing in a four-column panel is chrome this layout
   cannot afford, which is why they used to be hidden outright. One chevron, on
   the row under the pointer, is not chrome — it is the row confirming it is a
   link. So it is drawn, but only for the hovered or focused row, sliding in
   from where the text ends. Space is reserved at rest, so nothing reflows. */
.qnav-item-arrow {
    flex: none;
    align-self: center;
    width: 0.875rem;
    height: 0.875rem;
    color: var(--qnav-col-glyph, var(--qnav-glyph));
    opacity: 0;
    transform: translateX(-0.25rem);
    transition: opacity .18s ease, transform .18s ease, color .18s ease;
}

.qnav-item:hover .qnav-item-arrow,
.qnav-item:focus-visible .qnav-item-arrow {
    opacity: 1;
    transform: none;
}

/* --------------------------------------- flat panel (menus with no groups) */

.qnav-flat {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media (max-width: 1279px) {
    .qnav-flat {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Nothing left to say about the row itself — it is the same row the grouped
   panel draws. What is left is the arrangement: four tracks with a wide column
   gap and almost no row gap, so a menu of seven entries reads down its columns
   the way Products does rather than across as a grid of tiles.

   AccentClass cycles four accents by source order and the grid fills row-major
   across four tracks, so index % 4 lands the same accent in the same column —
   Products' one-hue-per-column, arrived at from the other direction. */
.qnav-flat {
    column-gap: 2.5rem;
    row-gap: 0.25rem;
}

/* Grid items stretch by default, which on a row that is one line tall next to
   one that is four stretches the short row's hover fill to match. */
.qnav-flat .qnav-item {
    align-self: start;
}

/* ------------------------------------------------------------ illustration */

/* ------------------------------------------------------------ mobile menu */

/* The drawer's closed state, declared unconditionally so it cannot fail open at
   any width. Everything that follows it is wrapped in the md breakpoint's own
   boundary (48rem, the width Tailwind's md: uses): this file is unlayered and the
   bundle's utilities sit in @layer utilities, so a bare .qnav-drawer rule outranks
   the md:hidden on the same element, and a stray `display` would put the drawer on
   the desktop header. Inside the media query it cannot, whatever it declares.

   The overflow is set here rather than by an overflow-hidden class in the markup
   because the bundle declares that utility twice and the second copy is
   `overflow: hidden !important` — an element carrying it can never be given a
   scrollbar again by any rule, at any specificity, inline styles included. */
.qnav-drawer {
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    transition: max-height .3s ease-in-out, opacity .3s ease-in-out;
}

@media (max-width: 47.9375rem) {

    /* The hamburger, squared up to the 44px minimum. p-2 around a 24px glyph is
       40px, and this button is the entire mobile menu's handle. */
    .qnav-burger {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
    }

    /* Open is bounded by the viewport and scrolls inside itself, which is the
       whole fix: the drawer lives inside a `sticky top-0` header, so its lower
       half is not merely below the fold — it is unreachable. The header pins at
       y=0 the instant the page moves, and `overflow: hidden` gave the drawer no
       scroll of its own, so on a 375x667 phone expanding Products clipped 596px:
       nine of the seventeen module links, plus Login and Start Free Trial, with
       no gesture that could bring them back.

       dvh, not vh: on a phone `100vh` is the height with the browser chrome
       retracted, so a vh-sized drawer runs its last rows underneath the URL bar
       exactly when the bar is showing. The vh line above it is the fallback for
       engines without dvh, where being 60-odd px too tall is the lesser fault
       now that the drawer scrolls.

       4rem is the mobile header row (h-16). The old value subtracted 80px, the
       md:h-20 row, which is not the row height at any width this drawer is
       visible at. */
    .qnav-drawer.is-open {
        max-height: calc(100vh - 4rem);
        max-height: calc(100dvh - 4rem);
        opacity: 1;
        /* Only the y axis opens. The x stays clipped, so a long module name can
           never hand a phone a sideways scroll. */
        overflow-x: hidden;
        overflow-y: auto;
        /* Reaching the end of the menu must not start scrolling the page behind
           it — on a drawer this long a thumb hits that boundary constantly. */
        overscroll-behavior: contain;
        -webkit-overflow-scrolling: touch;
        /* Same thin brand-tinted bar the desktop panel uses, for the phones that
           draw a classic scrollbar rather than an overlay one. */
        scrollbar-width: thin;
        scrollbar-color: var(--qh-edge) transparent;
        /* The drawer now ends exactly at the bottom of the viewport, which on a
           phone with a home indicator is underneath it. Start Free Trial is the
           last row in the list and would be the one sitting under the bar.
           env() is 0 everywhere else, so this costs nothing on a phone with a
           bezel. */
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    .qnav-drawer::-webkit-scrollbar {
        width: 6px;
    }

    .qnav-drawer::-webkit-scrollbar-track {
        background: transparent;
    }

    .qnav-drawer::-webkit-scrollbar-thumb {
        border-radius: 999px;
        background: var(--qh-edge);
    }

    /* A section heading is a tap target in a stack of a dozen, so it gets the
       same 44px floor the burger does — 0.6875rem on a 14px line lands at 43. */
    .qnav-m-trigger {
        min-height: 44px;
    }

    /* At 320px "Managed Payroll Services" is nearly the full row. The label wraps
       rather than squeezing the chevron out of shape, and the chevron holds its
       size. */
    .qnav-m-trigger > span {
        min-width: 0;
    }

    .qnav-m-trigger .qnav-chevron {
        flex: none;
    }

    /* The desktop mega panel is `position: fixed; top: 81px` and is opened by
       hover, which a touch screen never sends — but _openMenu survives a resize.
       Open a menu on a laptop, narrow the window or rotate a tablet, and the
       panel is left covering the page below a header that no longer has the tab
       that would close it. It has no business existing at this width. */
    .qnav-shell {
        display: none;
    }
}

.qnav-m-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0.6875rem 1rem;
    border-radius: 0.625rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: #3f4658;
    background: transparent;
    text-decoration: none;
    transition: color .18s ease, background-color .18s ease;
}

.qnav-m-trigger:hover,
.qnav-m-trigger:active,
.qnav-m-trigger.is-open {
    color: var(--qh-ink);
    background: var(--qh-tint);
}

/* The open section and the eleven closed ones look alike on a phone, where the
   expanded children scroll past the trigger that opened them. The bar marks
   which one is open at the point a thumb is most likely to be looking — the
   left edge, at the top of the run of children below it. */
.qnav-m-trigger {
    position: relative;
}

.qnav-m-trigger.is-open::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.4375rem;
    bottom: 0.4375rem;
    width: 3px;
    border-radius: 999px;
    background: var(--qh-gradient);
}

.qnav-m-trigger:focus-visible {
    outline: 2px solid var(--qh-indigo);
    outline-offset: -2px;
}

/* The children of an open section, reached through the trigger rather than by
   a class of their own — the markup wraps them in a bare Tailwind div. Anchored
   to .qnav-m-trigger.is-open, so it still cannot match anything outside this
   header even though it is a sibling selector rather than a descendant one.

   A rail down the left, continuing the bar on the trigger above: on a phone the
   whole drawer is one flat column of text, and the rail is what says these
   thirteen rows hang off that one heading rather than following it. */
.qnav-m-trigger.is-open + div {
    position: relative;
    /* 1rem is the trigger's own text inset, so the rail hangs directly under
       the first letter of the heading it belongs to. */
    margin: 0.125rem 0 0.5rem 1rem;
    border-left: 1px solid var(--qh-edge);
    animation: qnav-m-open .2s ease-out;
}

@keyframes qnav-m-open {
    from {
        opacity: 0;
        transform: translateY(-4px);
    }
}

/* Everything inside the rail re-indents against it rather than against the
   drawer, otherwise the rail's 1rem stacks on the 1rem these already carry and
   the children sit a third of the way across a phone screen. */
.qnav-m-trigger.is-open + div .qnav-m-group {
    padding-left: 0.875rem;
}

.qnav-m-trigger.is-open + div .qnav-m-link {
    padding-left: 0.875rem;
}

/* The rail is the leading mark now, so the per-row dot is redundant — two
   marks on the same 8px of a phone screen, one of them repeated thirteen
   times. It comes back on hover as the row's own tick. */
.qnav-m-trigger.is-open + div .qnav-m-link::before {
    left: -1px;
    top: 0.5rem;
    bottom: 0.5rem;
    width: 2px;
    height: auto;
    margin-top: 0;
    border-radius: 999px;
    background: transparent;
    transform: none;
}

.qnav-m-trigger.is-open + div .qnav-m-link:hover::before,
.qnav-m-trigger.is-open + div .qnav-m-link:focus-visible::before,
.qnav-m-trigger.is-open + div .qnav-m-link:active::before {
    background: var(--qh-indigo);
    transform: none;
}

.qnav-m-group {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.875rem 1rem 0.375rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--qnav-ink);
}

.qnav-m-group::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--qnav-edge);
}

.qnav-m-link {
    position: relative;
    display: block;
    /* 0.5625rem top and bottom on a 13px line puts the row just over 44px with
       the gap — the smallest target a thumb can hit reliably, and these sit in
       a stack of a dozen. */
    padding: 0.5625rem 1rem 0.5625rem 1.75rem;
    border-radius: 0.5rem;
    font-size: 0.8125rem;
    color: #5b6479;
    text-decoration: none;
    transition: color .18s ease, background-color .18s ease;
}

/* Marker dot in place of the desktop card's icon chip — the mobile list has
   no room for one, but without any leading mark the child rows read as an
   indented paragraph rather than a set of links. */
.qnav-m-link::before {
    content: "";
    position: absolute;
    left: 1.0625rem;
    top: 50%;
    width: 4px;
    height: 4px;
    margin-top: -2px;
    border-radius: 999px;
    background: #d3d7e2;
    transition: background-color .18s ease, transform .18s ease;
}

/* A phone has no hover, so :active carries the same weight here that :hover
   does on the desktop panel — it is the only feedback between the tap and the
   next page painting. */
.qnav-m-link:hover,
.qnav-m-link:focus-visible,
.qnav-m-link:active {
    color: var(--qh-ink);
    background: var(--qh-tint);
}

.qnav-m-link:hover::before,
.qnav-m-link:focus-visible::before,
.qnav-m-link:active::before {
    background: var(--qh-indigo);
    transform: scale(1.5);
}

.qnav-m-link:focus-visible {
    outline: 2px solid var(--qh-indigo);
    outline-offset: -2px;
}
/* ------------------------------------------------------------- motion */

/* The panel's motion is decoration — the drop, the column stagger, the spine
   growing, the chevron sliding in. None of it carries meaning the colour and
   the fill do not already carry, so it all comes off for a visitor who asked
   for less of it. The hover states themselves stay; only the movement goes. */
@media (prefers-reduced-motion: reduce) {
    .qnav-panel,
    .qnav-column,
    .qnav-m-trigger.is-open + div {
        animation: none;
    }

    .qnav-item::before,
    .qnav-item-arrow,
    .qnav-chip,
    .qnav-m-link::before {
        transition-property: opacity, background-color, color;
        transform: none;
    }

    /* The tab rule keeps its state, drawn rather than animated — the bar fades
       in at full width instead of opening out from the centre. */
    .qnav-trigger::after {
        transition-property: opacity;
        transform: scaleX(1);
        opacity: 0;
    }
}

.bg-indigo-800 {
    background-color: var(--color-indigo-700);
}