/*
 * Trezo Lens components.
 *
 * Sits on top of Bootstrap and of tokens.css, which must load first. Everything here reads a token
 * and never a literal colour, so a palette change happens in one file.
 *
 * What this file replaced was 326 lines inherited from a different project: a login split card, a
 * captcha filter, gridview sort arrows and a gradient hero, of which 20 of its 25 class selectors
 * were used by nothing in views/. Dead CSS never fails anything, which is why it survived every
 * commit since the skeleton.
 */

/* ---------------------------------------------------------------- shell */

body {
    background-color: var(--lens-surface);
    color: var(--lens-text);
    font-family: var(--lens-font-ui);
    -webkit-font-smoothing: antialiased;
}

main > .container {
    padding-top: var(--lens-space-7);
    padding-bottom: var(--lens-space-7);
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

.lens-page {
    flex: 1;
}

/* A measured value reads as an instrument reading rather than as a marketing figure. */
.lens-mono {
    font-family: var(--lens-font-mono);
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------- mark */

.lens-mark-trezo,
.lens-mark-lens {
    font-family: var(--lens-font-display);
    letter-spacing: -0.02em;
}

.lens-mark-trezo {
    font-weight: 400;
    color: var(--lens-text-muted);
}

.lens-mark-lens {
    font-weight: 700;
    color: var(--lens-text);
}

/* The accent lives between the two words, which is where the parent brand ends and the product
   begins. */
.lens-mark-dot {
    display: inline-block;
    width: 0.3rem;
    height: 0.3rem;
    margin: 0 0.3rem;
    border-radius: 50%;
    background-color: var(--lens-accent);
    vertical-align: middle;
}

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

.lens-navbar {
    background-color: var(--lens-surface-raised);
    border-bottom: var(--lens-border-width) solid var(--lens-border);
    padding-block: var(--lens-space-3);
}

.lens-navbar .navbar-brand {
    font-size: 1.15rem;
    display: inline-flex;
    align-items: center;
}

.lens-navbar .nav-link {
    color: var(--lens-text-muted);
    font-size: 0.9375rem;
    padding-inline: var(--lens-space-3);
}

.lens-navbar .nav-link:hover,
.lens-navbar .nav-link:focus-visible {
    color: var(--lens-text);
}

/* The tool currently open. Bootstrap's Nav marks it in the markup on its own, reading the route
   from the controller; without this rule that mark is invisible and the header only ever says
   where a visitor can go, never where they are.

   The underline is drawn with box-shadow rather than border-bottom so the tab does not change
   height when it becomes active, which would shift every other tab by a pixel as you navigate. */
.lens-navbar .nav-link.active {
    color: var(--lens-accent);
    font-weight: 600;
    box-shadow: inset 0 -2px 0 0 var(--lens-accent);
}

.lens-navbar .navbar-toggler {
    border-color: var(--lens-border);
    color: var(--lens-text-muted);
}

.lens-navbar .navbar-toggler:hover,
.lens-navbar .navbar-toggler:focus-visible {
    border-color: var(--lens-border-strong);
    color: var(--lens-text);
}

/* The three bars of the menu button, drawn rather than loaded.
   Bootstrap's own icon is a background-image carrying a data: URI, which `img-src 'self'` refuses,
   and the button rendered empty on every phone. `currentColor` is what makes the bars follow the
   button's own colour, so they darken on hover and stay legible in both colour modes. */
.lens-toggler-bars {
    display: block;
    position: relative;
    width: 1.25rem;
    height: 2px;
    background-color: currentColor;
}

.lens-toggler-bars::before,
.lens-toggler-bars::after {
    content: "";
    position: absolute;
    left: 0;
    width: 100%;
    height: 2px;
    background-color: currentColor;
}

.lens-toggler-bars::before {
    top: -6px;
}

.lens-toggler-bars::after {
    top: 6px;
}

/* 767.98px is where `navbar-expand-md` collapses the tabs. */
@media (max-width: 767.98px) {
    /* Each tab is a full-width row once the menu collapses, so the underline that marks the open
       tool on a desktop stretches edge to edge here and reads as a divider between items instead of
       as a mark on one. The accent colour and the weight carry the mark on their own at this width;
       a left border is what replaces the underline, since it grows along the row rather than across
       it. */
    .lens-navbar .nav-link.active {
        box-shadow: none;
        border-left: 2px solid var(--lens-accent);
        padding-left: var(--lens-space-2);
    }
}

/* ---------------------------------------------------------------- typography */

.lens-eyebrow {
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--lens-accent);
    margin-bottom: var(--lens-space-3);
}

.lens-section-title {
    font-family: var(--lens-font-display);
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    margin-bottom: var(--lens-space-4);
}

.lens-link {
    color: var(--lens-accent);
    text-decoration: none;
    font-weight: 500;
}

.lens-link:hover {
    text-decoration: underline;
}

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

.lens-btn-primary {
    background-color: var(--lens-accent);
    color: var(--lens-accent-contrast);
    border: none;
    border-radius: var(--lens-radius);
    font-weight: 600;
    padding: var(--lens-space-3) var(--lens-space-5);
    white-space: nowrap;
}

.lens-btn-primary:hover,
.lens-btn-primary:focus-visible {
    background-color: var(--lens-accent);
    color: var(--lens-accent-contrast);
    filter: brightness(1.08);
}

/*
 * The counterpart to the primary button, for a choice that must not read as the lesser one. It
 * carries a border rather than a fill so the two are visibly different actions, but the same size,
 * the same weight and the same padding: refusing costs exactly what accepting costs.
 */
.lens-btn-secondary {
    background-color: transparent;
    color: var(--lens-text);
    border: var(--lens-border-width) solid var(--lens-border-strong);
    border-radius: var(--lens-radius);
    font-weight: 600;
    padding: var(--lens-space-3) var(--lens-space-5);
    white-space: nowrap;
}

.lens-btn-secondary:hover,
.lens-btn-secondary:focus-visible {
    background-color: var(--lens-surface-sunken);
    color: var(--lens-text);
    border-color: var(--lens-border-strong);
}

/* ---------------------------------------------------------------- hero */

.lens-hero {
    padding-block: var(--lens-space-7) var(--lens-space-8);
    max-width: 46rem;
}

.lens-hero-title {
    font-family: var(--lens-font-display);
    /* The lower bound is what a 390px screen gets; the upper is the reference's own size. clamp
       carries the whole range, so there is no breakpoint to keep in step with the copy. */
    font-size: clamp(2.25rem, 6vw, 4.2rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.12;
    /* No character cap: this headline carries its own break element, and a ch limit on top of it
       produced four ragged lines. The reference's 18ch was measured against its own shorter copy. */
    max-width: 24ch;
    margin-bottom: var(--lens-space-4);
}

/* The one word the headline turns on. Colour rather than weight, because the display face is
   already at its heaviest here and a heavier run would not read as emphasis. */
.lens-hero-title em {
    font-style: normal;
    color: var(--lens-accent);
}

.lens-hero-lead {
    font-size: 1.0625rem;
    color: var(--lens-text-muted);
    max-width: 38rem;
    margin-bottom: var(--lens-space-6);
}

/*
 * The viewfinder: four corner brackets around the field the store URL is typed into.
 *
 * It is the one piece of ornament in the product, and it earns its place by saying what the tool
 * does before any copy is read: something is being framed and looked at. Built from two pseudo
 * elements on each of two nested boxes, so it costs no extra markup and no image.
 */
.lens-hero-form {
    position: relative;
    padding: var(--lens-space-4);
    max-width: 40rem;
}

.lens-hero-form::before,
.lens-hero-form::after,
.lens-inline-form::before,
.lens-inline-form::after {
    content: "";
    position: absolute;
    width: 1.4rem;
    height: 1.4rem;
    border: 2px solid var(--lens-accent);
    pointer-events: none;
}

.lens-hero-form::before {
    top: 0;
    left: 0;
    border-right: 0;
    border-bottom: 0;
}

.lens-hero-form::after {
    top: 0;
    right: 0;
    border-left: 0;
    border-bottom: 0;
}

.lens-inline-form::before {
    bottom: 0;
    left: 0;
    border-right: 0;
    border-top: 0;
}

.lens-inline-form::after {
    bottom: 0;
    right: 0;
    border-left: 0;
    border-top: 0;
}

.lens-inline-form {
    position: static;
    display: flex;
    gap: var(--lens-space-3);
    align-items: flex-start;
    flex-wrap: wrap;
}

/*
 * One sweep on load, never a loop. A repeating animation next to an input reads as "working" and
 * would be a lie: nothing is being scanned until the visitor submits. Honoured only where motion is
 * welcome; the reduced-motion block at the end of this file removes it.
 */
.lens-scanline {
    position: absolute;
    left: 4px;
    right: 4px;
    top: 4px;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--lens-accent), transparent);
    opacity: 0;
    pointer-events: none;
    animation: lens-sweep 900ms cubic-bezier(0.4, 0, 0.2, 1) 400ms;
}

