/* Binga Filing Systems.
   One stylesheet for the public site and the admin, no framework: the whole design fits
   comfortably in a file, and there is nothing to keep updated but this.

   Light and unfussy on purpose. The buyers are office managers and facilities people on
   corporate machines; the site's job is to look like a company that will still exist in
   ten years, which is also the truth being sold. Navy carries the brand, one warm accent
   does the pointing. */

:root {
    --ink: #17253a;
    --ink-soft: #47566e;
    --navy: #12314e;
    --navy-deep: #0c2238;
    --accent: #d97a1e;
    --accent-ink: #b25f0e;
    --paper: #ffffff;
    --paper-tint: #f2f5f9;
    --line: #dbe2ea;
    --ok-tint: #e8f5ec;
    --ok-ink: #1e6b3a;
    --danger: #b3372f;
    --danger-tint: #fbeaea;
    --radius: 10px;
    --radius-lg: 16px;
    --shadow: 0 10px 30px rgba(18, 49, 78, 0.10);
    --shadow-soft: 0 2px 8px rgba(18, 49, 78, 0.06);

    /* The accent at a whisper: focus rings on inputs, the glow behind the hero, the halo
       on a hovered card. Alpha rather than a paler orange so it sits on either theme. */
    --accent-tint: rgba(217, 122, 30, 0.16);

    /* The sticky header's ground: mostly paper, see-through enough for the page to show
       through its blur as it scrolls underneath. */
    --paper-glass: rgba(255, 255, 255, 0.84);

    /* Headings and ghost buttons read this rather than --navy directly. On the public
       site the two are the same colour; in the admin's dark mode the header keeps its
       navy while headings have to go light, and this is the seam between them. */
    --heading: var(--navy);

    /* The admin only: the bar across the top, and the side menu's lit entry. */
    --admin-bar: var(--navy);
    --side-active-bg: #e6edf6;
    --side-active-ink: var(--navy);

    color-scheme: light;
}

/* Night mode, public site and admin alike: each layout's inline script sets data-theme
   on <html> from the saved choice or the machine's preference, and theme.js flips it.
   Every rule below reads a token rather than a literal for anything that should adapt,
   so this block only redeclares the tokens. The navy bands (page heads, footer, the
   call-to-action strip, the admin bar) keep their navy: they are the brand, not the page,
   and they were already dark. */
[data-theme="dark"] {
    --ink: #e6ebf1;
    --ink-soft: #9fadbd;
    --paper: #1a2128;
    --paper-tint: #11161b;
    --line: #2c3742;
    --ok-tint: #17301f;
    --ok-ink: #8fd3a3;
    --danger: #ea8078;
    --danger-tint: #3a1f1d;
    --accent-ink: #f0a24a;
    --shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
    --shadow-soft: 0 2px 8px rgba(0, 0, 0, 0.30);
    --paper-glass: rgba(26, 33, 40, 0.84);
    --heading: #dfe8f2;
    --admin-bar: #0c1622;
    --side-active-bg: #1b2c40;
    --side-active-ink: #cfe0f4;
    color-scheme: dark;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: "Inter", system-ui, sans-serif;
    font-size: 16px;
    line-height: 1.6;
    color: var(--ink);
    background: var(--paper);
    -webkit-font-smoothing: antialiased;
}

/* Keyboard focus, one look everywhere: the accent ring, drawn outside the element so it
   never clips a button's own corners. Inputs get their own softer ring in the form rules,
   since a hard ring against a hard border is two outlines fighting. */
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

::selection { background: var(--accent); color: #fff; }

h1, h2, h3 {
    font-family: "Manrope", "Inter", system-ui, sans-serif;
    line-height: 1.15;
    color: var(--heading);
    margin: 0 0 14px;
    /* Tighter tracking on the big sizes, where Manrope's default spacing starts to look
       loose, and balanced wrapping so a two-line headline does not leave one word
       stranded on the second line. */
    letter-spacing: -0.02em;
    text-wrap: balance;
}

h1 { font-size: clamp(32px, 5vw, 52px); font-weight: 800; }
h2 { font-size: clamp(26px, 3.2vw, 36px); font-weight: 700; }
h3 { font-size: 19px; font-weight: 700; letter-spacing: -0.01em; }

p { margin: 0 0 14px; }
img { max-width: 100%; display: block; }
a { color: var(--accent-ink); }

.wrap {
    max-width: 1120px;
    margin: 0 auto;
    padding: 0 20px;
}

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

/* Frosted rather than solid: the page shows faintly through as it scrolls under the
   header, which is what makes a sticky bar read as sitting on the page rather than
   cutting it off. The solid fallback covers a browser without backdrop-filter. */
.site-head {
    background: var(--paper);
    background: var(--paper-glass);
    -webkit-backdrop-filter: saturate(160%) blur(14px);
    backdrop-filter: saturate(160%) blur(14px);
    border-bottom: 1px solid var(--line);
    position: sticky;
    top: 0;
    z-index: 20;
}

/* Keyboard users' way past the header on every page. Off screen until it has focus. */
.skip-link {
    position: absolute;
    left: 16px;
    top: -60px;
    z-index: 30;
    background: var(--navy);
    color: #fff;
    padding: 10px 16px;
    border-radius: 6px;
    text-decoration: none;
    font-weight: 600;
}

.skip-link:focus { top: 16px; }

.head-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: 88px;
}

