﻿/* ==========================================================================
   Site styles.

   Every visual rule lives here. There is no inline style anywhere in the
   views, and the HTML sanitiser strips style attributes from article bodies,
   so this file is the only thing that decides how the site looks.

   Bootstrap 5.3 is loaded first; this layers on top of it. Colours are CSS
   custom properties, so rebranding a new site built on this engine is a
   matter of changing the values in :root.

   THE DIVISION OF LABOUR, which is the rule to keep:

     Bootstrap owns LAYOUT.  container, row, col-*, d-flex, flex-*, gap-*,
                             justify-*, align-*, the spacing scale, the grid
                             breakpoints, table-responsive, img-fluid.
     This file owns SKIN.    colour, border, radius, shadow, type scale,
                             bespoke spacing values the Bootstrap scale has no
                             step for, and Bootstrap's own --bs-* variables.

   So a flex row is written `class="d-flex flex-wrap gap-3"` in the view, not
   `display: flex` in here. The point is not purity: two systems both laying out
   the same element is how a page ends up responsive in one place and not the
   other, and the one that loses is always the phone.

   If you find yourself writing display:flex, display:grid, justify-content or a
   media query for a breakpoint here, that belongs in the markup as a utility.
   ========================================================================== */

:root {
    /* Brand. Change these four and the site changes. */
    --brand:            #0b4f6c;
    --brand-dark:       #073b52;
    --brand-accent:     #ff7a1a;
    --brand-contrast:   #ffffff;

    --ink:              #16202a;
    --ink-muted:        #5a6a78;
    --rule:             #dfe5ea;
    --surface:          #ffffff;
    --surface-alt:      #f4f7f9;

    --radius:           .625rem;
    --shadow-sm:        0 1px 2px rgba(16, 32, 42, .06);
    --shadow-md:        0 6px 20px rgba(16, 32, 42, .10);

    --measure:          68ch;

    /* Bootstrap component overrides, so buttons and links pick up the brand. */
    --bs-primary:       var(--brand);
    --bs-link-color:    var(--brand);
    --bs-link-hover-color: var(--brand-dark);
    --bs-body-color:    var(--ink);
    --bs-border-color:  var(--rule);
}