@keyframes lens-sweep {
    0% { opacity: 0; top: 4px; }
    15% { opacity: 1; }
    85% { opacity: 1; }
    100% { opacity: 0; top: calc(100% - 6px); }
}

.lens-inline-field {
    flex: 1 1 20rem;
    margin-bottom: 0;
}

/* `display: flex` on this element overrides the `hidden` attribute's own `display: none`, so
   without this rule setting `field.hidden = true` changes nothing a visitor can see. The same
   pairing is already spelled out for `.lens-inline-warning[hidden]` further down. */
.lens-inline-field[hidden] {
    display: none;
}

/*
 * The chooser takes the whole row above the field rather than sitting beside it. Sharing the row
 * would put it in competition with `.lens-inline-field`'s 20rem basis, and both would shrink toward
 * it; the question of WHICH tool is also asked before the address, not next to it.
 */
.lens-tool-choice {
    flex: 1 1 100%;
    border: 0;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--lens-space-4);
    align-items: center;
}

.lens-tool-choice-legend {
    flex: 1 1 100%;
    float: none;
    width: auto;
    font-size: 0.875rem;
    color: var(--lens-text-muted);
    margin-bottom: var(--lens-space-2);
}

.lens-tool-option {
    margin-bottom: 0;
    padding-left: 1.6em;
}

.lens-tool-option .form-check-label {
    color: var(--lens-text);
    cursor: pointer;
}

.lens-tool-option .form-check-input:focus-visible {
    border-color: var(--lens-accent);
    box-shadow: 0 0 0 3px var(--lens-accent-soft);
    outline: none;
}