.brand { display: flex; align-items: center; }

/* The logo is the masthead here, not a small mark beside a wordmark: it carries the
   company name and "FILING SYSTEMS" inside the artwork. At the 44px it started at, that
   descriptor was a grey smudge and the whole thing only 104px wide, which read as an
   afterthought on a manufacturer's site. 64px makes both lines legible and gives the
   header something to be built around. */
.brand-logo { height: 64px; width: auto; }

/* Binga's logo is blue on transparent and its darker strokes disappear on a dark header.
   Not ours to recolour, so in night mode it sits on a white chip instead, the same
   answer ChatBill's footer gives the Tolerance logo. */
[data-theme="dark"] .brand-logo {
    background: #fff;
    padding: 6px 10px;
    border-radius: 8px;
    box-sizing: content-box;
}

/* The toggle and, on a phone, the burger beside it. */
.head-tools { display: flex; align-items: center; gap: 10px; }

.site-nav { display: flex; align-items: center; gap: 22px; }

.site-nav a {
    color: var(--ink);
    text-decoration: none;
    font-weight: 500;
    font-size: 15.5px;
    transition: color 140ms ease;
}

.site-nav a:hover { color: var(--accent-ink); }

/* The accent rule under a link: grows out from the left on hover, and stays under the
   page the visitor is on, which the layout marks with .active. The contact button is
   excluded, it has its own shape. */
.site-nav a:not(.nav-cta) { position: relative; padding: 6px 0; }

.site-nav a:not(.nav-cta)::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    border-radius: 2px;
    background: var(--accent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 180ms ease;
}

.site-nav a:not(.nav-cta):hover::after,
.site-nav a.active::after { transform: scaleX(1); }

.site-nav a.active { color: var(--heading); font-weight: 600; }

.site-nav .nav-cta {
    background: var(--accent);
    color: #fff;
    padding: 9px 18px;
    border-radius: 6px;
    font-weight: 600;
}