body {
    color: var(--ink);
    background: var(--surface);
    font-size: 1.0625rem;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

.btn-primary {
    --bs-btn-bg: var(--brand);
    --bs-btn-border-color: var(--brand);
    --bs-btn-hover-bg: var(--brand-dark);
    --bs-btn-hover-border-color: var(--brand-dark);
    --bs-btn-active-bg: var(--brand-dark);
    --bs-btn-active-border-color: var(--brand-dark);
}

/* --- service cards on the home page ---------------------------------------
   Skin only. Bootstrap's row and h-100 do the grid and the equal heights. */

.service-card {
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 1.25rem 1.25rem 1rem;
}

.service-card-title { font-size: 1.125rem; font-weight: 700; margin-bottom: .5rem; }
.service-card-title a { text-decoration: none; }
.service-card-title a:hover { text-decoration: underline; }
.service-card-text { color: var(--ink-muted); margin-bottom: 0; }

/* --- the two quote buttons on the currency pages --------------------------
   Orange for currency, green for the move, so the pair reads as two different
   things at a glance rather than as one button repeated.

   These are darker than the orange and green most people reach for, and
   deliberately. White text on a bright orange fails contrast at the sizes used
   here, and a colour that only some readers can read is not a colour choice.
   Both clear 4.5:1 against white text.

   Bootstrap's own variables do the work, so size, radius, focus and disabled
   states all come from .btn and only the colour lives here. */

:root {
    --quote-currency:      #c2410c;
    --quote-currency-dark: #9a3412;
    --quote-moving:        #15803d;
    --quote-moving-dark:   #166534;
}

.btn-quote-currency,
.btn-quote-moving {
    --bs-btn-color: #fff;
    --bs-btn-hover-color: #fff;
    --bs-btn-active-color: #fff;
    font-weight: 600;
}

.btn-quote-currency {
    --bs-btn-bg: var(--quote-currency);
    --bs-btn-border-color: var(--quote-currency);
    --bs-btn-hover-bg: var(--quote-currency-dark);
    --bs-btn-hover-border-color: var(--quote-currency-dark);
    --bs-btn-active-bg: var(--quote-currency-dark);
    --bs-btn-active-border-color: var(--quote-currency-dark);
}

.btn-quote-moving {
    --bs-btn-bg: var(--quote-moving);
    --bs-btn-border-color: var(--quote-moving);
    --bs-btn-hover-bg: var(--quote-moving-dark);
    --bs-btn-hover-border-color: var(--quote-moving-dark);
    --bs-btn-active-bg: var(--quote-moving-dark);
    --bs-btn-active-border-color: var(--quote-moving-dark);
}

/* --- focus and touch ------------------------------------------------------
   Keyboard users need to see where they are. :focus-visible rather than :focus
   so a mouse click does not leave a ring behind, which is why authors reach for
   outline:none and break keyboard navigation entirely. */

:focus-visible {
    outline: 3px solid var(--brand-accent);
    outline-offset: 2px;
    border-radius: 2px;
}

/* A finger is about 9mm. On a touch screen every control gets a 44px target,
   which is the one accessibility rule that is also plainly a usability one:
   below it, people mis-tap and give up on the form. */
@media (pointer: coarse) {
    .btn,
    .nav-link,
    .page-link,
    .form-control,
    .form-select {
        min-height: 44px;
    }

    .btn-sm {
        min-height: 40px;
        padding-inline: .875rem;
    }
    .topbar a {
        display: inline-block;
        padding-block: .5rem;
    }
}

.skip-link {
    position: absolute;
    top: .5rem;
    left: .5rem;
    z-index: 1080;
    padding: .5rem .875rem;
    background: var(--brand);
    color: var(--brand-contrast);
    border-radius: var(--radius);
}

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

.topbar {
    background: var(--brand-dark);
    color: rgba(255, 255, 255, .88);
    font-size: .875rem;
    padding: .4rem 0;
}
.topbar a       { color: #fff; text-decoration: none; font-weight: 600; }
.topbar a:hover { text-decoration: underline; }
.topbar-sep     { opacity: .5; margin: 0 .35rem; }

/* The bar carries no text now, so it needs its own height. Without this the padding
   collapses around nothing and the band disappears, which is not what an empty bar
   is for. */
.topbar-empty   { height: 1.75rem; padding: 0; }

/* The logo is square-ish, so it needs a little more height than a wordmark would
   to stay legible. The navbar padding comes down to match, which keeps the header
   the same overall height as before. */
.site-header .navbar { padding-block: .5rem; }
.site-logo           { height: 60px; width: auto; }

.navbar-brand        { font-weight: 700; color: var(--brand); }
.nav-link            { font-weight: 500; color: var(--ink); }
.nav-link:hover,
.nav-link:focus      { color: var(--brand); }

.nav-search          { margin: .25rem .75rem; }
.nav-search .form-control { min-width: 11rem; }
.nav-cta             { white-space: nowrap; }

.breadcrumb-bar {
    background: var(--surface-alt);
    border-bottom: 1px solid var(--rule);
    padding: .625rem 0;
    font-size: .875rem;
}
.breadcrumb-bar .breadcrumb-item a { color: var(--ink-muted); text-decoration: none; }
.breadcrumb-bar .breadcrumb-item a:hover { color: var(--brand); text-decoration: underline; }

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

.hero {
    background: linear-gradient(140deg, var(--brand) 0%, var(--brand-dark) 100%);
    color: var(--brand-contrast);
    padding: clamp(2.5rem, 6vw, 4.5rem) 0;
}
.hero-eyebrow {
    text-transform: uppercase;
    letter-spacing: .08em;
    font-size: .8125rem;
    font-weight: 700;
    opacity: .82;
    margin-bottom: .5rem;
}
.hero-title {
    font-size: clamp(1.9rem, 4.5vw, 3rem);
    font-weight: 800;
    line-height: 1.15;
    margin-bottom: .75rem;
    max-width: 22ch;
}
.hero-lead  { font-size: 1.15rem; opacity: .92; max-width: 58ch; margin-bottom: 1.5rem; }
/* Layout comes from Bootstrap: d-flex flex-wrap gap-3 on the element itself. */

/* --- sections and headings ---------------------------------------------- */

.section        { padding-block: clamp(2rem, 5vw, 3.5rem); }
.section-heading{ font-size: 1.5rem; font-weight: 700; margin-bottom: 1.5rem; }
.page-title     { font-size: clamp(1.75rem, 4vw, 2.5rem); font-weight: 800; line-height: 1.2; margin-bottom: .75rem; }
.page-intro     { font-size: 1.125rem; color: var(--ink-muted); max-width: var(--measure); margin-bottom: 2rem; }
.empty-state    { color: var(--ink-muted); padding: 2rem 0; }

/* --- article cards ------------------------------------------------------- */

/* Skin only. The column layout is Bootstrap's d-flex flex-column on the element. */
.article-card {
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    transition: box-shadow .18s ease, transform .18s ease;
}
.article-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }

.article-card-media img {
    display: block;
    width: 100%;
    /* Reserving the box stops the card shifting as images load, which is what
       keeps cumulative layout shift at zero on the listing pages. */
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

/* Padding is a bespoke value, so it stays here; the flex-column and flex-grow-1
   come from Bootstrap on the element. */
.article-card-body   { padding: 1.125rem 1.25rem 1.25rem; }
.article-card-category {
    display: inline-block;
    font-size: .75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--brand-accent);
    text-decoration: none;
    margin-bottom: .5rem;
}
.article-card-title  { font-size: 1.1875rem; font-weight: 700; line-height: 1.3; margin-bottom: .5rem; }
.article-card-title a{ color: var(--ink); text-decoration: none; }
.article-card-title a:hover { color: var(--brand); }
.article-card-excerpt{ color: var(--ink-muted); font-size: .9375rem; margin-bottom: 1rem; }
.article-card-meta   { font-size: .8125rem; color: var(--ink-muted); margin: auto 0 0; }
.article-card-sep    { margin: 0 .4rem; opacity: .6; }

/* --- article page -------------------------------------------------------- */

/* The article page matches the home page's content area exactly - 1320px, which is
   1296px of content once the container's 12px side padding comes off. Same width as
   the "Latest articles" grid, so an article and the listing it came from line up.

   Stated rather than left to Bootstrap's default on purpose: this is a decision
   about how wide an article should be, and the next person to read this file should
   see it made here rather than have to infer it from the absence of a rule.

   The reading column lands at ~864px, near 110 characters a line. That is wider
   than the 50-75 typography usually recommends; the trade is a page that fills the
   screen. Narrow the column to col-lg-7 in Article.cshtml if it reads heavy. */
.article-detail  { max-width: 1320px; }
.article-header  { margin-bottom: 1.5rem; }
.article-category{
    display: inline-block;
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--brand-accent);
    text-decoration: none;
    margin-bottom: .625rem;
}
.article-title   { font-size: clamp(1.9rem, 4.5vw, 2.75rem); font-weight: 800; line-height: 1.18; margin-bottom: .75rem; }
.article-meta    { font-size: .9375rem; color: var(--ink-muted); }
.article-meta-sep{ margin: 0 .45rem; opacity: .6; }