.lens-tool-option .form-check-input:checked {
    background-color: var(--lens-accent);
    border-color: var(--lens-accent);
}

/* The target field reads as a terminal: this is where the instrument is aimed. */
.lens-target-input {
    background-color: var(--lens-surface-sunken);
    border: var(--lens-border-width) solid var(--lens-border-strong);
    color: var(--lens-text);
    padding: var(--lens-space-3) var(--lens-space-4);
    font-size: 1rem;
}

.lens-target-input:focus {
    background-color: var(--lens-surface-sunken);
    color: var(--lens-text);
    box-shadow: none;
}

.lens-target-input:focus-visible {
    border-color: var(--lens-accent);
    box-shadow: 0 0 0 3px var(--lens-accent-soft);
    outline: none;
}

/* A full-width button is the only shape that converts on a phone. */
@media (max-width: 575.98px) {
    .lens-inline-field {
        flex: 1 1 100%;
    }

    /* The options stack rather than sitting side by side: two labels of this length on one row wrap
       mid-word at 390px and read as one run-on line. */
    .lens-tool-choice {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--lens-space-2);
    }

    .lens-inline-form .lens-btn-primary {
        width: 100%;
    }
}

.lens-hero-hint,
.lens-footer-note {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
    margin-top: var(--lens-space-3);
}

/* ---------------------------------------------------------------- tools */

.lens-tools-section {
    margin-bottom: var(--lens-space-8);
}

.lens-section-lead {
    color: var(--lens-text-muted);
    max-width: 46rem;
    margin-bottom: var(--lens-space-5);
}

.lens-tools {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: var(--lens-space-4);
}

.lens-tool-card {
    background-color: var(--lens-surface-raised);
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    padding: var(--lens-space-5);
    display: flex;
    flex-direction: column;
    gap: var(--lens-space-3);
}

.lens-tool-title {
    font-family: var(--lens-font-display);
    font-size: 1.3rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0;
}

.lens-tool-text {
    color: var(--lens-text-muted);
    font-size: 0.9375rem;
    flex: 1;
    margin: 0;
}

.lens-tool-link {
    color: var(--lens-accent);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.9375rem;
    align-self: flex-start;
}

.lens-tool-link:hover {
    text-decoration: underline;
}

/* A tool announced and not yet built. It has to read as a promise rather than as an option, so the
   card is quieter than the ones that work: no accent, a dashed edge, and a label instead of a link.
   Nothing here is disabled in the interactive sense, because there is no control to disable. */
.lens-tool-card-upcoming {
    background-color: transparent;
    border-style: dashed;
}

.lens-tool-soon {
    align-self: flex-start;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lens-text-muted);
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius);
    padding: var(--lens-space-1) var(--lens-space-3);
}

/* ---------------------------------------------------------------- credibility */

.lens-credibility {
    border-top: var(--lens-border-width) solid var(--lens-border);
    border-bottom: var(--lens-border-width) solid var(--lens-border);
    padding-block: var(--lens-space-6);
    margin-bottom: var(--lens-space-7);
}

.lens-stats {
    display: flex;
    flex-wrap: wrap;
    gap: var(--lens-space-7);
    margin-bottom: var(--lens-space-5);
}

.lens-stat {
    display: flex;
    flex-direction: column;
}

.lens-stat-value {
    font-size: 2rem;
    font-weight: 500;
    line-height: 1;
    color: var(--lens-text);
}

.lens-stat-label {
    font-size: 0.8125rem;
    color: var(--lens-text-muted);
    margin-top: var(--lens-space-2);
}

.lens-badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--lens-space-2);
    margin-bottom: var(--lens-space-4);
}

.lens-badge {
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius);
    padding: var(--lens-space-1) var(--lens-space-3);
    font-size: 0.8125rem;
    color: var(--lens-text-muted);
}

.lens-clients {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
    margin: 0;
}

/* ---------------------------------------------------------------- state pages */

.lens-state-page {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-block: var(--lens-space-7);
}

.lens-state-card {
    background-color: var(--lens-surface-raised);
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    padding: var(--lens-space-6);
    max-width: 34rem;
    width: 100%;
}

.lens-state-title {
    font-size: 1.5rem;
    font-weight: 600;
    margin-bottom: var(--lens-space-4);
}

.lens-state-message {
    color: var(--lens-text-muted);
    margin-bottom: var(--lens-space-4);
}

.lens-state-actions {
    display: flex;
    align-items: center;
    gap: var(--lens-space-4);
    flex-wrap: wrap;
    margin-top: var(--lens-space-5);
}

/* ---------------------------------------------------------------- footer */

.lens-footer {
    background-color: var(--lens-surface-raised);
    border-top: var(--lens-border-width) solid var(--lens-border);
    padding-block: var(--lens-space-6);
}

.lens-footer-inner {
    display: flex;
    flex-direction: column;
    gap: var(--lens-space-2);
}

.lens-footer-brand {
    font-size: 1rem;
}

.lens-footer-links {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
    display: flex;
    gap: var(--lens-space-2);
    flex-wrap: wrap;
}

.lens-footer-link {
    color: var(--lens-text-muted);
    text-decoration: none;
}

.lens-footer-link:hover {
    color: var(--lens-text);
    text-decoration: underline;
}

.lens-footer-sep {
    color: var(--lens-border-strong);
}

/* ---------------------------------------------------------------- forms */