.site-nav .nav-cta:hover { background: var(--accent-ink); color: #fff; }

/* The burger: a checkbox the label toggles, pure CSS. Hidden on desktop. */
.nav-toggle { display: none; }
.nav-burger { display: none; }

@media (max-width: 860px) {
    .nav-burger {
        display: flex;
        flex-direction: column;
        gap: 5px;
        padding: 10px;
        cursor: pointer;
    }

    .nav-burger span {
        display: block;
        width: 24px;
        height: 2.5px;
        background: var(--heading);
        border-radius: 2px;
    }

    .brand-logo { height: 52px; }

    /* The toggle and the burger sit together on the right, as the burger did alone. */
    .head-tools { gap: 6px; }

    .site-nav {
        display: none;
        position: absolute;
        /* Below the header whatever height it ends up: .site-head is sticky, so it is
           the positioned ancestor this resolves against. It used to be a hard 68px, which
           silently detached the menu from the header the moment the logo grew. */
        top: 100%;
        left: 0;
        right: 0;
        background: var(--paper);
        border-bottom: 1px solid var(--line);
        flex-direction: column;
        align-items: stretch;
        padding: 10px 20px 20px;
        gap: 4px;
        box-shadow: var(--shadow);
    }

    .site-nav a { padding: 10px 12px; border-radius: 6px; }
    /* In the dropped-down menu the underline has nothing to sit under; the current page
       gets a tinted row instead, the same mark the admin's side menu uses. */
    .site-nav a:not(.nav-cta) { padding: 10px 12px; }
    .site-nav a:not(.nav-cta)::after { display: none; }
    .site-nav a.active { background: var(--paper-tint); }
    .site-nav .nav-cta { text-align: center; margin-top: 8px; }
    .nav-toggle:checked ~ .site-nav { display: flex; }
}

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

/* Squared-off rather than pills. Filing cabinets are square things, and the pill shape
   read as a consumer app on a page selling steel to facilities managers. The tags
   (.tag-hidden, .tag-note) keep their pill: they are labels, not buttons. */
.btn {
    display: inline-block;
    padding: 11px 22px;
    border-radius: 6px;
    border: 1.5px solid transparent;
    font: 600 15.5px "Inter", system-ui, sans-serif;
    text-decoration: none;
    cursor: pointer;
    transition: background 140ms ease, border-color 140ms ease, color 140ms ease,
                transform 140ms ease, box-shadow 140ms ease;
}

/* The orange button carries a glow of its own colour and lifts a pixel on hover: it is
   the one thing on any page asking to be pressed, and it should look pressable. */
.btn-primary { background: var(--accent); color: #fff; box-shadow: 0 6px 16px rgba(217, 122, 30, 0.28); }
.btn-primary:hover { background: var(--accent-ink); transform: translateY(-1px); box-shadow: 0 10px 22px rgba(217, 122, 30, 0.32); }
.btn-primary:active { transform: none; box-shadow: 0 3px 8px rgba(217, 122, 30, 0.28); }

.btn-ghost { background: transparent; color: var(--heading); border-color: var(--heading); }
.btn-ghost:hover { background: var(--heading); color: var(--paper); }

.btn-danger { background: var(--danger); color: #fff; }
.btn-danger-ghost { color: var(--danger); border-color: var(--danger); background: transparent; }

.btn-small { padding: 7px 16px; font-size: 14px; }

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

/* A warm glow top right and a cool one bottom left over the paper gradient, so the
   opening screen has some depth without a stock-photo background. overflow: clip because
   the photo's offset frame below pokes past the column on purpose. */
.hero {
    background:
        radial-gradient(60% 80% at 100% 0%, var(--accent-tint), transparent 60%),
        radial-gradient(50% 70% at 0% 100%, rgba(18, 49, 78, 0.08), transparent 60%),
        linear-gradient(180deg, var(--paper-tint), var(--paper));
    overflow: clip;
}

/* The opening screen rises into place, copy first and the photo a beat behind. Short and
   once only; switched off with the rest of the motion for anyone who has asked for
   that, see the reduced-motion block at the end of the public rules. */
@keyframes rise {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
}

.hero-copy { animation: rise 520ms ease-out both; }
.hero-photo { animation: rise 520ms 140ms ease-out both; }

.hero-grid {
    display: grid;
    grid-template-columns: 1.1fr 1fr;
    gap: 40px;
    align-items: center;
    padding-top: 56px;
    padding-bottom: 56px;
}

.kicker {
    font-size: 13.5px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--accent-ink);
    margin-bottom: 10px;
}

.lead { font-size: 18px; color: var(--ink-soft); }
.hero .lead { font-size: 19px; max-width: 52ch; }

.hero-ctas { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 24px; }

/* Buttons that sit in a row share a minimum width, so three different labels come out as
   three same-sized buttons rather than a ragged line sized by their words. The hero's
   three are short labels and get the smaller floor; the rows further down the page carry
   longer labels ("Where these systems are used") and get a bigger one so they match each
   other. On a phone the floor comes off and each fills the line, one under the other. */
.btn { text-align: center; }
.hero-ctas .btn { min-width: 180px; }
.btn-row .btn { min-width: 300px; }

@media (max-width: 600px) {
    .hero-ctas .btn, .btn-row .btn { min-width: 0; flex: 1 1 100%; }
}

/* The photo sits on a tinted panel offset down and to the right, an old print trick that
   gives one flat rectangle a little depth without a heavy drop shadow doing the work. */
.hero-photo { position: relative; }

.hero-photo::before {
    content: "";
    position: absolute;
    inset: 22px -22px -22px 22px;
    border-radius: var(--radius-lg);
    background: linear-gradient(135deg, var(--accent), var(--navy));
    opacity: 0.16;
    z-index: 0;
}

.hero-photo img {
    position: relative;
    z-index: 1;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    aspect-ratio: 4 / 3;
    object-fit: cover;
    width: 100%;
}

@media (max-width: 860px) {
    .hero-grid { grid-template-columns: 1fr; padding-top: 36px; padding-bottom: 48px; }
    /* Less offset on a phone, where the frame would otherwise run under the edge. */
    .hero-photo::before { inset: 14px -10px -14px 14px; }
}

/* ---- sections ---------------------------------------------------------------------- */

.band { padding: 64px 0; }
.band-tint { background: var(--paper-tint); }
.section-lead { color: var(--ink-soft); max-width: 60ch; margin-bottom: 28px; font-size: 17px; }

/* A short accent rule under each section heading on the home page and the list pages.
   The About page's headings are excluded: they are running text, and a rule under every
   one of them would chop the profile into slabs. */
.band > .wrap:not(.prose) > h2::after {
    content: "";
    display: block;
    width: 48px;
    height: 4px;
    border-radius: 2px;
    background: var(--accent);
    margin-top: 14px;
}

.band > .wrap:not(.prose) > h2 { margin-bottom: 22px; }

/* The navy heading band on the inner pages. A diagonal into the deeper navy, and a warm
   glow off the top right corner, so it reads as a designed surface rather than a strip
   of flat colour. */
.page-head {
    background: linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);
    padding: 56px 0 48px;
    position: relative;
    overflow: hidden;
}

.page-head::after {
    content: "";
    position: absolute;
    right: -140px;
    top: -160px;
    width: 460px;
    height: 460px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(217, 122, 30, 0.32), transparent 68%);
    pointer-events: none;
}