.article-figure       { margin: 0 0 2rem; }
.article-figure img   { width: 100%; height: auto; border-radius: var(--radius); aspect-ratio: 16 / 9; object-fit: cover; }

/* The column is the measure now. Eight of twelve inside the standard container is
   roughly 620px at the large breakpoint and 860px at the largest, which keeps the
   line length in the comfortable range without a second cap fighting it and
   leaving a gap down the right of the text. */
.article-body { font-size: 1.0625rem; max-width: none; }

/* Media breaks out of the measure and uses the column. This is the point of the
   wider layout: the text stays readable while the pictures get the room. */
.article-body figure,
.article-body .table-responsive,
.article-body > img,
.article-body pre { max-width: none; }

/* A lead paragraph, set larger. Every article has an excerpt, so this is the one
   element that makes the top of every article look the same. */
.article-standfirst {
    font-size: 1.1875rem;
    line-height: 1.55;
    color: var(--ink-muted);
    max-width: none;
    margin: 0 0 1rem;
}

/* --- contents ------------------------------------------------------------- */

.article-contents {
    position: sticky;
    top: 1.5rem;
    border-left: 3px solid var(--rule);
    padding: .25rem 0 .25rem 1rem;
    max-height: calc(100vh - 3rem);
    overflow-y: auto;
}
.article-contents-heading {
    font-size: .6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ink-muted);
    margin-bottom: .5rem;
}
.article-contents-list {
    list-style: none;
    padding: 0;
    margin: 0;
    counter-reset: none;
}
.article-contents-list li { margin-bottom: .4rem; line-height: 1.35; }
.article-contents-list a {
    font-size: .8125rem;
    color: var(--ink-muted);
    text-decoration: none;
}
.article-contents-list a:hover { color: var(--brand); text-decoration: underline; }
.article-contents-l3 { padding-left: .75rem; }
.article-contents-l3 a { font-size: .75rem; }

.article-contents-inline {
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: .625rem .875rem;
    margin-bottom: 1.5rem;
    background: var(--surface-alt);
}
.article-contents-inline summary {
    cursor: pointer;
    font-weight: 700;
    font-size: .875rem;
    color: var(--brand);
}
.article-contents-inline .article-contents-list { margin-top: .625rem; }

/* Anchored headings must not land under a sticky header when jumped to. */
.article-body h2,
.article-body h3 { scroll-margin-top: 1.5rem; }