.lens-form-intro {
    max-width: 42rem;
    margin-bottom: var(--lens-space-6);
}

.lens-form-title {
    font-family: var(--lens-font-display);
    font-size: clamp(1.75rem, 3vw, 2.5rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin-bottom: var(--lens-space-3);
}

.lens-form-lead {
    color: var(--lens-text-muted);
    margin: 0;
}

/* The form leads and the checklist supports it, so the form keeps the reading width. */
.lens-form-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    gap: var(--lens-space-6);
    align-items: start;
}

@media (max-width: 991.98px) {
    .lens-form-layout {
        grid-template-columns: 1fr;
    }
}

.lens-form .form-label {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--lens-text);
    margin-bottom: var(--lens-space-2);
}

.lens-form .form-control,
.lens-form .form-select {
    background-color: var(--lens-surface-raised);
    border: var(--lens-border-width) solid var(--lens-border);
    color: var(--lens-text);
    padding: var(--lens-space-3);
}

/*
 * :focus-visible rather than :focus, so an autofocused field on page load does not wear a coloured
 * ring that reads as a validation error before anything has been typed. Keyboard focus still shows
 * it, which is what the ring is for.
 */
 * The reset comes FIRST and the ring after it. Both selectors have equal specificity, so the later
 * one wins: declared the other way round, `box-shadow: none` cancelled the keyboard focus ring for
 * every focused field and only the border colour changed. `.lens-target-input` had the correct
 * order all along, which is why the defect showed only here.
 */
.lens-form .form-control:focus,
.lens-form .form-select:focus {
    background-color: var(--lens-surface-raised);
    color: var(--lens-text);
    box-shadow: none;
}

.lens-form .form-control:focus-visible,
.lens-form .form-select:focus-visible {
    border-color: var(--lens-accent);
    box-shadow: 0 0 0 3px var(--lens-accent-soft);
    background-color: var(--lens-surface-raised);
    color: var(--lens-text);
    outline: none;
}

.lens-form .form-control::placeholder {
    color: var(--lens-text-muted);
    opacity: 0.7;
}

.lens-form .invalid-feedback,
.lens-form .help-block {
    color: var(--lens-critical);
    font-size: 0.8125rem;
}

.lens-form .form-group {
    margin-bottom: var(--lens-space-4);
}

.lens-field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--lens-space-4);
}

/* A legal declaration is contained rather than left loose among the fields: it has to be read. */
.lens-declarations {
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    background-color: var(--lens-surface-sunken);
    padding: var(--lens-space-4) var(--lens-space-5) var(--lens-space-2);
    margin-block: var(--lens-space-5);
}

.lens-declarations-legend {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--lens-text-muted);
    float: none;
    width: auto;
    padding: 0;
    margin-bottom: var(--lens-space-3);
}

/*
 * A checkbox and its wording are a two-column grid, not a floated box with a margin.
 *
 * Bootstrap's own alignment holds only while the label is one line. These labels are legal
 * declarations that wrap to two or three on a phone, and the floated box then sits against the
 * middle of the wording instead of its first line. Grid with align-items: start pins the box to
 * the first line at every width.
 */
.lens-declarations .form-check,
.lens-consent {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: start;
    column-gap: var(--lens-space-3);
    margin-block-end: var(--lens-space-4);
    padding-left: 0;
}

.lens-declarations .form-check:last-of-type {
    margin-block-end: var(--lens-space-2);
}

.lens-declarations .form-check-label,
.lens-declarations label,
.lens-consent .form-check-label {
    color: var(--lens-text);
    font-size: 0.9375rem;
    /* No margin: the grid column owns the spacing, and a margin here would double it. */
    margin: 0;
}

/*
 * Nudged down so the box centres against the cap height of the first line rather than its top
 * edge, which is what "aligned" reads as to the eye.
 */
.lens-form .form-check-input,
.lens-consent .form-check-input {
    background-color: var(--lens-surface-raised);
    border-color: var(--lens-border-strong);
    margin-block-start: 0.15em;
    /* Bootstrap floats the control; the grid places it, and a float would pull it out of the cell. */
    float: none;
    margin-left: 0;
}

.lens-form .form-check-input:checked,
.lens-consent .form-check-input:checked {
    background-color: var(--lens-accent);
    border-color: var(--lens-accent);
}

.lens-form .form-check-input:focus,
.lens-consent .form-check-input:focus {
    border-color: var(--lens-accent);
    box-shadow: 0 0 0 3px var(--lens-accent-soft);
}

.lens-fieldset {
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    padding: var(--lens-space-5);
    margin-bottom: var(--lens-space-5);
}

.lens-legend {
    display: flex;
    align-items: center;
    gap: var(--lens-space-3);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--lens-text);
    float: none;
    width: auto;
    padding: 0;
    margin-bottom: var(--lens-space-4);
}

.lens-legend-step {
    color: var(--lens-accent);
    font-size: 0.8125rem;
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius);
    padding: 0.1rem var(--lens-space-2);
}

.lens-inline-warning {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
    margin: var(--lens-space-2) 0 0;
}

.lens-inline-warning[hidden] {
    display: none;
}

.lens-form-actions {
    display: flex;
    align-items: center;
    gap: var(--lens-space-4);
    flex-wrap: wrap;
    margin-top: var(--lens-space-5);
}

.lens-form-note {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
}