.page-head .wrap { position: relative; z-index: 1; }
.page-head h1, .page-head .crumb a { color: #fff; }
.page-head h1 { margin-bottom: 0; }
.page-head .lead { color: #c7d3e0; margin: 14px 0 0; max-width: 60ch; }
.page-head .btn-row, .page-head p:has(> .btn) { margin-top: 24px; }
.crumb { font-size: 14px; color: #c7d3e0; margin-bottom: 8px; }
.crumb a { text-decoration: none; }
.crumb a:hover { text-decoration: underline; }

/* ---- the four steps ---------------------------------------------------------------- */

/* auto-fit rather than a fixed four, because the steps are editable now: adding a fifth
   or dropping to three must not leave a stretched card or an empty column. */
.steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    /* Every row as tall as the tallest one. Some steps have a description and some are
       just a name (Powder coating, Relocations), and without this the second row of
       panels came out half the height of the first, which read as two different things
       rather than seven steps of one process. */
    grid-auto-rows: 1fr;
    gap: 20px;
}

.step {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 24px 22px;
    box-shadow: var(--shadow-soft);
    transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease;
}

.step:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--accent); }

.step span {
    display: inline-grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--navy), var(--navy-deep));
    color: #fff;
    font: 700 16px "Manrope", sans-serif;
    margin-bottom: 14px;
    /* A halo in the accent, so the number reads as a badge and not a dot. */
    box-shadow: 0 0 0 4px var(--accent-tint);
}

.step p { color: var(--ink-soft); font-size: 14.5px; margin: 0; }

@media (max-width: 860px) { .steps { grid-template-columns: repeat(2, 1fr); } }
/* One column on a phone: equal rows would pad every short step out to the tallest one,
   which on a narrow screen is just scrolling past empty space. */
@media (max-width: 540px) { .steps { grid-template-columns: 1fr; grid-auto-rows: auto; } }

/* ---- product cards ----------------------------------------------------------------- */

.card-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    /* Same reasoning as .steps: rows of cards are one catalogue and must line up. */
    grid-auto-rows: 1fr;
    gap: 24px;
}

.card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    overflow: hidden;
    text-decoration: none;
    color: var(--ink);
    display: flex;
    flex-direction: column;
    box-shadow: var(--shadow-soft);
    transition: box-shadow 180ms ease, transform 180ms ease, border-color 180ms ease;
}

.card:hover { box-shadow: var(--shadow); transform: translateY(-4px); border-color: var(--accent); }

/* The photo in its own clipped box, so it can grow a touch on hover without spilling
   over the card's corners. */
.card-photo { overflow: hidden; }
.card-photo img { aspect-ratio: 3 / 2; object-fit: cover; width: 100%; transition: transform 400ms ease; }
.card:hover .card-photo img { transform: scale(1.05); }

/* Stands in for the photo on a product that has none, at exactly the photo's size, so a
   card without a picture is the same shape as its neighbours instead of a stub two
   thirds their height. A tinted panel with the name of the business rather than a stock
   image: a placeholder that pretends to be a photo is worse than one that is honest. */
.card-photo-empty {
    aspect-ratio: 3 / 2;
    width: 100%;
    display: grid;
    place-items: center;
    background: var(--paper-tint);
    border-bottom: 1px solid var(--line);
    color: var(--heading);
    font: 700 15px "Manrope", "Inter", system-ui, sans-serif;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.45;
}

.card-body { padding: 20px 22px 22px; display: flex; flex-direction: column; flex: 1; }
.card-body h3 { margin-bottom: 8px; }
.card-body p { color: var(--ink-soft); font-size: 15px; flex: 1; }
.card-more { color: var(--accent-ink); font-weight: 600; font-size: 15px; display: inline-flex; align-items: center; gap: 6px; }

/* The arrow after "Read more" slides right as the card lifts. */
.card-more::after { content: "\2192"; display: inline-block; transition: transform 180ms ease; }
.card:hover .card-more::after { transform: translateX(4px); }

/* Two across on a tablet before dropping to one on a phone: three squeezed into 760px
   were too narrow to read, one at that width is a column of billboards. */
@media (max-width: 960px) { .card-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .card-grid { grid-template-columns: 1fr; grid-auto-rows: auto; } }

/* ---- services ---------------------------------------------------------------------- */

/* The services on the home page: a grid of ticked tiles rather than a bulleted list. A
   bullet says "here is a list"; a tick says "yes, we do that", which is the question a
   visitor scanning this section is asking. */
.service-list {
    list-style: none;
    padding: 0;
    margin: 0 0 28px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    /* Every row as tall as the tallest, so a one-line service sits in the same size
       tile as a three-line one instead of the grid looking like a staircase. */
    grid-auto-rows: 1fr;
    gap: 12px 20px;
}

.service-list li {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    background: var(--paper-tint);
    border-radius: 8px;
    font-weight: 500;
    transition: background 140ms ease;
}

.service-list li:hover { background: var(--accent-tint); }

.service-list li::before {
    content: "";
    flex: 0 0 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E") center / 13px no-repeat;
}

/* The services page: two across where there is room, each with its accent edge. */
.service-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 18px;
}

@media (max-width: 420px) { .service-cards { grid-template-columns: 1fr; } }

.service-card {
    border: 1px solid var(--line);
    border-left: 4px solid var(--accent);
    border-radius: 10px;
    padding: 22px 24px;
    background: var(--paper);
    box-shadow: var(--shadow-soft);
    transition: transform 160ms ease, box-shadow 160ms ease;
}