.article-footer {
    border-top: 1px solid var(--rule);
    margin-top: 2.5rem;
    padding-top: 1rem;
    max-width: none;
}
.article-footer-dates { font-size: .8125rem; color: var(--ink-muted); }
.article-body > * + * { margin-top: 1.125rem; }
.article-body h2 { font-size: 1.5rem;   font-weight: 700; margin-top: 2.25rem; line-height: 1.3; }
.article-body h3 { font-size: 1.25rem;  font-weight: 700; margin-top: 1.75rem; line-height: 1.35; }
.article-body h4 { font-size: 1.0625rem;font-weight: 700; margin-top: 1.5rem; }
.article-body ul,
.article-body ol { padding-left: 1.35rem; }
.article-body li + li { margin-top: .4rem; }
.article-body img { max-width: 100%; height: auto; border-radius: var(--radius); }
.article-body a   { color: var(--brand); text-underline-offset: .15em; }
.article-body blockquote {
    border-left: 4px solid var(--brand-accent);
    padding: .25rem 0 .25rem 1.125rem;
    color: var(--ink-muted);
    font-style: italic;
}
.article-body table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.article-body th,
.article-body td    { border: 1px solid var(--rule); padding: .55rem .7rem; text-align: left; }
.article-body thead th { background: var(--surface-alt); font-weight: 700; }



.related { margin-top: 3.5rem; }

/* --- pagination ---------------------------------------------------------- */

.pagination-nav { margin-top: 2.5rem; }
.pagination .page-link { color: var(--brand); }
.pagination .page-item.active .page-link {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--brand-contrast);
}

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

/* .form-section is defined once, with its accent colours, further down. */
.form-legend  { float: none; width: auto; padding: 0 .5rem; font-size: 1rem; font-weight: 700; color: var(--brand); }

/* Quote form. Skin only - the grid and the spacing are Bootstrap's. */

/* --- quote form sections -------------------------------------------------
   Each step gets its own accent colour, so the eye can tell at a glance where one
   question ends and the next begins. The colour is carried on a left edge and a
   very light tint rather than a filled panel: a form of six saturated blocks is
   harder to read, not easier.

   Every accent is dark enough for its own legend text to clear 4.5:1 on the tint,
   and the tints sit at 5% so the field borders still read. Colour is never the only
   signal - the steps are numbered too, which is what a colour-blind reader uses. */

.form-section {
    --section-accent: var(--brand);
    border: 1px solid var(--rule);
    border-left: 4px solid var(--section-accent);
    border-radius: var(--radius);
    background: var(--surface-alt);
    padding: 1rem 1.125rem 1.125rem;
    margin-bottom: 1rem;
}