.lens-alert {
    border: var(--lens-border-width) solid var(--lens-border);
    border-left-width: 3px;
    border-radius: var(--lens-radius);
    padding: var(--lens-space-4);
    margin-bottom: var(--lens-space-5);
    background-color: var(--lens-surface-raised);
}

.lens-alert-error {
    border-left-color: var(--lens-critical);
}

.lens-alert-list {
    margin: 0;
    padding-left: var(--lens-space-5);
    color: var(--lens-text);
}

/* ---------------------------------------------------------------- checklist */

.lens-checklist {
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    background-color: var(--lens-surface-raised);
    padding: var(--lens-space-5);
}

.lens-checklist-title {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lens-text-muted);
    margin-bottom: var(--lens-space-4);
}

.lens-checklist-items {
    margin: 0;
    display: grid;
    gap: var(--lens-space-4);
}

.lens-checklist-name {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--lens-text);
    position: relative;
    padding-left: var(--lens-space-5);
}

.lens-checklist-name::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.45em;
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 1px;
    background-color: var(--lens-accent);
}

.lens-checklist-detail {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
    margin: var(--lens-space-1) 0 0;
    padding-left: var(--lens-space-5);
}

.lens-checklist-footer {
    font-size: 0.8125rem;
    color: var(--lens-text-muted);
    border-top: var(--lens-border-width) solid var(--lens-border);
    margin: var(--lens-space-5) 0 0;
    padding-top: var(--lens-space-4);
}

/* ---------------------------------------------------------------- findings */

/*
 * Screen-reader-only text. Bootstrap ships .visually-hidden, but this file must not depend on that
 * class surviving a Bootstrap upgrade or a partial being rendered outside the full stylesheet: the
 * text explaining a withheld row appeared on screen once because of exactly that.
 */
.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.list-group {
    list-style: none;
    padding-left: 0;
    --bs-list-group-bg: var(--lens-surface-raised);
    --bs-list-group-color: var(--lens-text);
    --bs-list-group-border-color: var(--lens-border);
    --bs-list-group-border-radius: var(--lens-radius-lg);
}

.list-group-item {
    padding: var(--lens-space-4) var(--lens-space-5);
}

/*
 * Severity is a coloured side border AND a word. The border reads at a glance and stacks well on a
 * narrow screen; the word is what survives a colour-blind reader and a black-and-white printout.
 * Neither is decoration: both say what state the store is in.
 */
.lens-finding {
    border-left: 3px solid var(--lens-border);
}

.lens-finding-high {
    border-left-color: var(--lens-critical);
}

.lens-finding-medium {
    border-left-color: var(--lens-warning);
}

.lens-finding-low {
    border-left-color: var(--lens-neutral);
}

.lens-finding-ok {
    border-left-color: var(--lens-ok);
}

/*
 * A check that could not run is a third state, not a dim pass. The border is dashed rather than
 * solid so the distinction survives a reader who cannot separate the two colours, matching the tag
 * that carries the same idea in a word.
 */
.lens-finding-unknown {
    border-left-color: var(--lens-text-muted);
    border-left-style: dashed;
}

.lens-finding-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--lens-space-4);
}

@media (max-width: 575.98px) {
    .lens-finding-row {
        flex-direction: column-reverse;
        align-items: flex-start;
        gap: var(--lens-space-2);
    }
}

.lens-finding-body {
    flex: 1;
    min-width: 0;
}

.lens-finding-title {
    font-weight: 600;
    margin-bottom: var(--lens-space-1);
}

.lens-finding-detail {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
}

.lens-finding-fix {
    font-size: 0.875rem;
    margin-top: var(--lens-space-3);
    padding-top: var(--lens-space-3);
    border-top: var(--lens-border-width) solid var(--lens-border);
}

.lens-finding-fix-label {
    display: block;
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lens-text-muted);
    margin-bottom: var(--lens-space-1);
}

.lens-tag {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.25rem var(--lens-space-3);
    border-radius: var(--lens-radius);
    border: var(--lens-border-width) solid currentcolor;
    white-space: nowrap;
}

.lens-tag-high {
    color: var(--lens-critical);
}

.lens-tag-medium {
    color: var(--lens-warning);
}

.lens-tag-low {
    color: var(--lens-neutral);
}

.lens-tag-ok {
    color: var(--lens-ok);
}

/* Dashed, so "not evaluated" is legible as its own state without depending on the colour. */
.lens-tag-unknown {
    color: var(--lens-text-muted);
    border-style: dashed;
}

.finding-withheld .finding-withheld-bars {
    display: flex;
    flex-direction: column;
    gap: var(--lens-space-2);
    flex: 1;
    padding-block: var(--lens-space-1);
}

/*
 * The bars stand where withheld text would be. They are not blurred text: the withheld title,
 * detail and recommendation are never passed to the view, so there is nothing here to reveal by
 * deleting a declaration in the browser console.
 */
.finding-bar {
    display: block;
    height: 0.7rem;
    border-radius: var(--lens-radius);
    background-color: var(--lens-border);
}

.finding-bar-thin {
    height: 0.5rem;
    opacity: 0.65;
}

.finding-withheld {
    background-color: var(--lens-surface-sunken);
}

/* ---------------------------------------------------------------- result head */

.lens-result-head {
    margin-bottom: var(--lens-space-5);
}