.service-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.service-card h3 { margin-bottom: 6px; }
.service-card p { color: var(--ink-soft); margin: 0; }

/* ---- applications ------------------------------------------------------------------ */

/* A vertical list, read top to bottom, one environment per row. It was a row of chips,
   which is the wrong shape entirely: chips are for filters and tags, where each word is
   something you click, and they leave no room for the line that explains why the
   environment is on the list at all. */
.application-list {
    list-style: none;
    padding: 0;
    margin: 0;
    border-top: 1px solid var(--line);
    max-width: 78ch;
}

.application-list li {
    border-bottom: 1px solid var(--line);
    padding: 22px 0 22px 22px;
    /* The accent rule stands in for a bullet: it lines the rows up down the left without
       the indent and hanging punctuation a real list marker brings. */
    border-left: 3px solid transparent;
    padding-left: 22px;
    transition: border-left-color 120ms ease, background 120ms ease;
}

.application-list li:hover {
    border-left-color: var(--accent);
    background: var(--paper-tint);
}

.application-list h2 {
    font-size: 19px;
    font-weight: 700;
    margin: 0 0 4px;
}

.application-list p {
    color: var(--ink-soft);
    margin: 0;
    max-width: 62ch;
}

.application-closing {
    margin-top: 32px;
    max-width: 62ch;
}

.application-closing p { color: var(--ink-soft); }

.after-note { color: var(--ink-soft); max-width: 60ch; }

/* Two or more buttons in a row. Buttons are inline-block, so without this they sit
   against each other with only a space between and wrap raggedly on a phone. */
.btn-row {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 24px;
}

/* ---- product detail ---------------------------------------------------------------- */

.product-grid {
    display: grid;
    grid-template-columns: 1fr 1.2fr;
    gap: 40px;
    align-items: start;
}

.product-photo img { border-radius: var(--radius-lg); box-shadow: var(--shadow); }

/* The photo keeps pace with a long description on a wide screen; top clears the sticky
   header. Released on a phone, where the two stack. */
@media (min-width: 861px) { .product-photo { position: sticky; top: 108px; } }
@media (max-width: 860px) { .product-grid { grid-template-columns: 1fr; } }

.prose { max-width: 68ch; }
.prose p, .prose li { color: var(--ink-soft); }
.prose h2 { margin-top: 30px; }
.prose strong { color: var(--ink); }

/* ---- CTA band ---------------------------------------------------------------------- */

.cta-band {
    background:
        radial-gradient(70% 140% at 50% 130%, rgba(217, 122, 30, 0.34), transparent 62%),
        linear-gradient(180deg, var(--navy), var(--navy-deep));
    color: #c7d3e0;
    padding: 72px 0;
    text-align: center;
}

.cta-band h2 { color: #fff; }
.cta-band p { max-width: 56ch; margin: 0 auto 16px; font-size: 17px; }
.cta-band p:last-child { margin-top: 24px; margin-bottom: 0; }

/* ---- gallery ------------------------------------------------------------------------ */

.gallery-grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 16px;
}

/* Uniform tiles, cropped to fit: a gallery grid reads as a grid, and the full photo is
   one tap away in the lightbox where nothing is cropped. */
.gallery-grid a {
    position: relative;
    display: block;
    overflow: hidden;
    border-radius: var(--radius);
    box-shadow: var(--shadow-soft);
    transition: box-shadow 180ms ease, transform 180ms ease;
}

.gallery-grid a:hover { box-shadow: var(--shadow); transform: translateY(-3px); }

.gallery-grid img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
    transition: transform 500ms ease;
}

.gallery-grid a:hover img { transform: scale(1.05); }

/* The caption, over the foot of the tile on a navy fade, appearing on hover. The
   lightbox shows it in full underneath the photo; here it is a hint of what the tile is. */
.gallery-cap {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 28px 14px 12px;
    color: #fff;
    font-size: 14px;
    font-weight: 500;
    background: linear-gradient(180deg, transparent, rgba(12, 34, 56, 0.85));
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 200ms ease, transform 200ms ease;
}

.gallery-grid a:hover .gallery-cap { opacity: 1; transform: none; }

/* No hover on a touch screen, so the caption simply shows. */
@media (hover: none) { .gallery-cap { opacity: 1; transform: none; } }

/* The lightbox. Hidden until its id is the URL fragment; see Gallery.cshtml for how the
   links drive it without script. */
.lightbox {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(12, 34, 56, 0.93);
    padding: 24px;
}

.lightbox:target { display: grid; place-items: center; }

.lightbox a { text-decoration: none; cursor: zoom-out; }

.lightbox figure { margin: 0; }