.form-section-1 { --section-accent: #0b4f6c; background: rgba(11, 79, 108, .05); }
.form-section-2 { --section-accent: #1b7a5a; background: rgba(27, 122, 90, .05); }
.form-section-3 { --section-accent: #3f51a3; background: rgba(63, 81, 163, .05); }
.form-section-4 { --section-accent: #a75a12; background: rgba(167, 90, 18, .05); }
.form-section-5 { --section-accent: #6b4a9e; background: rgba(107, 74, 158, .05); }
.form-section-6 { --section-accent: #3d6070; background: rgba(61, 96, 112, .05); }

.form-section .form-legend { color: var(--section-accent); }

/* The quote page intro, set small and across the full column.
   .page-intro caps its width at 68ch, which is right for an article but makes this
   one sentence wrap over three lines and push the form down. Removing the cap and
   dropping to 12px fits it on one or two lines with nothing truncated, so the form
   starts higher up the page. Defined after .page-intro so it wins on order. */
.page-intro-sm {
    font-size: .75rem;
    line-height: 1.5;
    max-width: none;
}

/* Compact by default on a pointer device. The coarse-pointer block above still
   lifts every control back to a 44px target on a touch screen, so this trades
   density on a desktop for nothing on a phone. */
.quote-form .form-label { margin-bottom: .2rem; font-size: .875rem; font-weight: 600; }
.quote-form .form-text  { margin-top: .15rem; font-size: .75rem; }
.quote-form .form-control,
.quote-form .form-select { padding: .375rem .625rem; }

/* --- size estimator -------------------------------------------------------
   Skin only; the grid inside it is Bootstrap's. Kept visually quieter than the
   form itself, because it is a helper and not a step. */

.size-estimator {
    border: 1px dashed var(--section-accent, var(--brand));
    border-radius: var(--radius);
    background: var(--surface);
}
.size-estimator-toggle {
    cursor: pointer;
    padding: .5rem .75rem;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--section-accent, var(--brand));
}
.size-estimator-body   { padding: 0 .75rem .75rem; }
.size-estimator-group  {
    font-size: .6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-muted);
    margin: .5rem 0 .25rem;
}
.size-estimator .form-label { font-size: .75rem; margin-bottom: .1rem; }
.size-estimator .form-control { padding: .25rem .5rem; font-size: .8125rem; }

.size-estimator-result {
    border-top: 1px solid var(--rule);
    padding-top: .625rem;
    margin-top: .25rem;
}
.size-estimator-total  { font-size: 1rem; }
.size-estimator-advice { font-size: .8125rem; color: var(--ink-muted); }
.size-estimator-note   { font-size: .6875rem; color: var(--ink-muted); margin-top: .5rem; }

/* Required-field marker. Red on white here is 4.5:1, but colour is never the only
   signal - each marked label also carries a visually-hidden "required", and the
   fields have the required attribute for anything reading the markup. */
.required-mark {
    color: #d6343d;
    font-weight: 700;
    margin-left: .15rem;
}

.form-required-note {
    font-size: .875rem;
    color: var(--ink-muted);
}
.form-required-note .required-mark { margin-left: 0; margin-right: .15rem; }

.form-legend-optional {
    font-weight: 500;
    font-size: .8125rem;
    color: var(--ink-muted);
    text-transform: uppercase;
    letter-spacing: .06em;
    margin-left: .5rem;
}

/* The extras read as one tickable block rather than four loose checkboxes, which
   makes it obvious they are optional and related. */
.extra-check {
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: .625rem .75rem .625rem 2.25rem;
    background: var(--surface);
    height: 100%;
}
.extra-check:hover { border-color: var(--brand); }
.extra-check .form-check-input:checked ~ .form-check-label { font-weight: 600; color: var(--brand); }
.form-label   { font-weight: 600; font-size: .9375rem; }
.form-hint    { font-size: .8125rem; color: var(--ink-muted); margin: .35rem 0 0; }
.field-error  { display: block; color: #b42318; font-size: .8125rem; margin-top: .25rem; }
.search-form  { max-width: 30rem; margin-bottom: 2rem; }
.auth-form,
.admin-form   { margin-top: 1.5rem; }

.form-control:focus,
.form-select:focus {
    border-color: var(--brand);
    box-shadow: 0 0 0 .2rem rgba(11, 79, 108, .15);
}

/* Honeypot. Off-screen rather than display:none, because some bots skip
   anything that is not rendered. Real people never reach it. */
.hp-field {
    position: absolute !important;
    left: -9999px !important;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

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

.admin-bar     { /* layout via Bootstrap utilities on the element */ }
.admin-actions { /* layout via Bootstrap utilities on the element */ }
.admin-table   { font-size: .9375rem; }
.admin-slug    { display: block; font-size: .8125rem; color: var(--ink-muted); }
.admin-panel   {
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 1.125rem 1.25rem;
    margin-bottom: 1.25rem;
    background: var(--surface-alt);
}
.admin-panel-title { font-size: .9375rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-muted); margin-bottom: 1rem; }
.code-area     { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .875rem; line-height: 1.5; }

.badge.status-published { background: #0f7b40; }
.badge.status-draft     { background: #8a6d1f; }
.badge.status-archived  { background: #5a6a78; }

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

.site-footer {
    background: var(--brand-dark);
    color: rgba(255, 255, 255, .82);
    padding: clamp(2.25rem, 5vw, 3.5rem) 0 1.5rem;
    margin-top: 4rem;
}
.footer-heading { font-size: .9375rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #fff; margin-bottom: 1rem; }
.footer-text    { font-size: .9375rem; font-style: normal; }
.footer-list    { list-style: none; padding: 0; margin: 0; font-size: .9375rem; }
.footer-list li + li { margin-top: .5rem; }
.footer-list a,
.site-footer a  { color: rgba(255, 255, 255, .82); text-decoration: none; }
.footer-list a:hover,
.site-footer a:hover { color: #fff; text-decoration: underline; }
.footer-bottom  {
    border-top: 1px solid rgba(255, 255, 255, .16);
    margin-top: 2.5rem;
    padding-top: 1.25rem;
    font-size: .8125rem;
    opacity: .78;
}

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

@media print {
    .topbar, .site-header, .site-footer, .breadcrumb-bar,
    .related, .pagination-nav { display: none !important; }
    .article-body { max-width: none; }
}

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

@media (prefers-reduced-motion: reduce) {
    * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
    .article-card:hover { transform: none; }
}