.lens-result-title {
    font-size: clamp(1.375rem, 3vw, 2rem);
    font-weight: 600;
    letter-spacing: -0.02em;
    margin: 0;
    word-break: break-word;
}

.lens-result-arrow {
    color: var(--lens-text-muted);
    margin-inline: var(--lens-space-2);
}

/* ---------------------------------------------------------------- gauge */

.lens-gauge {
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    background-color: var(--lens-surface-raised);
    padding: var(--lens-space-5);
    margin-bottom: var(--lens-space-6);
}

.lens-gauge-reading {
    display: flex;
    align-items: baseline;
    gap: var(--lens-space-2);
    flex-wrap: wrap;
}

.lens-gauge-value {
    font-size: clamp(2.5rem, 7vw, 3.75rem);
    font-weight: 500;
    line-height: 1;
}

.lens-gauge-max {
    font-size: 1.125rem;
    color: var(--lens-text-muted);
}

.lens-gauge-band {
    margin-left: var(--lens-space-3);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/*
 * What stands where the number and its scale would be, when too little of the store could be read
 * for any score to be honest. Muted rather than coloured: a band colour would rank a store that was
 * never ranked.
 */
.lens-gauge-note {
    margin-top: var(--lens-space-3);
    margin-bottom: 0;
    max-width: 60ch;
    color: var(--lens-text-muted);
}

/* The scale is what turns a number into a reading: it shows where the store sits on a range. */
.lens-gauge-scale {
    margin-top: var(--lens-space-4);
}

.lens-gauge-track {
    height: 0.5rem;
    border-radius: var(--lens-radius);
    background-color: var(--lens-surface-sunken);
    border: var(--lens-border-width) solid var(--lens-border);
    overflow: hidden;
}

.lens-gauge-fill {
    height: 100%;
    border-radius: var(--lens-radius);
}

.lens-gauge-fill-ok {
    background-color: var(--lens-ok);
}

.lens-gauge-fill-medium {
    background-color: var(--lens-warning);
}

.lens-gauge-fill-high {
    background-color: var(--lens-critical);
}

.lens-gauge-ticks {
    display: flex;
    justify-content: space-between;
    font-size: 0.75rem;
    color: var(--lens-text-muted);
    margin-top: var(--lens-space-2);
}

.lens-gauge-summary {
    font-size: 1.0625rem;
    margin: var(--lens-space-4) 0 0;
}

.lens-gauge-counts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--lens-space-6);
    margin: var(--lens-space-5) 0 0;
    padding-top: var(--lens-space-4);
    border-top: var(--lens-border-width) solid var(--lens-border);
}

.lens-gauge-count dt {
    font-size: 0.75rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--lens-text-muted);
    font-weight: 500;
}

.lens-gauge-count dd {
    font-size: 1.375rem;
    margin: var(--lens-space-1) 0 0;
}

/* ---------------------------------------------------------------- risk badge */

.lens-risk-badge {
    display: inline-flex;
    align-items: baseline;
    gap: var(--lens-space-2);
    border: var(--lens-border-width) solid currentcolor;
    border-radius: var(--lens-radius);
    padding: var(--lens-space-2) var(--lens-space-4);
}

.lens-risk-label {
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    opacity: 0.8;
}

.lens-risk-value {
    font-size: 1.125rem;
    font-weight: 700;
}

.lens-risk-high {
    color: var(--lens-critical);
}

.lens-risk-medium {
    color: var(--lens-warning);
}

.lens-risk-ok {
    color: var(--lens-ok);
}

/* ---------------------------------------------------------------- result body */

.lens-result-section {
    margin-bottom: var(--lens-space-6);
}

.lens-withheld-note {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
    margin-top: var(--lens-space-3);
}

.lens-alert-ok {
    border-left-color: var(--lens-ok);
}

.lens-alert-info {
    border-left-color: var(--lens-accent);
}

/* ---------------------------------------------------------------- capture */

.lens-capture {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    gap: var(--lens-space-6);
    align-items: start;
    border-top: var(--lens-border-width) solid var(--lens-border);
    padding-top: var(--lens-space-6);
}

@media (max-width: 991.98px) {
    .lens-capture {
        grid-template-columns: 1fr;
    }
}

.lens-capture-title {
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: var(--lens-space-3);
}

.lens-capture-lead {
    color: var(--lens-text-muted);
    margin-bottom: var(--lens-space-5);
}

.lens-consent {
    margin-block: var(--lens-space-4);
}

.lens-trust {
    background-color: var(--lens-surface-sunken);
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    padding: var(--lens-space-5);
}

.lens-trust-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: var(--lens-space-3);
    font-size: 0.875rem;
    color: var(--lens-text-muted);
}

.lens-trust-list li {
    padding-left: var(--lens-space-5);
    position: relative;
}

.lens-trust-list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.45em;
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    border: 2px solid var(--lens-ok);
}

/* ---------------------------------------------------------------- procedure */

.lens-link-card {
    border: var(--lens-border-width) solid var(--lens-border);
    border-left: 3px solid var(--lens-ok);
    border-radius: var(--lens-radius-lg);
    background-color: var(--lens-surface-raised);
    padding: var(--lens-space-5);
    margin-bottom: var(--lens-space-6);
}

.lens-link-label {
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lens-text-muted);
    margin-bottom: var(--lens-space-2);
}