.lightbox img {
    max-width: min(92vw, 1100px);
    max-height: 82vh;
    width: auto;
    height: auto;
    border-radius: var(--radius-lg);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.lightbox figcaption {
    color: #dce6ef;
    text-align: center;
    margin-top: 12px;
    font-size: 15px;
}

/* ---- client logo strip -------------------------------------------------------------- */

/* Other companies' logos, so they arrive at every size, aspect ratio and background.
   Each sits in a fixed-height white tile and is contained rather than cropped, which is
   the only way a wide wordmark and a square badge can share a row without one of them
   being mangled. Greyscale until hovered keeps four unrelated brand palettes from
   fighting each other and the page. */
.client-strip {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 20px;
    padding: 0;
    margin: 0;
    align-items: center;
}

.client-strip li {
    /* White in both themes, not the page colour: these are other companies' logos, drawn
       for a white ground, and a dark tile would swallow half of them. */
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 22px 24px;
    height: 120px;
    display: grid;
    place-items: center;
    box-shadow: var(--shadow-soft);
    transition: box-shadow 160ms ease, transform 160ms ease;
}

.client-strip li:hover { box-shadow: var(--shadow); transform: translateY(-2px); }

.client-strip a { display: block; }

.client-strip img {
    max-height: 76px;
    max-width: 100%;
    width: auto;
    object-fit: contain;
    filter: grayscale(100%);
    opacity: 0.75;
    transition: filter 150ms ease, opacity 150ms ease;
}

.client-strip li:hover img { filter: none; opacity: 1; }

/* Admin-typed text whose line breaks are meant: the street address, typed over three
   lines in the admin, shows over three lines. Everything else collapses as usual. */
.keep-lines { white-space: pre-line; }

/* ---- contact ----------------------------------------------------------------------- */

.contact-grid {
    display: grid;
    grid-template-columns: 1fr 1.4fr;
    gap: 48px;
    align-items: start;
}

@media (max-width: 860px) { .contact-grid { grid-template-columns: 1fr; } }

/* The address, numbers and addresses as rows with an icon each, in a tinted panel. They
   were a bare run of lines that looked like the footer had wandered up the page. */
.contact-card {
    background: var(--paper-tint);
    border-radius: var(--radius-lg);
    padding: 26px 28px;
    display: grid;
    gap: 18px;
}

.contact-row { display: flex; gap: 14px; align-items: flex-start; }

.contact-row svg {
    flex: 0 0 40px;
    width: 40px;
    height: 40px;
    padding: 10px;
    border-radius: 10px;
    background: var(--paper);
    color: var(--accent-ink);
    box-shadow: var(--shadow-soft);
}

.contact-row-body { min-width: 0; }
.contact-row-body p { margin: 0; }
.contact-row-body a { display: block; text-decoration: none; font-weight: 500; overflow-wrap: anywhere; }
.contact-row-body a:hover { text-decoration: underline; }
.contact-row-label { display: block; font-size: 13px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-soft); margin-bottom: 2px; }

.contact-form {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 28px 32px 32px;
    box-shadow: var(--shadow-soft);
}

.contact-form h2 { margin-bottom: 4px; }
.contact-form form label:first-of-type { margin-top: 12px; }

@media (max-width: 540px) {
    .contact-card { padding: 20px; }
    .contact-form { padding: 22px 20px 24px; }
}

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

form label {
    display: block;
    font-weight: 600;
    font-size: 14.5px;
    margin: 16px 0 6px;
}

form input[type="text"],
form input[type="email"],
form input[type="tel"],
form input[type="password"],
form input[type="number"],
form input:not([type]),
form select,
form textarea {
    width: 100%;
    padding: 11px 14px;
    border: 1.5px solid var(--line);
    border-radius: 8px;
    font: inherit;
    color: var(--ink);
    background: var(--paper);
    transition: border-color 140ms ease, box-shadow 140ms ease;
}

form input:focus, form select:focus, form textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 4px var(--accent-tint);
}

form button[type="submit"] { margin-top: 20px; }

.field-error { color: var(--danger); font-size: 14px; }
.field-error ul { margin: 0; padding-left: 18px; }
.field-hint { color: var(--ink-soft); font-size: 13.5px; margin: 6px 0 0; }

.check-line {
    display: flex !important;
    align-items: center;
    gap: 10px;
    font-weight: 500 !important;
}

.check-line input { width: auto !important; }

.notice-ok {
    background: var(--ok-tint);
    color: var(--ok-ink);
    border-radius: 8px;
    padding: 14px 18px;
    margin-bottom: 18px;
}

.notice-ok p { margin: 0; }

/* The same shape as .notice-ok, for the thing that went wrong: a failed test mail, a
   password this server cannot read. */
.notice-bad {
    background: var(--danger-tint);
    color: var(--danger);
    border-radius: 8px;
    padding: 14px 18px;
    margin-bottom: 18px;
}

.notice-bad p { margin: 0; }

/* ---- dealers ----------------------------------------------------------------------- */

/* The sign-in and register forms: one panel, narrow, centred. A two-field form spread
   across the full page width looks abandoned. */
.account-panel {
    max-width: 560px;
    margin: 0 auto;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 28px 32px 32px;
    box-shadow: var(--shadow-soft);
}

.account-panel h2 { margin-bottom: 6px; }
.account-panel .section-lead { margin-bottom: 8px; }
.account-panel .btn { margin-top: 20px; }