.lens-link-value {
    margin-bottom: var(--lens-space-2);
    word-break: break-all;
}

.lens-procedure-lead {
    color: var(--lens-text-muted);
    max-width: 46rem;
    margin-bottom: var(--lens-space-5);
}

.lens-code {
    font-family: var(--lens-font-mono);
    font-size: 0.9em;
    color: var(--lens-accent);
    background-color: var(--lens-surface-sunken);
    border-radius: 3px;
    padding: 0.1em 0.35em;
}

.lens-steps {
    list-style: none;
    counter-reset: lens-step;
    padding: 0;
    margin: 0;
    display: grid;
    gap: var(--lens-space-5);
}

.lens-step {
    counter-increment: lens-step;
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    background-color: var(--lens-surface-raised);
    padding: var(--lens-space-5);
    padding-left: var(--lens-space-8);
    position: relative;
}

.lens-step::before {
    content: counter(lens-step, decimal-leading-zero);
    position: absolute;
    left: var(--lens-space-5);
    top: var(--lens-space-5);
    font-family: var(--lens-font-mono);
    font-size: 0.8125rem;
    color: var(--lens-accent);
}

.lens-step-title {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: var(--lens-space-2);
}

.lens-step-text {
    color: var(--lens-text-muted);
    font-size: 0.9375rem;
    margin-bottom: var(--lens-space-3);
}

.lens-step-hint {
    font-size: 0.8125rem;
    color: var(--lens-text-muted);
    margin: var(--lens-space-2) 0 0;
}

.lens-token {
    display: flex;
    align-items: stretch;
    gap: var(--lens-space-2);
    background-color: var(--lens-surface-sunken);
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius);
    padding: var(--lens-space-2) var(--lens-space-3);
    flex-wrap: wrap;
}

.lens-token-value {
    flex: 1 1 16rem;
    font-size: 0.8125rem;
    color: var(--lens-text);
    word-break: break-all;
    align-self: center;
}

.lens-copy {
    background: none;
    border: var(--lens-border-width) solid var(--lens-border-strong);
    border-radius: var(--lens-radius);
    color: var(--lens-text-muted);
    font-size: 0.8125rem;
    padding: var(--lens-space-1) var(--lens-space-3);
    cursor: pointer;
    white-space: nowrap;
}

.lens-copy:hover {
    border-color: var(--lens-accent);
    color: var(--lens-accent);
}

.lens-route {
    margin-top: var(--lens-space-4);
}

.lens-route-name {
    font-size: 0.875rem;
    font-weight: 600;
    margin-bottom: var(--lens-space-2);
}

.lens-alert-warning {
    border-left-color: var(--lens-warning);
}

/* ---------------------------------------------------------------- document */

.lens-document {
    max-width: 52rem;
}

.lens-document-head {
    border-bottom: 2px solid var(--lens-border-strong);
    padding-bottom: var(--lens-space-5);
    margin-bottom: var(--lens-space-6);
}

.lens-document-mark {
    font-size: 0.9375rem;
    margin-bottom: var(--lens-space-4);
}

.lens-document-title {
    font-family: var(--lens-font-display);
    font-size: 2rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    margin-bottom: var(--lens-space-5);
}

.lens-document-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--lens-space-6);
    margin: 0;
}

.lens-document-meta dt {
    font-size: 0.75rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--lens-text-muted);
    font-weight: 500;
}

.lens-document-meta dd {
    margin: var(--lens-space-1) 0 0;
    font-size: 1.0625rem;
}

.lens-document-summary {
    margin: var(--lens-space-5) 0 0;
    font-size: 1.0625rem;
}

.lens-document-section {
    margin-bottom: var(--lens-space-6);
}

.lens-document-list,
.lens-checklist-ordered {
    margin: 0;
    padding-left: var(--lens-space-6);
    display: grid;
    gap: var(--lens-space-3);
}

.lens-document-list-critical li::marker {
    color: var(--lens-critical);
}

.lens-checklist-ordered li::marker {
    color: var(--lens-accent);
    font-family: var(--lens-font-mono);
}

.lens-table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--lens-text);
    border-color: var(--lens-border);
    margin: 0;
}

.lens-table th {
    font-weight: 500;
    color: var(--lens-text-muted);
    width: 45%;
}

.lens-table-total {
    font-weight: 700;
}

.lens-document-note,
.lens-document-footer {
    font-size: 0.875rem;
    color: var(--lens-text-muted);
}

.lens-document-footer {
    border-top: var(--lens-border-width) solid var(--lens-border);
    padding-top: var(--lens-space-4);
    margin-top: var(--lens-space-6);
}

/* ---------------------------------------------------------------- severity */

.lens-severity-high {
    color: var(--lens-critical);
}

.lens-severity-medium {
    color: var(--lens-warning);
}

.lens-severity-low {
    color: var(--lens-neutral);
}

.lens-severity-ok {
    color: var(--lens-ok);
}

/*
 * No score, so no verdict colour. Green would read as a store with nothing wrong and red as one in
 * trouble; the truth is that nobody could look, which is what muted says.
 */
.lens-severity-unknown {
    color: var(--lens-text-muted);
}

/* ---------------------------------------------------------------- print */

/*
 * A report is meant to be forwarded, so it will be printed or saved as PDF by someone. The shell
 * is chrome and does not belong on paper; severity has to survive black and white, which it does
 * because every finding also carries its severity as text.
 */
@media print {
    #header,
    #footer,
    .lens-no-print {
        display: none !important;
    }

    body {
        background: #ffffff;
        color: #000000;
    }

    main > .container {
        padding: 0;
    }

    .list-group-item {
        break-inside: avoid;
    }
}

/* ---------------------------------------------------------------- motion */

/*
 * Motion is an enhancement, never information. Everything animated in this stylesheet says
 * something the layout already says, so removing it costs a visitor nothing, and for someone with
 * vestibular sensitivity a sweeping line is not decoration but a symptom trigger.
 */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    /* The scanline animates from opacity 0, so simply shortening it would leave the line frozen
       across the field. It is removed outright instead. */
    .lens-scanline {
        display: none;
    }
}

/* ---------------------------------------------------------------- cookie banner */

/*
 * Sits at the bottom, over the page rather than in front of it. It does not block reading, does not
 * dim the content and traps no focus: analytics is not worth interrupting someone who came here to
 * diagnose a store.
 */
.lens-cookie-banner {
    position: fixed;
    left: var(--lens-space-4);
    right: var(--lens-space-4);
    bottom: var(--lens-space-4);
    z-index: 1030;
    max-width: 34rem;
    margin-inline: auto;
    padding: var(--lens-space-5);
    background-color: var(--lens-surface-raised);
    border: var(--lens-border-width) solid var(--lens-border-strong);
    border-radius: var(--lens-radius-lg);
    box-shadow: 0 8px 32px rgb(0 0 0 / 35%);
}

.lens-cookie-text {
    color: var(--lens-text-muted);
    font-size: 0.9375rem;
    margin-bottom: var(--lens-space-4);
}

/*
 * Both buttons share a row and stretch equally. Refusing must cost exactly what accepting costs;
 * a refusal styled as an afterthought is not a freely given choice, whatever the copy says.
 */
.lens-cookie-actions {
    display: flex;
    gap: var(--lens-space-3);
}

.lens-cookie-actions .btn {
    flex: 1 1 0;
}

.lens-cookie-link {
    margin-top: var(--lens-space-3);
    margin-bottom: 0;
    font-size: 0.875rem;
}

/* The anchor inside inherits the accent from the paragraph, which carries lens-link itself. One
   class in one place rather than a decorative one on each. */
.lens-cookie-link a {
    color: inherit;
}

/* ------------------------------------------------------------- sales cta */

/*
 * The commercial close. Sunken so it separates from the sections above without a rule, and holding
 * the same scanline the hero opens with: the sweep that starts the page finishes it.
 */
.lens-sales-cta {
    position: relative;
    overflow: hidden;
    background-color: var(--lens-surface-sunken);
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    padding: var(--lens-space-7) var(--lens-space-6);
    margin-block-start: var(--lens-space-7);
    text-align: center;
}

/*
 * The base .lens-scanline rule plays its sweep once, on stylesheet application: correct for the
 * hero, where the visitor is already looking at it, and invisible here, where the section sits
 * below the fold and the sweep would finish before anyone scrolls to it. This variant starts
 * silent and only plays once the section enters the viewport, restarted by toggling the
 * animation-name from "none" to the shared keyframes when `.lens-scanline-run` is added.
 */
.lens-scanline-armed {
    animation: none;
    opacity: 0;
}

.lens-scanline-armed.lens-scanline-run {
    animation: lens-sweep 900ms cubic-bezier(0.4, 0, 0.2, 1);
}

.lens-sales-lines {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--lens-space-5);
    margin-block: var(--lens-space-6);
    text-align: left;
}

@media (max-width: 767px) {
    .lens-sales-lines {
        grid-template-columns: 1fr;
    }
}

.lens-sales-line-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--lens-text);
    margin-bottom: var(--lens-space-2);
}

.lens-sales-line-text {
    font-size: 0.9375rem;
    color: var(--lens-text-muted);
    margin: 0;
}

.lens-sales-button {
    /* Wide enough to read as the page's closing action rather than as one more inline link. */
    min-width: 16rem;
}

/* --------------------------------------------------------- pending state */

/*
 * A disabled submit reads as unavailable unless it says otherwise. It keeps the accent and loses
 * only the pointer, so the visitor sees a button that is working rather than one that is off.
 */
.lens-btn-primary:disabled {
    cursor: progress;
    opacity: 0.75;
}

/*
 * The state panel. Revealed by the script after the delay, hidden in markup so a page without
 * JavaScript never shows a message about work it cannot report on.
 */
.lens-pending-panel {
    display: flex;
    align-items: center;
    gap: var(--lens-space-3);
    margin-block-start: var(--lens-space-4);
    padding: var(--lens-space-4);
    background-color: var(--lens-surface-sunken);
    border: var(--lens-border-width) solid var(--lens-border);
    border-radius: var(--lens-radius-lg);
    font-size: 0.9375rem;
    color: var(--lens-text-muted);
}

.lens-pending-panel[hidden] {
    display: none;
}

.lens-pending-spinner {
    flex: none;
    width: 1.125rem;
    height: 1.125rem;
    border: 2px solid var(--lens-border-strong);
    border-top-color: var(--lens-accent);
    border-radius: 50%;
    animation: lens-spin 700ms linear infinite;
}

@keyframes lens-spin {
    to {
        transform: rotate(360deg);
    }
}