.account-switch {
    text-align: center;
    color: var(--ink-soft);
    margin: 20px 0 0;
    font-size: 15px;
}

/* A row of two fields side by side (name and company, password and its repeat). */
.field-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 16px;
}

@media (max-width: 540px) { .field-pair { grid-template-columns: 1fr; } }

/* The honeypot. Moved out of sight rather than display:none, which some bots check. */
.hp-field {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

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

.site-foot {
    background: var(--navy-deep);
    color: #b9c6d4;
    margin-top: 40px;
    font-size: 15px;
    /* A thread of the accent along the top edge, the one warm line on the navy. */
    border-top: 3px solid var(--accent);
}

/* The home page ends in the navy call-to-action band, and the footer should run straight
   on from it rather than leave a strip of page between two navy blocks. */
.cta-band + .site-foot, main:has(> .cta-band:last-child) + .site-foot { margin-top: 0; }

.foot-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr 1fr;
    gap: 32px;
    padding-top: 52px;
    padding-bottom: 28px;
}

.foot-name { color: #fff; font: 700 20px "Manrope", sans-serif; margin-bottom: 6px; letter-spacing: -0.01em; }
.foot-tag { margin: 0; max-width: 40ch; }
.foot-head { color: #fff; font-weight: 600; margin-bottom: 10px; font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; }
.site-foot a { color: #dce6ef; text-decoration: none; }
.site-foot a:hover { color: #fff; text-decoration: underline; }
.foot-links { display: flex; gap: 16px; flex-wrap: wrap; }

.foot-legal {
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    padding-top: 16px;
    padding-bottom: 20px;
    font-size: 13.5px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.foot-legal p { margin: 0; }

/* Quieter than the other footer links, which is the point: it is a staff door, not
   something to draw a customer's eye. Still a proper target size on a phone. */
.foot-sep { opacity: 0.4; margin: 0 6px; }

.foot-admin {
    color: #8ea3b8;
    text-decoration: none;
}

.foot-admin:hover { color: #dce6ef; text-decoration: underline; }

/* The "Built by Tolerance" credit, same shape as ChatBill's. */
.built-by {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}

.built-by img { height: 30px; width: auto; display: block; }

@media (max-width: 700px) { .foot-grid { grid-template-columns: 1fr; gap: 20px; } }

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

/* Everything above that moves is decoration. Anyone who has told their machine they
   would rather it did not gets the same page standing still. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation: none !important;
        transition: none !important;
    }
}

/* ---- admin ------------------------------------------------------------------------- */

body.admin { background: var(--paper-tint); font-family: system-ui, sans-serif; }
body.admin h1, body.admin h2, body.admin h3 { font-family: system-ui, sans-serif; }

/* The bar across the top holds the brand, the theme toggle and the way out; the
   sections themselves moved to the side menu below. Shorter than the public header,
   which has a logo to make room for. */
.admin-head { background: var(--admin-bar); }
.admin-head .head-row { min-height: 64px; }

.admin-brand {
    color: #fff;
    font-weight: 700;
    font-size: 18px;
    text-decoration: none;
}

.admin-brand span { color: var(--accent); }

.admin-head-tools { display: flex; align-items: center; gap: 18px; }
.admin-head-link { color: #dce6ef; text-decoration: none; font-size: 15px; }
.admin-head-link:hover { color: #fff; }

.inline-form { display: inline; }

.link-button {
    background: none;
    border: none;
    color: #dce6ef;
    font: inherit;
    font-size: 15px;
    cursor: pointer;
    padding: 0;
}

/* The theme toggle, the same control ChatBill's navbar has. Which glyph is showing says
   what a click does: a moon ("switch to dark") in light mode, a sun in dark. Swapped by
   the attribute theme.js sets on <html>. Declared here in the admin block in the bar's
   own inks; the public header's version below repaints it for a paper background. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 6px;
    background: transparent;
    color: #dce6ef;
    cursor: pointer;
}

.theme-toggle:hover, .theme-toggle:focus-visible { border-color: #fff; color: #fff; }
.theme-toggle-icon { width: 18px; height: 18px; }
.theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* The same button in the public header, which is paper rather than navy. */
.site-head .theme-toggle { border-color: var(--line); color: var(--ink-soft); }
.site-head .theme-toggle:hover, .site-head .theme-toggle:focus-visible { border-color: var(--heading); color: var(--heading); }

/* ---- admin side menu ---- */

/* The page beside its menu, the shape ChatBill's signed-in pages have: a 220px column
   of sections on the left, sticky so it stays put while a long list scrolls, and the
   page taking the rest. Only when there is a menu: the login page has none and keeps
   the plain block layout. */
.admin-shell { padding-top: 24px; padding-bottom: 60px; }
.admin-shell:has(> .admin-side) { display: flex; align-items: flex-start; gap: 28px; }
/* min-width: 0, or a wide row inside main refuses to shrink and shoves the menu off. */
.admin-shell:has(> .admin-side) > .admin-main { flex: 1 1 auto; min-width: 0; }
.admin-main { padding: 0; }

.admin-side {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 0 0 220px;
    position: sticky;
    top: 24px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 10px;
    box-shadow: var(--shadow);
}

.admin-side a {
    padding: 10px 14px;
    border-radius: 6px;
    color: var(--ink);
    font-weight: 600;
    font-size: 14.5px;
    text-decoration: none;
}

.admin-side a:hover { background: var(--paper-tint); color: var(--side-active-ink); }
.admin-side a.active { background: var(--side-active-bg); color: var(--side-active-ink); }

/* The account-ish entries (dealers, backups, password) set apart from the pages by a
   rule and a little air, the way ChatBill separates "My profile" from the work. */
.admin-side-rule { margin-top: 6px; padding-top: 14px !important; border-top: 1px solid var(--line); border-radius: 0 0 6px 6px !important; }

/* Narrow screens: the same links as a wrapping strip above the page rather than a
   column beside it, which would leave a 400px phone with nothing to put the page in.
   Still every section, one tap away, no menu to open. */
@media (max-width: 900px) {
    .admin-shell:has(> .admin-side) { display: block; }
    .admin-side {
        position: static;
        flex-direction: row;
        flex-wrap: wrap;
        gap: 6px;
        margin-bottom: 20px;
    }
    .admin-side a { padding: 7px 12px; font-size: 14px; }
    .admin-side-rule { margin-top: 0; padding-top: 7px !important; border-top: none; border-radius: 6px !important; }
}

.admin-lead { color: var(--ink-soft); }
.admin-narrow { max-width: 420px; }

/* ---- dashboard tiles ---- */

/* A fixed four across rather than as-many-as-fit, so a group of one tile (Backups) and a
   group of four are cut from the same grid and every tile on the page is the same width.
   Equal rows and a minimum height do the same for height: a tile with a two-line label
   and a tile with a one-word label must not be different sizes. */
.admin-tiles {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: 1fr;
    gap: 16px;
    margin-top: 12px;
    margin-bottom: 28px;
}

@media (max-width: 1100px) { .admin-tiles { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px) { .admin-tiles { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 420px) { .admin-tiles { grid-template-columns: 1fr; } }

.admin-group {
    font-size: 15px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--ink-soft);
    margin: 0;
}

.admin-tile {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 20px 24px;
    text-decoration: none;
    color: var(--ink);
    min-height: 124px;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    transition: box-shadow 120ms ease, border-color 120ms ease;
}

.admin-tile:hover { box-shadow: var(--shadow); border-color: var(--side-active-ink); }
.admin-tile strong { display: block; font-size: 30px; line-height: 1.1; color: var(--heading); margin-bottom: 6px; }
.admin-tile span { font-weight: 600; }
.admin-tile small { display: block; color: var(--ink-soft); font-size: 13px; font-weight: 500; margin-top: 2px; }

.admin-title-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}

.admin-list { display: grid; gap: 12px; }

.admin-item {
    display: flex;
    align-items: center;
    gap: 16px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 14px 18px;
    flex-wrap: wrap;
}

.admin-thumb {
    width: 72px;
    height: 48px;
    object-fit: cover;
    border-radius: 6px;
}

/* A client's logo, unlike a product photo, must not be cropped to fill: half a wordmark
   is not a recognisable company. */
.admin-thumb-contain {
    object-fit: contain;
    background: var(--paper);
}

.admin-logo-preview {
    max-width: 240px;
    max-height: 90px;
    width: auto;
    object-fit: contain;
}

.admin-item-body { flex: 1; min-width: 200px; }
.admin-item-title { font-weight: 600; margin: 0; }
.admin-item-meta { color: var(--ink-soft); font-size: 13.5px; margin: 0; }
.admin-item-actions { display: flex; gap: 8px; }

.tag-hidden {
    background: var(--danger-tint);
    color: var(--danger);
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    padding: 2px 10px;
    margin-left: 8px;
    vertical-align: middle;
}

/* An informational tag, where .tag-hidden is a warning one. */
.tag-note {
    background: var(--paper-tint);
    color: var(--ink-soft);
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    padding: 2px 10px;
    margin-left: 8px;
    vertical-align: middle;
}

/* The pick-and-upload strip at the top of the admin gallery. */
.admin-upload-strip {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 16px 18px;
    margin-bottom: 20px;
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.admin-upload-strip input[type="file"] { flex: 1; min-width: 220px; }
.admin-upload-strip .field-hint { width: 100%; margin: 0; }
.admin-upload-strip .btn { margin: 0; }

.admin-form { max-width: 640px; }
.admin-form-actions { display: flex; gap: 12px; margin-top: 24px; }

/* The one line at the foot of a site-text form that applies to every box above it. */
.admin-form-note { margin-top: 20px; }
.admin-form-actions .btn { margin-top: 0; }

.admin-current-photo { margin: 8px 0 12px; }
.admin-current-photo img { max-width: 240px; border-radius: 8px; margin-bottom: 8px; }

.admin-confirm {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 22px 26px;
    max-width: 560px;
}
