@charset "UTF-8";
/*!
    Main Stylesheet Manifest

    This file imports all SCSS partials in the correct order.
    DO NOT add styles here — use the appropriate partial instead.

    Compile: sass --watch css:css

    Import order:
        1. Fonts & Variables (design tokens)
        2. Helpers (mixins & utilities)
        3. Utility classes (colors, typography)
        4. Base element styles
        5. Components (reusable patterns)
        6. Sections (ACF flexible content)
        7. Page-specific overrides

    @author development@bronte.co.nz
*/
/*
    Font Face Declarations

    Define custom web fonts here using @font-face.
    Font files should be stored in /assets/fonts/ or loaded from CDN.

    After adding fonts, update $font-family-primary or $font-family-secondary
    in _variables.scss to use them.

    Example:
        @font-face {
            font-family: 'CustomFont';
            src: url('../assets/fonts/custom.woff2') format('woff2'),
                 url('../assets/fonts/custom.woff') format('woff');
            font-weight: 400;
            font-style: normal;
            font-display: swap;
        }
*/
/*
    Proxima Nova — the Bronte brand font (self-hosted, D-04).

    Reconciled 2026-07-25 against the Bronte Design System export
    (.planning/design/_ds/.../colors_and_type.css). The .ttf weights (300–800)
    ship in the export and are copied into the theme's /fonts/ directory; this
    block mirrors the export's @font-face declarations verbatim. Self-hosted —
    NEVER a render-blocking third-party font CDN (T-05-31). `font-display: swap`
    keeps text visible while the face loads.

    Paths are relative to the compiled stylesheet (css/style.css) -> ../fonts/.
    $font-family-primary in _variables.scss already points at 'proxima-nova'.
*/
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-Light.ttf") format("truetype");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-LightItalic.ttf") format("truetype");
  font-weight: 300;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-Italic.ttf") format("truetype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-Medium.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-MediumItalic.ttf") format("truetype");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-Semibold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-SemiboldItalic.ttf") format("truetype");
  font-weight: 600;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-BoldItalic.ttf") format("truetype");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-Extrabold.ttf") format("truetype");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "proxima-nova";
  src: url("../fonts/ProximaNova-ExtraboldItalic.ttf") format("truetype");
  font-weight: 800;
  font-style: italic;
  font-display: swap;
}
/*
    Design Tokens (Variables)

    Central source of truth for all design values.
    ALWAYS check here before adding new values elsewhere.

    Source of truth: the Bronte Design System export
    (.planning/design/_ds/bronte-design-system-.../colors_and_type.css), itself
    lifted from the bronte.co.nz theme (_variables.scss / _general.scss /
    _buttons.scss). These were reconciled against the real brand on 2026-07-25
    (Phase 5, D-04) — the previous values were a generic starter palette
    (green primary, Helvetica) that did NOT match the brand.

    How to use:
        1. Import in your partial: @use 'variables' as *;
        2. Use variables: color: $color-primary;

    Naming conventions:
        $color-{name}      — colours
        $spacing-{size}    — spacing (xs, sm, md, lg, xl, 2xl, 3xl, 4xl)
        $font-size-{size}  — font sizes
        $font-weight-{name} — font weights
        $screen-{size}     — breakpoints
*/
/*  ===== BRAND COLOURS =====
    The Bronte accent is CORAL/ORANGE, not green. Green is a *status* colour
    only (see the semantic-status scale below), never the brand accent. */
/*  ===== SEMANTIC STATUS SCALE =====
    Data-encoding only (score bands, uptime, freshness). Status colour is
    MEANING, never decoration — never used as the brand accent. */
/*  ===== CATEGORICAL BREAKDOWN RAMP (Phase 7) =====
    NOT the semantic status scale above, and never to be swapped for it.

    The five GTmetrix page-load segments (HTML / CSS / JavaScript / Images / Other)
    are CATEGORIES, not judgements. Painting "Images" with $color-poor because red
    happened to be the fourth colour to hand would tell an admin the site is failing
    when it is merely image-heavy — status colour is meaning, and these segments carry
    none. See 07-UI-SPEC.md §Color → "The breakdown bar's five segments".

    A monotonic dark→light ramp is distinguishable by LUMINANCE in greyscale and on a
    printed report, is unmistakably categorical rather than semantic (nobody reads a
    grey ramp as pass/fail),
    and reuses three values the palette already holds. It pairs with a legend carrying
    each percentage as visible text, so colour is never load-bearing. */
/*  ===== SIGNATURE SHADOWS =====
    Bronte cards use a deeply-layered, very soft "floating" shadow. */
/*  ===== DASHBOARD LAYOUT (Phase 5, D-04/D-05) =====
    Chrome constants for the app-shell, reconciled against the exported design
    (.planning/design/ — the dark slate nav rail + light top bar in the Overview
    screenshot). The rail is the fixed dark "30%" chrome; the canvas is the light
    "60%" bulk; the coral accent stays the scarce "10%". */
/*
    Helper Utilities

    Layout, positioning, and display utilities.
    For typography utilities, see _typography.scss.
    For colour utilities, see _colors.scss.

    Usage:
        <div class="pos-relative">
            <img class="bg-image" src="..." alt="...">
            <div class="z-above">Content above image</div>
        </div>
*/
.w-100 {
  width: 100%;
}

.h-100 {
  height: 100%;
}

.pos-relative {
  position: relative;
}

.pos-absolute {
  position: absolute;
}

.z-below {
  z-index: 5;
}

.z-base {
  z-index: 10;
}

.z-above {
  z-index: 15;
}

.mb-0 {
  margin-bottom: 0;
}

.last-child-mb-0 > :last-child {
  margin-bottom: 0;
}

/*  Accessibility

    .baseline-sr-only — the visually-hidden utility every status mark depends on.

    Why a NEW class rather than reusing something: 07-UI-SPEC.md §"As-built reality"
    row 3 established two facts. First, .screen-reader-text is NOT defined anywhere in
    this theme's SCSS even though partials/data-table.php already emits it — so that
    text is almost certainly visible on screen today. Second, %visually-hidden in
    _forms.scss is a Sass PLACEHOLDER: @extend cannot cross module boundaries under
    @use, so no component partial can reach it. Do NOT try to @extend it here.

    _helpers.scss is already @use'd by style.scss (line 24), so this ships with no
    manifest change and is available to every partial and template.

    It exists so a status mark can carry its meaning as a word: the source-panel item
    mark is a real text glyph followed by a .baseline-sr-only span ("Pass" / "Warning" /
    "Fail" / "Not collected"), which is what stops the five status tones encoding
    meaning by colour alone.

    clip-path: inset(50%) is the modern recipe; the deprecated clip: rect() is kept
    beside it for older engines, exactly as _forms.scss does. */
.baseline-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.bg-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
}

/*
    Colour Utility Classes

    Background and text colour utilities generated from $colors map.
    All colours are defined in _variables.scss.

    Usage:
        <div class="bg-primary text-white">Primary background</div>
        <p class="text-muted">Secondary text</p>

    Available classes:
        .bg-{color}   — background colour
        .text-{color} — text colour

    Where {color} is: primary, secondary, dark, light, white, black, muted
*/
.bg-primary {
  background-color: #f86349;
}

.text-primary {
  color: #f86349;
}

.bg-secondary {
  background-color: #fff55a;
}

.text-secondary {
  color: #fff55a;
}

.bg-dark {
  background-color: #111111;
}

.text-dark {
  color: #111111;
}

.bg-light {
  background-color: #f6f9f9;
}

.text-light {
  color: #f6f9f9;
}

.bg-white {
  background-color: #fff;
}

.text-white {
  color: #fff;
}

.bg-black {
  background-color: #000;
}

.text-black {
  color: #000;
}

.bg-muted {
  background-color: #959a9e;
}

.text-muted {
  color: #959a9e;
}

/*
    Typography Utility Classes

    Apply these classes directly in HTML to control text appearance.
    All values come from _variables.scss for consistency.

    Usage:
        <p class="text-lg font-bold">Large bold text</p>
        <span class="text-muted text-sm">Small muted caption</span>
*/
.text-left {
  text-align: left;
}

.text-center {
  text-align: center;
}

.text-right {
  text-align: right;
}

.text-xs {
  font-size: 12px;
}

.text-sm {
  font-size: 14px;
}

.text-base {
  font-size: 16px;
}

.text-lg {
  font-size: 18px;
}

.text-xl {
  font-size: 24px;
}

.text-2xl {
  font-size: 32px;
}

.text-3xl {
  font-size: 36px;
}

.font-normal {
  font-weight: 400;
}

.font-medium {
  font-weight: 500;
}

.font-semibold {
  font-weight: 600;
}

.font-bold {
  font-weight: 700;
}

.leading-tight {
  line-height: 1.2;
}

.leading-base {
  line-height: 1.5;
}

.leading-loose {
  line-height: 1.8;
}

.font-primary {
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.font-secondary {
  font-family: Georgia, serif;
}

/*
    Button Styles

    Base button styles and variants.
    Applied to .btn class, <button>, and submit inputs.

    Usage:
        <a href="#" class="btn">Default button</a>
        <button class="btn btn-primary">Primary button</button>

    Add variants below as needed:
        .btn-primary  — primary colour button
        .btn-outline  — outlined button
        .btn-lg       — large button
*/
.btn,
button,
input[type=submit] {
  -webkit-appearance: none;
  border-radius: 0;
  display: inline-block;
  font-size: 16px;
  font-weight: 700;
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  padding: 8px 16px;
  line-height: 1.5;
  cursor: pointer;
  transition: 0.2s all;
  border: 0;
  text-transform: uppercase;
  text-align: center;
}
.btn:focus,
button:focus,
input[type=submit]:focus {
  outline: none;
}

/*
    Navigation Menu Styles

    Styles for WordPress menus registered in functions/setup.php.
    Menu locations: header, footer, mobile.

    Structure:
        <nav>
            <ul class="menu menu-main">
                <li><a href="#">Link</a></li>
            </ul>
        </nav>

    Modifiers:
        .menu-main   — header navigation
        .menu-footer — footer navigation
*/
.menu {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 14px;
}
.menu-main li {
  margin-left: 32px;
}
.menu-main a {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
}
.menu-footer {
  flex-direction: column;
}
.menu-footer li {
  margin-bottom: 8px;
  position: relative;
}
.menu-footer a {
  line-height: 1.428;
  font-weight: 400;
}

/*
    Base Element Styles

    Global styles for HTML elements (body, a, img, headings, etc.).
    These apply site-wide without needing classes.

    For utility classes, see:
        _helpers.scss    — layout utilities
        _typography.scss — text utilities
        _colors.scss     — colour utilities
*/
* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: var(--wp-admin--admin-bar--height); /**
* @link https://make.wordpress.org/core/2022/01/07/theme-focused-changes-and-filters-in-wordpress-5-9/#adjusting-for-fixed-header-navigation
*/
}

html,
body {
  min-height: 100vh;
}

body {
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  color: #111111;
  display: flex;
  flex-direction: column;
  margin: 0;
}

a {
  transition: all 0.2s ease-in-out;
  text-decoration: none;
}
a:hover {
  text-decoration: none;
}

main {
  flex: 1;
}

svg,
img {
  max-width: 100%;
  height: auto;
  display: block;
}

p img {
  display: inline-block;
}

.text > :first-child {
  margin-top: 0;
}
.text > :last-child {
  margin-bottom: 0;
}
.text ol,
.text ul {
  line-height: inherit;
  padding-left: 20px;
}
.text li:last-child {
  margin-bottom: 0;
}

h1,
h2,
h3,
h4,
h5 {
  margin-top: 0;
}

@media (min-width: 768px) {
  .alignleft,
  img.alignleft {
    float: left;
    margin-right: 1em;
    margin-bottom: 1em;
  }
}

@media (min-width: 768px) {
  .alignright,
  img.alignright {
    float: right;
    margin-left: 1em;
    margin-bottom: 1em;
  }
}

.aligncenter,
img.aligncenter {
  margin: 1em auto;
}

/*
    Site Header Styles

    Includes mobile menu, hamburger toggle, and header layout.
    The header element itself is in header.php.

    Key classes:
        .side-menu    — slide-out mobile menu panel
        .menu-opener  — hamburger icon (animates to X when open)
        .opened       — body class when menu is open
*/
.side-menu {
  position: fixed;
  pointer-events: none;
  top: 84px;
  right: 0;
  bottom: 0;
  z-index: 750;
  transition: all ease-in-out 0.4s;
  width: 100vw;
}
@media (min-width: 576px) {
  .side-menu {
    width: 410px;
  }
}
.side-menu .inner {
  background: #fff;
  height: calc(100vh - 72px);
  padding: 30px 12px;
  overflow: auto;
}

.opened .side-menu {
  transform: translateX(0) !important;
  pointer-events: all;
}

.menu-opener {
  z-index: 50;
  cursor: pointer;
  position: relative;
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border: 1px solid #fff;
  margin-left: auto;
}
.menu-opener:before, .menu-opener:after {
  content: "";
  backface-visibility: hidden;
  transition: all 0.4s;
  background: #fff;
  height: 1px;
  left: 9px;
  right: 9px;
  top: 13px;
  position: absolute;
}
.menu-opener:before {
  box-shadow: 0 13px 0 0 #fff;
}
.menu-opener:after {
  top: 19px;
}
.opened .menu-opener:before {
  box-shadow: 0 0 0 0 transparent;
  transform: rotate(225deg);
  top: 19px;
}
.opened .menu-opener:after {
  transform: rotate(315deg);
  top: 19px;
}

/*
    Site Footer Styles

    Styles for the site footer in footer.php.
    Add footer layout, widgets, and copyright styling here.
*/
/**
 * Gravity Forms - Orbital Theme Overrides
 *
 * Styles for GF 2.9+ Orbital theme.
 * Uses CSS custom properties to override Orbital defaults.
 *
 * Structure:
 *   1. CSS Custom Properties (theme-wide overrides)
 *   2. Direct Style Overrides (elements Orbital doesn't fully control)
 *   3. Validation & Error States
 *   4. Honeypot Field (spam protection)
 */
.gform_wrapper.gform-theme--orbital[data-form-index] {
  --gf-color-primary: #f86349;
  --gf-color-primary-rgb: 248, 99, 73;
  --gf-ctrl-label-font-family-primary: proxima-nova, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
  --gf-ctrl-label-font-size-primary: 14px;
  --gf-ctrl-label-font-weight-primary: 600;
  --gf-ctrl-label-color-primary: #111111;
  --gf-ctrl-font-family: proxima-nova, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
  --gf-ctrl-font-size: 16px;
  --gf-ctrl-line-height: 1.5;
  --gf-ctrl-color: #111111;
  --gf-ctrl-color-placeholder: #959a9e;
  --gf-ctrl-bg-color: #fff;
  --gf-ctrl-border-color: #cfd0d4;
  --gf-ctrl-border-width: 1px;
  --gf-ctrl-border-radius: 5px;
  --gf-ctrl-padding-x: 16px;
  --gf-ctrl-padding-y: 12px;
  --gf-ctrl-border-color-focus: #f86349;
  --gf-ctrl-focus-ring-color: rgba(248, 99, 73, 0.2);
  --gf-ctrl-select-color: #111111;
  --gf-ctrl-choice-label-color: #111111;
  --gf-ctrl-btn-font-family: proxima-nova, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
  --gf-ctrl-btn-font-size: 16px;
  --gf-ctrl-btn-font-weight: 600;
  --gf-ctrl-btn-color: #fff;
  --gf-ctrl-btn-color-hover: #fff;
  --gf-ctrl-btn-bg-color: #f86349;
  --gf-ctrl-btn-bg-color-hover: #ef4022;
  --gf-ctrl-btn-border-color: #f86349;
  --gf-ctrl-btn-border-color-hover: #ef4022;
  --gf-ctrl-btn-border-radius: 5px;
  --gf-ctrl-btn-padding-x: 24px;
  --gf-ctrl-btn-padding-y: 12px;
  --gf-field-pg-row-gap: 24px;
  --gf-form-gap-y: 24px;
}

.gform_wrapper.gform-theme--orbital {
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
.gform_wrapper.gform-theme--orbital .gform_required_legend {
  display: none;
}
.gform_wrapper.gform-theme--orbital .gfield_required {
  color: inherit;
}
.gform_wrapper.gform-theme--orbital textarea {
  min-height: 120px;
  resize: vertical;
}
.gform_wrapper.gform-theme--orbital select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%23959a9e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 10px;
  padding-right: 48px;
}
.gform_wrapper.gform-theme--orbital .gform_footer,
.gform_wrapper.gform-theme--orbital .gform_page_footer {
  margin-top: 24px;
  padding: 0;
}

.gform_wrapper.gform-theme--orbital .gfield_validation_message,
.gform_wrapper.gform-theme--orbital .validation_message {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.5;
  color: #dc3545;
}
.gform_wrapper.gform-theme--orbital .gfield_error input,
.gform_wrapper.gform-theme--orbital .gfield_error select,
.gform_wrapper.gform-theme--orbital .gfield_error textarea {
  border-color: #dc3545;
}
.gform_wrapper.gform-theme--orbital .gform_submission_error {
  margin-bottom: 24px;
  padding: 16px;
  font-size: 14px;
  color: #dc3545;
  background-color: rgba(220, 53, 69, 0.1);
  border-radius: 5px;
}
.gform_wrapper.gform-theme--orbital .gform_confirmation_message {
  padding: 24px;
  font-size: 16px;
  line-height: 1.5;
  color: #16a34a;
  background-color: rgba(22, 163, 74, 0.1);
  border-radius: 5px;
}

.gform_wrapper .gform_validation_container {
  display: none !important;
  position: absolute !important;
  left: -9999px !important;
}

.hidden_label .gfield_label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/*
    Components Manifest

    Import reusable UI components here (alphabetical order).
    Components are standalone patterns used across multiple sections.

    Examples: blog-card, team-card, testimonial-card, accordion

    Creating a new component:
        1. Create css/components/_my-component.scss
        2. Add @use 'my-component'; below
        3. Use .my-component class in templates

    Component structure:
        .my-component {
            .image { }
            .title { }
            .content { }
        }
*/
/*
    App shell (UI-SPEC app-shell / D-21)

    Full-screen dashboard chrome: fixed dark nav rail (left) + a light top bar and
    the scrolling content canvas (right). Reused by the Phase-6 client portal, so it
    is view-agnostic. Reconciled against .planning/design/ (Overview screenshot):
    the 60/30/10 split — light canvas (#f6f9f9) is the 60% bulk, the dark slate rail
    is the 30% chrome, the coral accent stays the scarce 10%.

    Markup: template-parts/dashboard/shell.php
        .app-shell > .nav-rail + .app-shell__main
        .app-shell__main > .app-shell__topbar + .app-shell__content
*/
body.baseline-dashboard {
  margin: 0;
  background: #f6f9f9;
  color: #111111;
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.5;
}

.app-shell {
  display: flex;
  min-height: 100vh;
  background: #f6f9f9;
  /* ---- TOP BAR ---- */
  /* ---- CONTENT CANVAS ---- */
}
@media (max-width: 992px) {
  .app-shell {
    flex-direction: column;
  }
}
.app-shell__main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: #f6f9f9;
}
.app-shell__topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 64px;
  padding: 24px 48px;
  background: rgba(246, 249, 249, 0.86);
  backdrop-filter: saturate(1.2) blur(8px);
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
@media (max-width: 768px) {
  .app-shell__topbar {
    padding: 16px 24px;
  }
}
.app-shell__heading {
  min-width: 0;
}
.app-shell__title {
  margin: 0;
  font-size: 32px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: #111111;
}
.app-shell__subtitle {
  margin: 2px 0 0;
  font-size: 14px;
  color: #959a9e;
}
.app-shell__live {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 16px;
  border-radius: 30px;
  background: #fff;
  box-shadow: 0 25px 7px 0 rgba(105, 105, 105, 0), 0 16px 6px 0 rgba(105, 105, 105, 0.01), 0 9px 5px 0 rgba(105, 105, 105, 0.05), 0 4px 4px 0 rgba(105, 105, 105, 0.08), 0 1px 2px 0 rgba(105, 105, 105, 0.09);
  font-size: 12px;
  font-weight: 600;
  color: #959a9e;
}
.app-shell__live-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #30b55e;
  box-shadow: 0 0 0 3px rgba(48, 181, 94, 0.18);
}
.app-shell__content {
  flex: 1 1 auto;
  width: 100%;
  max-width: 1360px;
  padding: 32px 48px 64px;
}
@media (max-width: 768px) {
  .app-shell__content {
    padding: 24px;
  }
}

body.admin-bar .nav-rail {
  top: 32px;
  height: calc(100vh - 32px);
}
body.admin-bar .app-shell__topbar {
  top: 32px;
}
@media screen and (max-width: 782px) {
  body.admin-bar .nav-rail {
    top: 46px;
    height: auto;
  }
  body.admin-bar .app-shell__topbar {
    top: 46px;
  }
}

.dashboard-placeholder {
  padding: 48px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  text-align: center;
  color: #959a9e;
}

/*
    Approval toolbar + prose editor + queue (UI-SPEC Admin approval / RPT-03)

    The admin-only report-approval surface (Plan 06-09). Three clusters:
      .approval-queue   the list of reports awaiting review (reuses .report-card);
                        a guard-failed row is visually promoted (poor-tinted).
      .approval-toolbar the action bar on the approval detail (Approve / Regenerate /
                        Reject / Reopen) — accent stays scarce (only Approve is primary).
      .approval-prose   the inline editor over the AI summary/recommendations (D-12).

    The destructive confirms reuse .modal-confirm (css/components/_modal-confirm.scss);
    inline "Saved"/error uses .inline-alert. Client-facing copy lives in the partial.

    Markup: template-parts/dashboard/approvals.php
*/
/* ----- uniform refusal (defence-in-depth cap re-check) --------------------- */
.approval-refusal {
  max-width: 640px;
  margin: 0 auto;
  padding: 48px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  text-align: center;
  color: #959a9e;
  font-size: 16px;
}

/* ==========================================================================
   QUEUE
   ========================================================================== */
.approval-queue {
  /* A flagged (guard-failed) row is promoted: a poor-tinted edge + surface so it
     reads as "needs a human decision" before anything else in the queue. */
}
.approval-queue__heading {
  margin: 0 0 24px;
  font-size: 24px;
  font-weight: 800;
  color: #111111;
}
.approval-queue__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.approval-queue__row--flagged {
  border: 1px solid rgba(220, 53, 69, 0.4);
  background: #fff5f5;
}
.approval-queue__flag {
  display: block;
  margin-top: 4px;
  color: #dc3545;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}
.approval-queue__empty {
  margin-top: 24px;
}

/* ==========================================================================
   DETAIL — head + published note + back link
   ========================================================================== */
.approval-detail {
  /* The read-only client preview sits below the editor, visually separated. */
}
.approval-detail__back {
  display: inline-block;
  margin-bottom: 16px;
  color: #959a9e;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}
.approval-detail__back:hover {
  color: #111111;
}
.approval-detail__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 24px;
}
.approval-detail__eyebrow {
  color: #f86349;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.approval-detail__title {
  margin: 4px 0 0;
  font-size: 24px;
  font-weight: 800;
  color: #111111;
}
.approval-detail__published {
  margin: 0 0 24px;
  color: #959a9e;
  font-size: 14px;
}
.approval-detail__preview {
  margin-top: 32px;
  padding-top: 32px;
  border-top: 1px solid #cfd0d4;
}

/* ==========================================================================
   TOOLBAR — sticky action bar; accent scarce (Approve is the only primary)
   ========================================================================== */
.approval-toolbar {
  position: sticky;
  top: 16px;
  z-index: 5;
  padding: 16px;
  margin-bottom: 24px;
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  /* Inline Save/approve error surfaced by the JS (reuses .inline-alert tones). */
  /* Regenerate is a busy-state button (disabled + label swap while dispatching). */
}
.approval-toolbar__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.approval-toolbar__message {
  margin: 8px 0 0;
}
.approval-toolbar__message[hidden] {
  display: none;
}
.approval-toolbar__regenerate[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* ==========================================================================
   NOTICE — the guard-fail prompt (reuses .inline-alert, adds spacing)
   ========================================================================== */
.approval-notice {
  margin-bottom: 24px;
  line-height: 1.5;
}

/* ==========================================================================
   PROSE EDITOR (D-12) — edit the untrusted AI summary before approving
   ========================================================================== */
.approval-prose {
  padding: 24px;
  margin-bottom: 24px;
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
}
.approval-prose__heading {
  margin: 0 0 4px;
  font-size: 18px;
  font-weight: 700;
  color: #111111;
}
.approval-prose__help {
  margin: 0 0 16px;
  color: #959a9e;
  font-size: 14px;
  line-height: 1.5;
}
.approval-prose__input {
  display: block;
  width: 100%;
  min-height: 220px;
  padding: 16px;
  border: 1px solid #d1d5db;
  border-radius: 5px;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.6;
  color: #111111;
  resize: vertical;
}
.approval-prose__input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
  border-color: #f86349;
}
.approval-prose__actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}

/*
    Breakdown bar (07-UI-SPEC.md §Color → "The breakdown bar's five segments",
    §"Escaping & Accessibility")

    The five-segment stacked page-load bar and its text legend, used by the GTmetrix
    panel only. This is the one genuinely NEW component in the phase: 07-PATTERNS.md
    §"No Analog Found" row 1 records that no stacked or segmented bar exists anywhere in
    this theme — `_trend-chart.scss` is a Chart.js canvas wrapper and `_score-card.scss`
    is a ring — so the UI-SPEC section named above is the spec, and the only thing copied
    from an existing partial is `_status-pill.scss`'s modifier loop shape.

    THE SEGMENTS ARE CATEGORIES, NOT JUDGEMENTS. Their colours come from the
    `$color-breakdown-*` ramp in `_variables.scss`, never from the semantic status scale:
    painting "Images" red would say a site is failing when it is merely image-heavy.

    Colour is never load-bearing. The bar carries `role="img"` with a composed
    `aria-label` the template supplies ("Page load breakdown: HTML 6%, CSS 9%,
    JavaScript 38%, Images 41%, Other 6%") — that label IS the non-colour affordance —
    each segment carries `title="{label} {pct}%"`, the ramp is distinguishable by
    luminance in greyscale, and the legend prints every percentage as visible text.

    Markup: <div class="breakdown-bar" role="img" aria-label="Page load breakdown: …">
              <span class="breakdown-bar__segment breakdown-bar__segment--1"
                    style="width:6%" title="HTML 6%"></span>
              …
            </div>
            <ul class="breakdown-bar__legend">
              <li class="breakdown-bar__legend-item">
                <span class="breakdown-bar__swatch breakdown-bar__swatch--1"></span>HTML 6%
              </li>
            </ul>
*/
/*  Fixed component dimensions (07-UI-SPEC.md §Spacing Scale → "Fixed component
    dimensions"). The design's 14px track and 9px swatch are rounded onto the scale; the
    8px swatch matches the existing `.status-pill__icon` dot exactly. */
/*  The categorical ramp, in segment order: HTML, CSS, JavaScript, Images, Other.
    Indexed 1–5 so a modifier class is a position, never a payload-supplied name. */
.breakdown-bar {
  display: flex;
  height: 12px;
  border-radius: 30px;
  overflow: hidden;
  background: #f6f6f8;
  /*  Width is the ONLY inline style permitted on this component, and the only inline
      style permitted anywhere in this phase. It is an integer percentage PHP has
      already validated: `breakdown` is accepted only when it is exactly five entries
      of integer `pct` summing to exactly 100, and anything else renders the absent
      state below rather than a partially-filled track. A COLOUR MUST NEVER BE INLINED
      HERE — segment colour comes from the position modifier classes, so a payload can
      never reach a `style=` attribute. Do not widen this exception. */
  /*  Carries the label AND the percentage as visible text. This is a deliberate
      improvement on the exported design, whose legend is label-only and therefore
      leans on colour to say which segment is which. */
  /*  The state used when `breakdown` fails the sum-to-100 assertion or is missing
      entirely: fall back to the shared muted `.metric-absent` treatment. A bar whose
      segments do not fill the track is worse than no bar, so a partially-filled track
      is never rendered. */
}
.breakdown-bar__segment {
  height: 100%;
}
.breakdown-bar__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  font-size: 12px;
  line-height: 1.2;
  color: #111111;
}
.breakdown-bar__legend-item {
  display: inline-flex;
  align-items: center;
  font-variant-numeric: tabular-nums;
}
.breakdown-bar__swatch {
  display: inline-block;
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 4px;
}
.breakdown-bar--absent {
  display: block;
  height: auto;
  background: none;
  border-radius: 0;
  color: #959a9e;
  font-style: italic;
  font-weight: 400;
  white-space: nowrap;
}

/*  Position => ramp colour, written as full literal selectors so the five segment and
    five swatch classes are greppable here and in the compiled stylesheet. A segment's
    colour is chosen by its index in the closed ramp, never by the payload. */
.breakdown-bar__segment--1 {
  background: #323643;
}

.breakdown-bar__swatch--1 {
  background: #323643;
}

.breakdown-bar__segment--2 {
  background: #4f5566;
}

.breakdown-bar__swatch--2 {
  background: #4f5566;
}

.breakdown-bar__segment--3 {
  background: #6f7688;
}

.breakdown-bar__swatch--3 {
  background: #6f7688;
}

.breakdown-bar__segment--4 {
  background: #959a9e;
}

.breakdown-bar__swatch--4 {
  background: #959a9e;
}

.breakdown-bar__segment--5 {
  background: #cfd0d4;
}

.breakdown-bar__swatch--5 {
  background: #cfd0d4;
}

/*
    Dashboard button variants (UI-SPEC Color — accent reserved list)

    The base .btn (css/_buttons.scss) is the marketing uppercase button; the dashboard
    wants sentence-case controls with the scarce coral accent only on primary CTAs.
    These variants layer onto `.btn` used across the dashboard partials:
      .btn--primary  coral fill  (Rescan site, Add site, Add client, Save, Compare)
      .btn--ghost    neutral outline (Cancel, Add core page, Remove)
      .btn--danger   poor/red fill  (destructive confirm — Pause site)

    Accent stays scarce so "attention" reads (UI-SPEC): secondary actions are ghost.
*/
.baseline-dashboard .btn,
.login-card .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 8px 24px;
  border-radius: 5px;
  font-size: 14px;
  font-weight: 600;
  text-transform: none;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.baseline-dashboard .btn:focus-visible,
.login-card .btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.baseline-dashboard .btn:disabled, .baseline-dashboard .btn[disabled],
.login-card .btn:disabled,
.login-card .btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}
.baseline-dashboard .btn--primary,
.login-card .btn--primary {
  background: #f86349;
  color: #fff;
  border: 1px solid #f86349;
}
.baseline-dashboard .btn--primary:hover:not(:disabled),
.login-card .btn--primary:hover:not(:disabled) {
  background: #ef4022;
  border-color: #ef4022;
}
.baseline-dashboard .btn--ghost,
.login-card .btn--ghost {
  background: transparent;
  color: #111111;
  border: 1px solid #cfd0d4;
}
.baseline-dashboard .btn--ghost:hover:not(:disabled),
.login-card .btn--ghost:hover:not(:disabled) {
  border-color: #111111;
}
.baseline-dashboard .btn--danger,
.login-card .btn--danger {
  background: #dc3545;
  color: #fff;
  border: 1px solid #dc3545;
}
.baseline-dashboard .btn--danger:hover:not(:disabled),
.login-card .btn--danger:hover:not(:disabled) {
  background: #b02a37;
  border-color: #b02a37;
}

/*
    Check config (UI-SPEC check-config / D-06/D-07)

    The registry-driven per-site check toggles embedded in the site form. A bordered
    fieldset of toggle rows; each row a checkbox + label, with an optional indented
    sub-options block (structured-data types). Disabled/off checks read muted.

    Markup: template-parts/dashboard/partials/check-config.php
      fieldset.check-config ( legend __hint  .check-config__row ( __toggle __options ) )
*/
.check-config {
  margin: 0 0 16px;
  padding: 16px;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
}
.check-config__legend {
  padding: 0 4px;
  font-size: 14px;
  font-weight: 600;
  color: #111111;
}
.check-config__hint {
  margin: 0 0 16px;
  font-size: 12px;
  color: #959a9e;
}
.check-config__row + .check-config__row {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid #cfd0d4;
}
.check-config__toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  cursor: pointer;
}
.check-config__toggle input {
  accent-color: #f86349;
}
.check-config__toggle:focus-within {
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
  border-radius: 5px;
}
.check-config__label {
  font-size: 14px;
  font-weight: 600;
  color: #111111;
}
.check-config__options {
  margin-top: 8px;
  padding-left: 24px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.check-config__options-label {
  flex: 1 0 100%;
  font-size: 12px;
  color: #959a9e;
}
.check-config__option {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: #111111;
  cursor: pointer;
}

/*
    Compare select (UI-SPEC compare-select / D-18)

    The per-card "Compare" checkbox on the sites grid. Selecting up to 3 (Plan 11
    caps and disables the rest at max) enables the "Compare selected" CTA. Selected
    state carries the scarce coral accent; a disabled (max-reached) box reads muted.

    Markup: <label class="compare-select"><input class="compare-select__input"><span class="compare-select__label"></label>
*/
.compare-select {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  font-size: 12px;
  font-weight: 600;
  color: #959a9e;
  cursor: pointer;
}
.compare-select__input {
  width: 18px;
  height: 18px;
  accent-color: #f86349;
  cursor: pointer;
}
.compare-select__input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.compare-select__input:disabled {
  cursor: not-allowed;
}
.compare-select:has(.compare-select__input:checked) {
  color: #f86349;
}
.compare-select:has(.compare-select__input:disabled) {
  opacity: 0.5;
  cursor: not-allowed;
}

/*
    CWV metric (UI-SPEC cwv-metric / D-16)

    One Core Web Vitals reading (LCP / INP / CLS) toned by its rating band
    (good / needs-improvement / poor / no-data), paired with a text rating label so
    the band never relies on colour alone. A NULL value is the neutral metric-absent
    glyph — never 0, never a status colour.

    Markup: template-parts/dashboard/partials/cwv-metric.php
      .cwv-metric.cwv-metric--{tone} ( __label __value __rating )
*/
.cwv-metric {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px;
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  text-align: center;
}
.cwv-metric__label {
  font-size: 12px;
  font-weight: 600;
  color: #959a9e;
}
.cwv-metric__value {
  font-size: 24px;
  font-weight: 600;
  line-height: 1.2;
  color: #111111;
}
.cwv-metric__rating {
  font-size: 12px;
  font-weight: 600;
  color: #959a9e;
}
.cwv-metric--good .cwv-metric__value {
  color: #30b55e;
}
.cwv-metric--good .cwv-metric__rating {
  color: #30b55e;
}
.cwv-metric--needs-improvement .cwv-metric__value {
  color: #f59e0b;
}
.cwv-metric--needs-improvement .cwv-metric__rating {
  color: #f59e0b;
}
.cwv-metric--poor .cwv-metric__value {
  color: #dc3545;
}
.cwv-metric--poor .cwv-metric__rating {
  color: #dc3545;
}
.cwv-metric--no-data .cwv-metric__value {
  color: #959a9e;
}
.cwv-metric--no-data .cwv-metric__rating {
  color: #959a9e;
}

/*
    Data table (UI-SPEC data-table)

    The shared rows / empty / paged table (incidents log, reusable for leaderboard /
    activity). White surface, light row rules, a sticky-feeling header, and a footer
    with the "Showing X–Y of N" count + Previous/Next pager.

    Markup: template-parts/dashboard/partials/data-table.php
      .data-table > (.data-table__empty | table.data-table__table + .data-table__footer)
*/
.data-table {
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  overflow: hidden;
}
.data-table__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.data-table th,
.data-table td {
  padding: 8px 16px;
  text-align: left;
  vertical-align: middle;
}
.data-table thead th {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #959a9e;
  background: #f6f6f8;
  border-bottom: 1px solid #cfd0d4;
}
.data-table tbody tr + tr {
  border-top: 1px solid #cfd0d4;
}
.data-table tbody tr:hover {
  background: #f6f9f9;
}
.data-table time {
  color: #959a9e;
}
.data-table__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 16px;
  border-top: 1px solid #cfd0d4;
  background: #f6f6f8;
}
.data-table__count {
  margin: 0;
  font-size: 12px;
  color: #959a9e;
}
.data-table__pager {
  display: flex;
  align-items: center;
  gap: 8px;
}
.data-table__page-status {
  font-size: 12px;
  color: #959a9e;
}
.data-table__page-btn {
  min-height: 32px;
  padding: 4px 16px;
  border: 1px solid #cfd0d4;
  border-radius: 5px;
  background: #fff;
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  color: #111111;
  cursor: pointer;
}
.data-table__page-btn:hover:not(:disabled) {
  border-color: #111111;
}
.data-table__page-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.data-table__page-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.incidents__ongoing {
  color: #dc3545;
  font-weight: 600;
}

/*
    Empty state (UI-SPEC empty-state)

    Shared block for "no sites / no incidents / no clients / nothing needs attention /
    compare needs selection". Centred, muted, with an optional heading + CTA. Used
    across every view (and inside the data-table + trend-chart empty branches).
*/
.empty-state {
  padding: 48px 24px;
  text-align: center;
  color: #959a9e;
}
.empty-state__title {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 600;
  color: #111111;
}
.empty-state p {
  margin: 0 auto 16px;
  max-width: 46ch;
  font-size: 14px;
  line-height: 1.5;
}
.empty-state p:last-child {
  margin-bottom: 0;
}
.empty-state strong {
  color: #111111;
  font-weight: 600;
}
.empty-state .btn {
  margin-top: 8px;
}

/*
    Form field + button group + core-pages repeater
    (UI-SPEC form-field / D-06 — the add/edit site + add client forms)

    Native front-end form controls: label over input, hint + error nodes, the
    active/paused button-group radio, and the repeating core-pages rows. Focus rings
    are the visible coral accent; the JS error state adds
    `.form-field__input--error` and unhides `.form-field__error`.

    Markup: template-parts/dashboard/partials/site-form.php + client-form.php
*/
.form-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 16px;
}
.form-field__label {
  font-size: 12px;
  font-weight: 600;
  color: #111111;
}
.form-field__optional {
  font-weight: 400;
  color: #959a9e;
}
.form-field__input {
  width: 100%;
  min-height: 44px;
  padding: 8px 16px;
  border: 1px solid #d1d5db;
  border-radius: 5px;
  font-size: 16px;
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: #fff;
  color: #111111;
}
.form-field__input:focus {
  outline: none;
  border-color: #f86349;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.form-field__input--error {
  border-color: #dc3545;
}
.form-field__hint {
  margin: 0;
  font-size: 12px;
  color: #959a9e;
}
.form-field__error {
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  color: #dc3545;
}
.form-field__error[hidden] {
  display: none;
}

/* ---- ACTIVE / PAUSED BUTTON GROUP (radiogroup) ---- */
.button-group {
  display: inline-flex;
  border: 1px solid #cfd0d4;
  border-radius: 5px;
  overflow: hidden;
}
.button-group__option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 8px 24px;
  font-size: 14px;
  font-weight: 600;
  color: #959a9e;
  cursor: pointer;
}
.button-group__option + .button-group__option {
  border-left: 1px solid #cfd0d4;
}
.button-group__option input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.button-group__option--active, .button-group__option:has(input:checked) {
  background: #f86349;
  color: #fff;
}
.button-group__option:focus-within {
  box-shadow: inset 0 0 0 3px rgba(248, 99, 73, 0.45);
}

/* ---- CORE PAGES REPEATER ---- */
.core-pages__rows {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.core-pages__row {
  display: flex;
  gap: 8px;
  align-items: center;
}
@media (max-width: 576px) {
  .core-pages__row {
    flex-wrap: wrap;
  }
}
.core-pages__add {
  align-self: flex-start;
  margin-top: 8px;
}

/*
    Grade circle (07-UI-SPEC.md §"The one grade-tone mapper", §Typography, §Print)

    The A–F letter circle, in two sizes: the GTmetrix panel (large), the
    security-headers panel and the client-facing monthly report (both small).

    Plus `.grade-letter`, the same grade at TEXT scale for the two surfaces that carry a
    grade inline rather than as a badge — the sites-list card footer (D-25) and the
    Compare grade rows. Both are 12.5px / 16px contexts where a 48px circle would
    dominate the row it sits in, and 07-UI-SPEC §5 specifies them as text outright
    ("the label GTmetrix in muted 12px, then the letter in $font-weight-bold toned").
    It lives HERE rather than in either view's section partial so the tone => colour map
    below stays the single home of the mapping: two views, one map, no drift.

    THE LETTER ITSELF IS THE INFORMATION. It is text, not a colour encoding — the tone is
    reinforcement only, which is what keeps this component honest in greyscale. The tone
    comes from `baseline_present_grade_tone($grade_rank)`, derived from the integer rank
    n8n sends (A=0 … F=5), never from the letter string and NEVER from a payload colour.

    One display size for both circles is deliberate: rendering the large and small
    circles at the same 24px letter says the two grades are the same *class* of value,
    which they are, and removes a size from the type scale for nothing lost.

    Markup: <span class="grade-circle grade-circle--lg grade-circle--good"
                  aria-label="Security grade B, 75 out of 100">B</span>
*/
/*  Fixed component dimensions (07-UI-SPEC.md §Spacing Scale → "Fixed component
    dimensions"). Both are multiples of 4; the design's off-scale 74px / 50px / 52px are
    rounded onto the scale here. */
.grade-circle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border-radius: 50%;
  color: #fff;
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  /*  Print safety, mechanism 1 of 2. Ask the browser not to strip the fill. This alone
      is not enough — it is advisory, users can override it, and several engines ignore
      it in "simplified" print modes — which is why the @media print block below
      inverts the component outright rather than relying on this holding. */
  print-color-adjust: exact;
  -webkit-print-color-adjust: exact;
}
.grade-circle--lg {
  width: 72px;
  height: 72px;
}
.grade-circle--sm {
  width: 48px;
  height: 48px;
}
.grade-circle--good {
  background: #30b55e;
}
.grade-circle--warning {
  background: #f59e0b;
}
.grade-circle--poor {
  background: #dc3545;
}
.grade-circle--neutral {
  background: #959a9e;
}

/*  The same grade, inline at text scale (sites-list card footer, Compare grade rows).

    No fill and no ring: the letter takes the tone as its own COLOUR, so it needs neither
    print mechanism above — there is no background for a printer to strip. Written as
    literal `--{tone}` selectors from the SAME map, so the closed set of four stays
    greppable in both the source and the compiled output. */
.grade-letter {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.grade-letter--good {
  color: #30b55e;
}
.grade-letter--warning {
  color: #f59e0b;
}
.grade-letter--poor {
  color: #dc3545;
}
.grade-letter--neutral {
  color: #959a9e;
}

/*  Print safety, mechanism 2 of 2 — required, not belt-and-braces decoration.

    A filled circle carrying a white letter becomes WHITE ON WHITE the moment a browser
    strips background colours for print, and this component renders inside a client-facing
    monthly report that clients do print. So invert it regardless: transparent fill, a
    ring in the tone colour, and the letter in the tone colour rather than white. The
    grade then survives even a printer that honours no backgrounds at all. */
@media print {
  .grade-circle {
    background: transparent;
  }
  .grade-circle--good {
    background: transparent;
    border: 2px solid #30b55e;
    color: #30b55e;
  }
  .grade-circle--warning {
    background: transparent;
    border: 2px solid #f59e0b;
    color: #f59e0b;
  }
  .grade-circle--poor {
    background: transparent;
    border: 2px solid #dc3545;
    color: #dc3545;
  }
  .grade-circle--neutral {
    background: transparent;
    border: 2px solid #959a9e;
    color: #959a9e;
  }
}
/*
    Toast / inline alert (UI-SPEC toast/inline-alert)

    Save-success / error / rate-limit messages surfaced by Plan 11 (baseline-dashboard.js
    injects `.inline-alert inline-alert--{success|error|warning}`, and the form message
    node `.form-message`). Tone from the semantic scale, paired with an icon dot so it
    never relies on colour alone.

    Markup (JS-created): <p class="inline-alert inline-alert--error" role="alert">…</p>
*/
.inline-alert,
.form-message {
  display: block;
  padding: 8px 16px;
  border-radius: 5px;
  border: 1px solid transparent;
  font-size: 14px;
  font-weight: 600;
}
.inline-alert--success,
.form-message--success {
  color: #16a34a;
  background: #f0fdf4;
  border-color: rgba(22, 163, 74, 0.25);
}
.inline-alert--error,
.form-message--error {
  color: #dc3545;
  background: #fff5f5;
  border-color: rgba(220, 53, 69, 0.25);
}
.inline-alert--warning,
.form-message--warning {
  color: #f59e0b;
  background: #fffbeb;
  border-color: rgba(245, 158, 11, 0.25);
}

/*
    KPI card (UI-SPEC kpi-card / D-14)

    One overview KPI, reconciled against .planning/design/ (the Overview KPI row):
    an uppercase micro-label ON TOP, then a big Display numeral (with an optional unit
    + a trend arrow or a small delta chip), then a muted caption. White floating card.

    Markup: template-parts/dashboard/partials/kpi-card.php
      .kpi-card[.--coral] > __label __figure(__value[__unit] __trend|__delta) __caption
*/
.kpi-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 24px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
}
.kpi-card__label {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #959a9e;
}
.kpi-card__figure {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.kpi-card__value {
  font-size: 44px;
  font-weight: 800;
  line-height: 1;
  color: #111111;
  font-variant-numeric: tabular-nums;
}
.kpi-card__value--absent {
  font-size: 24px;
  font-weight: 700;
  color: #959a9e;
}
.kpi-card__unit {
  margin-left: 1px;
  font-size: 22px;
  font-weight: 700;
  color: inherit;
}
.kpi-card__trend {
  font-size: 15px;
  line-height: 1;
}
.kpi-card__trend--up {
  color: #30b55e;
}
.kpi-card__trend--down {
  color: #dc3545;
}
.kpi-card__delta {
  padding: 2px 8px;
  border-radius: 30px;
  background: rgba(248, 99, 73, 0.1);
  color: #f86349;
  font-size: 12px;
  font-weight: 700;
}
.kpi-card__caption {
  font-size: 12px;
  color: #959a9e;
}
.kpi-card--coral .kpi-card__value:not(.kpi-card__value--absent) {
  color: #f86349;
}

/*
    Login card (UI-SPEC login-card / D-03)

    The branded, centred sign-in card shown on the logged-out /dashboard root. Real
    WP auth over wp_signon; capability decides the destination (no role toggle).
    Reconciled against .planning/design/ (BRONTË BASELINE wordmark): a single white
    card floating on the light canvas, the stacked wordmark as the brand anchor, a
    coral primary submit, and the one generic error in the status-poor tint.

    Markup: template-parts/dashboard/login.php
        .login-screen > .login-card ( __wordmark __title __lede __error __form )
*/
.login-screen {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 32px;
  background: radial-gradient(1200px 600px at 50% -10%, rgba(248, 99, 73, 0.06), transparent 60%), #f6f9f9;
}

.login-card {
  width: 100%;
  max-width: 420px;
  padding: 48px;
  background: #fff;
  border-radius: 15px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  /* ---- WORDMARK ---- */
  /* ---- FORM ---- */
}
.login-card__wordmark {
  display: flex;
  flex-direction: column;
  line-height: 1;
  text-transform: uppercase;
  margin-bottom: 32px;
}
.login-card__wordmark-top, .login-card__wordmark-bottom {
  font-weight: 800;
  font-size: 34px;
  letter-spacing: 0.005em;
}
.login-card__wordmark-top {
  color: #111111;
}
.login-card__wordmark-bottom {
  color: #f86349;
}
.login-card__wordmark-kicker {
  margin-top: 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: #959a9e;
}
.login-card__title {
  margin: 0 0 4px;
  font-size: 24px;
  font-weight: 700;
  color: #111111;
}
.login-card__lede {
  margin: 0 0 24px;
  font-size: 14px;
  color: #959a9e;
}
.login-card__error {
  margin: 0 0 16px;
  padding: 8px 16px;
  border-radius: 5px;
  background: #fff5f5;
  color: #dc3545;
  font-size: 14px;
}
.login-card__form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.login-card__field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.login-card__label {
  font-size: 12px;
  font-weight: 600;
  color: #111111;
}
.login-card input[type=text],
.login-card input[type=password] {
  width: 100%;
  min-height: 44px;
  padding: 8px 16px;
  border: 1px solid #d1d5db;
  border-radius: 5px;
  background: #fff;
  font-size: 16px;
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: #111111;
}
.login-card input[type=text]:focus,
.login-card input[type=password]:focus {
  outline: none;
  border-color: #f86349;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.login-card__remember {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: #959a9e;
  cursor: pointer;
}
.login-card__remember input {
  accent-color: #f86349;
}
.login-card__submit {
  min-height: 46px;
  margin-top: 8px;
  border: 0;
  border-radius: 5px;
  background: #f86349;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.login-card__submit:hover {
  background: #ef4022;
}
.login-card__submit:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}

/*
    Field-data-absent glyph (D-16 / UI-SPEC)

    The muted "— No field data" treatment emitted wherever a metric is NULL (CrUX
    field data Google never published, a never-scanned score). It is ALWAYS neutral
    muted — NEVER 0 and NEVER a status colour — so honest absence never reads as a
    genuine low value. Used inline by nearly every view + the score/cwv/compare cells.
*/
.metric-absent {
  color: #959a9e;
  font-style: italic;
  font-weight: 400;
  white-space: nowrap;
}

/*
    Modal confirm (UI-SPEC modal-confirm / T-05-24)

    The reusable destructive-confirmation dialog (pause site). Hidden by [hidden];
    Plan 11 unhides it. Centred dialog over a dimmed backdrop, the confirm button
    carries the danger treatment via .btn--danger.

    Markup: template-parts/dashboard/partials/modal-confirm.php
      .modal-confirm[hidden] ( __backdrop  __dialog ( __title __body __actions ) )
*/
.modal-confirm {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.modal-confirm[hidden] {
  display: none;
}
.modal-confirm__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}
.modal-confirm__dialog {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 440px;
  padding: 32px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
}
.modal-confirm__title {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 600;
  color: #111111;
}
.modal-confirm__body {
  margin: 0 0 24px;
  font-size: 14px;
  color: #959a9e;
}
.modal-confirm__actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/*
    Nav rail (UI-SPEC app-shell / D-21)

    The fixed dark sidebar reconciled against .planning/design/ (Overview + Compare
    screenshots): slate surface, coral "B" badge + BRONTË BASELINE wordmark, line-icon
    nav with a solid coral active pill and a red Incidents count, then the yellow
    "+ Add a site" CTA and the user chip + logout pinned to the foot.

    Markup: template-parts/dashboard/shell.php  (.nav-rail > brand + nav + foot)
*/
.nav-rail {
  position: sticky;
  top: 0;
  align-self: flex-start;
  flex-shrink: 0;
  width: 236px;
  height: 100vh;
  display: flex;
  flex-direction: column;
  padding: 24px 16px;
  background: #323643;
  color: rgba(255, 255, 255, 0.62);
  /* ---- BRAND ---- */
  /* ---- NAV ---- */
  /* ---- FOOT ---- */
}
@media (max-width: 992px) {
  .nav-rail {
    position: static;
    width: auto;
    height: auto;
  }
}
.nav-rail__brand {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 8px 24px;
  text-decoration: none;
}
.nav-rail__badge {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 10px;
  background: #f86349;
  color: #fff;
  font-weight: 800;
  font-size: 18px;
  line-height: 1;
}
.nav-rail__wordmark {
  display: flex;
  flex-direction: column;
  line-height: 1.05;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 700;
  font-size: 16px;
}
.nav-rail__wordmark-top {
  color: #fff;
}
.nav-rail__wordmark-bottom {
  color: #f86349;
}
.nav-rail__nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 8px;
}
.nav-rail__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border-radius: 10px;
  color: rgba(255, 255, 255, 0.62);
  font-size: 16px;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.nav-rail__item:hover {
  color: rgba(255, 255, 255, 0.92);
  background: rgba(255, 255, 255, 0.06);
}
.nav-rail__item:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.nav-rail__item--active, .nav-rail__item--active:hover {
  background: #f86349;
  color: #fff;
  box-shadow: 0 6px 16px -6px rgba(248, 99, 73, 0.7);
}
.nav-rail__icon {
  flex-shrink: 0;
  display: inline-flex;
  width: 22px;
  height: 22px;
}
.nav-rail__icon svg {
  width: 100%;
  height: 100%;
}
.nav-rail__label {
  flex: 1;
}
.nav-rail__count {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 30px;
  background: #dc3545;
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
}
.nav-rail__foot {
  margin-top: auto;
  padding-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.nav-rail__add {
  display: block;
  padding: 12px 16px;
  border-radius: 10px;
  background: #fff55a;
  color: #111111;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  transition: filter 0.2s cubic-bezier(0.4, 0, 0.2, 1), transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.nav-rail__add:hover {
  filter: brightness(0.96);
  transform: translateY(-1px);
}
.nav-rail__add:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.nav-rail__user {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-top: 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.nav-rail__avatar {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: #f86349;
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
}
.nav-rail__user-meta {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.25;
}
.nav-rail__user-name {
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-rail__user-role {
  color: rgba(255, 255, 255, 0.45);
  font-size: 12px;
}
.nav-rail__logout {
  flex-shrink: 0;
  display: inline-flex;
  width: 20px;
  height: 20px;
  color: rgba(255, 255, 255, 0.45);
  transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.nav-rail__logout:hover, .nav-rail__logout:focus-visible {
  color: #fff;
  outline: none;
}
.nav-rail__logout svg {
  width: 100%;
  height: 100%;
}

/*
    Reason chip (UI-SPEC reason-chip / D-12)

    The named "why this needs attention" label (data from present.php — "regression",
    "stale 3d", "below your avg", "perf 42"). Tone comes from the reason's leading
    token (poor / warning / neutral) and is paired with a coloured dot so it never
    relies on colour alone.

    Markup: <span class="reason-chip reason-chip--{tone}"><span class="reason-chip__dot"></span>…</span>
*/
.reason-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 30px;
  background: #f6f6f8;
  font-size: 12px;
  font-weight: 600;
  color: #111111;
  white-space: nowrap;
}
.reason-chip__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #959a9e;
  flex: 0 0 auto;
}
.reason-chip--poor .reason-chip__dot {
  background: #dc3545;
}
.reason-chip--warning .reason-chip__dot {
  background: #f59e0b;
}
.reason-chip--neutral .reason-chip__dot {
  background: #959a9e;
}

/*
    Report card + status badge (CLI-02 / D-09 / D-11 / UI-SPEC report-card)

    The history-list + portal item: a site monogram, the site name, the report period,
    a fixed subtitle, the workflow status badge and a "View report" CTA. The most recent
    report is visually promoted (.report-card--anchor) per the UI-SPEC visual hierarchy;
    older rows are a quieter list.

    .report-status-badge is the SHARED workflow chip used by both the history card and
    the report-view header — status is ALWAYS colour + text label, never colour alone
    (the badge inline-styles its own semantic colour pair from the view).

    Markup: template-parts/dashboard/report-history.php + report.php.
    Tokens only (_variables.scss).
*/
.report-card {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  text-decoration: none;
  color: inherit;
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.report-card:hover {
  transform: translateY(-1px);
}
.report-card--anchor {
  border: 2px solid rgba(248, 99, 73, 0.35);
}
.report-card__mono {
  flex: 0 0 48px;
  width: 48px;
  height: 48px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 18px;
  color: #fff;
}
.report-card__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.report-card__title {
  font-weight: 600;
  font-size: 16px;
  color: #111111;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.report-card__period {
  font-size: 14px;
  color: #959a9e;
}
.report-card__summary {
  font-size: 12px;
  color: #959a9e;
}
.report-card__meta {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  text-align: right;
}
.report-card__cta {
  font-size: 14px;
  font-weight: 600;
  color: #f86349;
}
@media (max-width: 576px) {
  .report-card__meta {
    flex-direction: row;
    align-items: center;
  }
}

/* ---- Shared workflow status chip (colour pair set inline per status) ---- */
.report-status-badge {
  display: inline-block;
  padding: 4px 11px;
  border-radius: 30px;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}

/*
    Rescan button + progress indicator (UI-SPEC rescan-button / D-09/D-11)

    The phase-flagship control. It IS a .btn.btn--primary (coral) in idle; Plan 11
    drives the six states off [data-state] (idle / queued / dispatched / done / failed /
    cooldown). The disabled treatment is UX-only — the server owns the real guard.
    A spinner shows while a job is in flight; a done state briefly reads success; a
    failed poll surfaces the inline alert (styled in _inline-alert.scss).

    Markup: template-parts/dashboard/partials/rescan-button.php
      button.rescan-button[data-state] > .rescan-button__label
*/
.rescan-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.rescan-button[data-state=queued]::before, .rescan-button[data-state=dispatched]::before {
  content: "";
  width: 14px;
  height: 14px;
  border: 2px solid rgba(255, 255, 255, 0.5);
  border-top-color: #fff;
  border-radius: 50%;
  animation: rescan-spin 0.7s linear infinite;
}
.rescan-button[data-state=done] {
  background: #30b55e;
  border-color: #30b55e;
}
.rescan-button[data-state=failed], .rescan-button[data-state=cooldown] {
  background: #959a9e;
  border-color: #959a9e;
}
.rescan-button__alert {
  margin-top: 8px;
}

@keyframes rescan-spin {
  to {
    transform: rotate(360deg);
  }
}
/* ---- Inline progress indicator (queued -> dispatched -> done/failed) ---- */
.progress-indicator {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  color: #f59e0b;
}
.progress-indicator--done {
  color: #30b55e;
}
.progress-indicator--failed {
  color: #dc3545;
}

/*
    Score card (UI-SPEC score-card / D-13)

    One Lighthouse score vs Google's recommended band vs the site's own 3-month
    average, with the two "below" flags. Reconciled against .planning/design/
    (site-detail + CWV cards): a clean cell on a subtle grey field, a BIG band-coloured
    numeral, the uppercase micro-label, then the recommended/avg meta — paired with the
    "Recommended {band}" text so the state never reads by colour alone. Absent
    current/avg renders the neutral metric-absent glyph (never 0/red).

    Markup: template-parts/dashboard/partials/score-card.php
      .score-card.score-card--{tone} ( __label __value __recommended __avg __flag )
*/
.score-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 16px;
  background: #f6f6f8;
  border-radius: 10px;
}
.score-card__label {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #959a9e;
}
.score-card__value {
  font-size: 36px;
  font-weight: 800;
  line-height: 1.05;
  color: #111111;
}
.score-card__recommended, .score-card__avg {
  font-size: 12px;
  color: #959a9e;
}
.score-card__recommended {
  margin-top: 2px;
}
.score-card__flag {
  align-self: flex-start;
  margin-top: 4px;
  padding: 2px 8px;
  border-radius: 30px;
  font-size: 12px;
  font-weight: 600;
  background: #fffbeb;
  color: #f59e0b;
}
.score-card__flag--recommended {
  background: #fff5f5;
  color: #dc3545;
}
.score-card--good .score-card__value {
  color: #30b55e;
}
.score-card--needs-improvement .score-card__value {
  color: #f59e0b;
}
.score-card--poor .score-card__value {
  color: #dc3545;
}
.score-card--no-data .score-card__value {
  color: #959a9e;
}

/*
    Screenshot thumb (UI-SPEC screenshot-thumb / D-17)

    A live mShots <img> of the site's current appearance. The page never depends on
    it (a broken fetch is hidden via onerror), so this only frames the image: a
    fixed-ratio, rounded, clipped box with a neutral placeholder background while the
    first mShots request warms up.

    Markup: <figure class="screenshot-thumb"><img class="screenshot-thumb__img"></figure>
*/
.screenshot-thumb {
  margin: 0;
  overflow: hidden;
  background: #f6f6f8;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  aspect-ratio: 4/3;
}
.screenshot-thumb__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

/*
    Site card (UI-SPEC site-card / D-15)

    One site's cell in the sites grid: compare checkbox, mShots thumb, name, a
    semantic status pill, then either the headline score-card OR — for a
    running-first-scan site — a skeleton (NEVER a fabricated 0). Reconciled against
    .planning/design/: a clean white card, soft floating shadow, no coloured border;
    state reads from the compact dot+label pill, never a coloured card edge.

    Markup: template-parts/dashboard/partials/site-card.php
      article.site-card.site-card--{tone}[data-status] ( .compare-select .screenshot-thumb
        .site-card__name .status-pill .site-card__skeleton|score-card .site-card__ago )
*/
.site-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  padding: 16px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.site-card:hover {
  transform: translateY(-2px);
}
.site-card .screenshot-thumb,
.site-card .score-card, .site-card__skeleton, .site-card__first-scan {
  width: 100%;
}
.site-card .compare-select {
  align-self: flex-end;
  margin-bottom: -4px;
}
.site-card__name {
  font-size: 18px;
  font-weight: 700;
  color: #111111;
  text-decoration: none;
}
.site-card__name:hover, .site-card__name:focus-visible {
  color: #f86349;
}
.site-card__name:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
  border-radius: 5px;
}
.site-card__ago {
  margin-top: auto;
  font-size: 12px;
  color: #959a9e;
}
.site-card__first-scan {
  margin: 0;
  font-size: 12px;
  color: #959a9e;
  line-height: 1.5;
}
.site-card__skeleton {
  padding: 2px 0;
}
.site-card__skeleton-bar {
  display: block;
  height: 32px;
  width: 55%;
  border-radius: 5px;
  background: linear-gradient(90deg, #f6f6f8 25%, #eceef1 37%, #f6f6f8 63%);
  background-size: 400% 100%;
  animation: site-card-shimmer 1.4s ease infinite;
}

@keyframes site-card-shimmer {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0 50%;
  }
}
/*
    Source panel (07-UI-SPEC.md §"The normalised item shape → SCSS class contract", D-23)

    The shared chrome for the four Phase-7 site-detail panels — GTmetrix, Security
    headers, Technical SEO, Structured data — and the single home of the one place a
    payload's `status` becomes a visual treatment.

    THE LOAD-BEARING RULE, in words: the payload's `status` SELECTS this class; it never
    BECOMES one, and no payload-derived value may ever reach a `style=` attribute. PHP
    switches over exactly five literals (pass / warn / fail / info / absent), defaulting
    to `info`, and emits one of the five modifier classes below. A vendor string can
    therefore never reach a class name. The exported design interpolates a payload colour
    straight into `style="background:{{ r.color }}"` at three offsets; that is refused
    outright on security grounds, and this partial is what makes the refusal possible.

    Colour is never alone: each mark is a real text character and is immediately followed
    by a `.baseline-sr-only` status word ("Pass" / "Warning" / "Fail" / "Not collected").

    Cross-boundary note: the `label` and `note` strings n8n sends for `security` and `seo`
    render verbatim in the client-facing monthly report, so they are client-facing copy.

    Markup: <section class="source-panel">
              <header class="source-panel__head">
                <div><h3 class="source-panel__title">…</h3>
                     <p class="source-panel__subtitle">…</p></div>
                [right slot: .grade-circle or .source-panel__chip]
              </header>
              <div class="source-panel__body">
                <div class="source-panel__item source-panel__item--pass">
                  <span class="source-panel__item__mark">✓</span>
                  <span class="baseline-sr-only">Pass</span>
                  <span class="source-panel__item__label">…</span>
                  <span class="source-panel__item__value">…</span>
                  <span class="source-panel__item__note">…</span>
                </div>
              </div>
            </section>
*/
/*  Fixed component dimensions (07-UI-SPEC.md §Spacing Scale → "Fixed component
    dimensions"). Declared as named constants rather than written inline so the values
    stay reviewable in one place; the grid minima are `auto-fill` thresholds, not
    spacing, which is why they sit off the 4px scale by design intent. */
/*  status token => (mark foreground, mark background).

    `info` deliberately takes the ink colour and NO background fill. A blue chip reads as
    a state, and `info` means *no state* — "here is a number, no judgement" (TTFB, page
    size, request count). That is why the blue semantic token is absent from this map. */
.source-panel {
  /*  Card chrome from tokens. 07-UI-SPEC.md's token → inline-neighbour equivalence
      table is why a class-based panel sits cleanly beside the inline-styled cards
      Plan 05-12 left on the same screen: the background and radius are byte-identical,
      the shadow is the same variable the inline cards resolve through a custom
      property, and the padding is 2px larger than the design's off-scale value —
      invisible at a grid-item edge. The reconciliation direction is towards tokens. */
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  padding: 24px;
  /*  The two copy states. Both are ordinary muted text, NOT error styling: a check
      that has not run yet and a payload the presenter declined to walk are both
      normal conditions, and dressing either in a status colour would tell an admin
      something is wrong when nothing is. */
  /*  The SEO and schema cell grids. `auto-fill` means a two-type schema panel looks
      intentional rather than broken. */
  /*  ACCENT USE 1 OF 3. The coral accent is permitted in exactly three places in this
      phase: this structured-data "{valid}/{total} valid" chip, the focus ring on the
      GTmetrix out-link below, and the "Open security issues" KPI numeral above zero.
      Never on a panel title, never on a grade circle, never on a breakdown segment,
      never on the sites-card grade. Do not spread it. */
  /*  The GTmetrix out-link — the phase's only new interactive control. Accent TEXT,
      not an accent-filled button: fill stays reserved for the shell's existing primary
      actions. The tap target is the a11y minimum even though the visual padding is
      smaller. Focus uses the codebase's box-shadow ring idiom (`outline: none` +
      `box-shadow: $focus-ring`), which is how every other focusable control in the
      theme renders it. */
}
.source-panel__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}
.source-panel__title {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.2;
  color: #111111;
  margin: 0;
}
.source-panel__subtitle {
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  color: #959a9e;
  margin: 4px 0 0;
}
.source-panel__body {
  margin-top: 12px;
}
.source-panel__empty, .source-panel__unreadable {
  color: #959a9e;
  font-size: 14px;
  line-height: 1.5;
  margin: 0;
}
.source-panel__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid #cfd0d4;
  /*  The mark is a REAL TEXT CHARACTER inside the circle, never a background
      image, so it survives greyscale, high-contrast mode, a printed page and a
      copy-paste. The modifier below tints this circle only — never the row. */
}
.source-panel__item:last-child {
  border-bottom: 0;
}
.source-panel__item__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
}
.source-panel__item__label {
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  color: #111111;
}
.source-panel__item__value {
  margin-left: auto;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.5;
  color: #111111;
  font-variant-numeric: tabular-nums;
}
.source-panel__item__note {
  flex: 0 0 100%;
  font-size: 12px;
  line-height: 1.5;
  color: #959a9e;
}
.source-panel__grid {
  display: grid;
  gap: 12px;
}
.source-panel__grid--seo {
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}
.source-panel__grid--seo .source-panel__item {
  display: block;
  border-bottom: 0;
}
.source-panel__grid--seo .source-panel__item__label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #959a9e;
}
.source-panel__grid--seo .source-panel__item__value {
  display: block;
  margin-left: 0;
  font-size: 24px;
  line-height: 1.2;
}
.source-panel__grid--schema {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.source-panel__grid--schema .source-panel__item {
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  padding: 12px;
}
.source-panel__chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 30px;
  background: #f86349;
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.source-panel__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: #f86349;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.5;
  text-decoration: none;
}
.source-panel__link:hover {
  color: #ef4022;
  text-decoration: underline;
}
.source-panel__link:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
  border-radius: 5px;
}

/*  The status token → modifier class map, written out as full literal selectors so the
    five class names are greppable in this file and in the compiled stylesheet. This is
    the closed set PHP selects from; nothing outside it can be produced. */
.source-panel__item--pass .source-panel__item__mark {
  color: #30b55e;
  background: #f0fdf4;
}

.source-panel__item--warn .source-panel__item__mark {
  color: #f59e0b;
  background: #fffbeb;
}

.source-panel__item--fail .source-panel__item__mark {
  color: #dc3545;
  background: #fff5f5;
}

.source-panel__item--info .source-panel__item__mark {
  color: #111111;
  background: transparent;
}

.source-panel__item--absent .source-panel__item__mark {
  color: #959a9e;
  background: #f6f6f8;
}

/*
    Status pill (UI-SPEC status-pill / semantic status scale)

    The core data-encoding chip: good / warning / poor / neutral. Colour is MEANING,
    never decoration — and NEVER colour alone: every pill pairs the tone with an icon
    glyph (::before / .status-pill__icon) AND a text label (D-15, T-05-30). Used on
    site cards, the incidents table, the clients list.

    Markup: <span class="status-pill status-pill--{tone}">
              [<span class="status-pill__icon status-pill__icon--{icon}">]
              <span class="status-pill__label">…</span>
            </span>
*/
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 30px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
}
.status-pill__icon {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}
.status-pill__label {
  color: inherit;
}
.status-pill--good {
  color: #30b55e;
  background: #f0fdf4;
}
.status-pill--warning {
  color: #f59e0b;
  background: #fffbeb;
}
.status-pill--poor {
  color: #dc3545;
  background: #fff5f5;
}
.status-pill--neutral {
  color: #959a9e;
  background: #f6f6f8;
}

/*
    Tabs (UI-SPEC tabs / D-16)

    The site-detail Lighthouse mobile/desktop switch. Both panels are server-rendered;
    Plan 11 toggles the active one off [data-tab]. Underline-style tab bar with the
    coral accent on the active tab; the hidden panels carry the [hidden] attribute.

    Markup: template-parts/dashboard/site-detail.php
      .tabs ( .tabs__tab[.--active] ) + .tabs__panel[.--active]
*/
.tabs {
  display: flex;
  gap: 8px;
  border-bottom: 1px solid #cfd0d4;
  margin-bottom: 16px;
}
.tabs__tab {
  min-height: 44px;
  padding: 8px 16px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  font-size: 14px;
  font-weight: 600;
  text-transform: none;
  color: #959a9e;
  cursor: pointer;
}
.tabs__tab:hover {
  color: #111111;
}
.tabs__tab:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.tabs__tab--active {
  color: #f86349;
  border-bottom-color: #f86349;
}
.tabs__panel[hidden] {
  display: none;
}

/*
    Trend chart (UI-SPEC trend-chart / Charts contract / D-19)

    The Chart.js canvas wrapper on site detail. JS owns the line colours (accent line,
    muted dashed threshold); this only frames the canvas and shows the shared empty
    state ("Not enough history yet") when there is no series — never an empty axis.

    Markup: template-parts/dashboard/site-detail.php
      .trend-chart ( __title canvas.trend-chart__canvas .trend-chart__empty )
*/
.trend-chart {
  padding: 24px;
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
}
.trend-chart__title {
  margin: 0 0 16px;
  font-size: 18px;
  font-weight: 600;
  color: #111111;
}
.trend-chart__canvas {
  display: block;
  width: 100% !important;
  max-height: 280px;
}
.trend-chart__canvas[hidden] {
  display: none;
}

/*
    Sections Manifest

    Import ACF Flexible Content section styles here (alphabetical order).
    Each section corresponds to a layout in the Sections field group.

    Creating a new section:
        1. Create css/sections/_my-section.scss
        2. Add @use 'my-section'; below
        3. PHP template: template-parts/sections/s-my-section.php

    Section structure:
        .section-my-section {
            padding: $section-spacing-y 0;

            .title { }
            .content { }
        }
*/
/*
    Clients view (UI-SPEC Clients — ADM-07 / D-08)

    Primary anchor: the client list (name + contact + portal-access status pill). The
    add-client form sits beside/below it in its own card. The forbidden branch reuses
    the empty-state.

    Markup: template-parts/dashboard/clients.php (+ partials/client-form.php)
*/
.clients {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 32px;
  align-items: start;
  /* ---- LIST ---- */
  /* ---- ADD-CLIENT CARD ---- */
}
@media (max-width: 992px) {
  .clients {
    grid-template-columns: 1fr;
  }
}
.clients__header {
  grid-column: 1/-1;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.clients__title {
  margin: 0;
  font-size: 32px;
  font-weight: 600;
  color: #111111;
}
.clients__subtitle {
  margin: 0;
  font-size: 14px;
  color: #959a9e;
}
.clients__list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  overflow: hidden;
}
.clients__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 24px;
}
.clients__item + .clients__item {
  border-top: 1px solid #cfd0d4;
}
.clients__item-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.clients__name {
  font-size: 14px;
  font-weight: 600;
  color: #111111;
}
.clients__contact {
  font-size: 12px;
  color: #959a9e;
}
.clients__add {
  padding: 24px;
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  box-shadow: 0 25px 7px 0 rgba(105, 105, 105, 0), 0 16px 6px 0 rgba(105, 105, 105, 0.01), 0 9px 5px 0 rgba(105, 105, 105, 0.05), 0 4px 4px 0 rgba(105, 105, 105, 0.08), 0 1px 2px 0 rgba(105, 105, 105, 0.09);
}
.clients__add-title {
  margin: 0 0 16px;
  font-size: 18px;
  font-weight: 600;
  color: #111111;
}

.client-form__actions {
  margin-top: 16px;
}

/*
    Compare view (UI-SPEC Compare — ADM-06 / D-18)

    A "choose up to 3 sites" selector card, then the side-by-side metric matrix (one
    column per site). Reconciled against .planning/design/ (02-compare): avatar chips
    on the column heads, big values with the leader marked coral "Best" and the others
    carrying a "−x% vs best" delta. The matrix scrolls horizontally on narrow screens.

    Markup: template-parts/dashboard/compare.php
*/
/* ---- Weekly-source cells: the per-cell capture age and the security sub-value ----

   PER CELL, NEVER PER ROW AND NEVER PER COLUMN (07-UI-SPEC.md §6 / D-25). A weekly check
   can be seven days older than the cell beside it, so one age for a whole row would be a
   lie about at least one of its values. That is also why the four weekly rows carry no
   "Best" chip: see compare.php section 5b.

   The stale variant recolours the chip, and the template ALWAYS puts the word "stale"
   inside it. Colour is reinforcement, never the message — the chip has to survive
   greyscale, a printed page and a screen reader. */
.compare-age {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: #959a9e;
  font-variant-numeric: tabular-nums;
}
.compare-age--stale {
  color: #f59e0b;
  font-weight: 700;
}

/*  The muted "· {score}/{max}" that trails the security grade. */
.compare-sub {
  font-size: 12px;
  font-weight: 400;
  color: #959a9e;
  font-variant-numeric: tabular-nums;
}

.compare {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* ---- Selector card ---- */
.compare-picker {
  padding: 24px 32px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
}
.compare-picker__label {
  margin: 0 0 16px;
  font-size: 14px;
  font-weight: 700;
  color: #111111;
}
.compare-picker__row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
}
.compare-picker__select {
  flex: 1 1 180px;
  min-width: 0;
  min-height: 44px;
  padding: 8px 16px;
  border: 1px solid #d1d5db;
  border-radius: 5px;
  background: #fff;
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: #111111;
}
.compare-picker__select:focus {
  outline: none;
  border-color: #f86349;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.compare-picker__go {
  flex: 0 0 auto;
}

/* ---- Matrix ---- */
.compare__matrix-wrap {
  overflow-x: auto;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
}

.compare-matrix {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  /* Site column heads: avatar + name + url */
  /* Group header rows (CWV / Uptime / Freshness) */
  /* Score cells: big value + Best/delta tag */
}
.compare-matrix th,
.compare-matrix td {
  padding: 16px 24px;
  text-align: left;
  border-bottom: 1px solid #cfd0d4;
  vertical-align: middle;
}
.compare-matrix tbody tr:last-child th,
.compare-matrix tbody tr:last-child td {
  border-bottom: 0;
}
.compare-matrix__site-head {
  vertical-align: middle;
}
.compare-matrix__site {
  display: flex;
  align-items: center;
  gap: 12px;
}
.compare-matrix__avatar {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}
.compare-matrix__avatar--a {
  background: #f86349;
}
.compare-matrix__avatar--b {
  background: #323643;
}
.compare-matrix__avatar--c {
  background: #30b55e;
}
.compare-matrix__site-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}
.compare-matrix__site-name {
  font-weight: 700;
  color: #111111;
  text-decoration: none;
  white-space: nowrap;
}
.compare-matrix__site-name:hover {
  color: #f86349;
}
.compare-matrix__site-url {
  font-size: 12px;
  font-weight: 400;
  color: #959a9e;
}
.compare-matrix__group th {
  padding-top: 16px;
  padding-bottom: 8px;
  background: transparent;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #959a9e;
  border-bottom: 0;
}
.compare-matrix__metric, .compare-matrix__metric-head {
  font-weight: 600;
  color: #111111;
}
.compare-matrix__metric-head {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #959a9e;
}
.compare-matrix__value {
  font-variant-numeric: tabular-nums;
  color: #111111;
}
.compare-matrix__num {
  display: block;
  font-size: 24px;
  font-weight: 700;
  line-height: 1.1;
  color: #111111;
}
.compare-matrix__num--best {
  color: #f86349;
}
.compare-matrix__tag {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: #959a9e;
}
.compare-matrix__tag--best {
  color: #f86349;
  font-weight: 700;
}

/*
    Incidents log view (UI-SPEC Incidents — ADM-08 / D-14)

    Primary anchor: the paged data-table of incidents. Above it a filter bar (status
    pills + a source select). The table itself is styled by the data-table component;
    this only lays out the view chrome + the source-filter control.

    Markup: template-parts/dashboard/incidents.php
*/
.incidents {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.incidents__header {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.incidents__title {
  margin: 0;
  font-size: 32px;
  font-weight: 600;
  color: #111111;
}
.incidents__subtitle {
  margin: 0;
  font-size: 14px;
  color: #959a9e;
}
.incidents__controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.incidents__source-filter {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.incidents__source-label {
  font-size: 12px;
  font-weight: 600;
  color: #959a9e;
}
.incidents__source-select {
  min-height: 44px;
  padding: 4px 16px;
  border: 1px solid #d1d5db;
  border-radius: 5px;
  background: #fff;
  font-size: 14px;
  font-family: "proxima-nova", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: #111111;
}
.incidents__source-select:focus {
  outline: none;
  border-color: #f86349;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}

/*
    Overview view (UI-SPEC Overview — ADM-02)

    Primary anchor: the KPI row. Secondary: sites-needing-attention (left) + the
    performance leaderboard (right). Supporting panels beneath. Reconciled against
    .planning/design/ (Overview screenshot): a two-column band, panels with a title +
    subtitle, coloured status dots, and leaderboard score bars. The KPI row is SIX tiles
    since Phase 7 (D-17) — the design draws four and has no six-tile reference, so the
    responsive ladder below is the UI contract's decision rather than a design lift.

    Markup: template-parts/dashboard/overview.php
*/
.overview {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  grid-auto-rows: min-content;
  align-items: start;
  gap: 24px;
}
.overview .kpi-row {
  grid-column: 1/-1;
}
.overview .attention-panel {
  grid-column: 1;
}
.overview .leaderboard-panel {
  grid-column: 2;
}
.overview .incidents-panel {
  grid-column: 1;
}
.overview .activity-panel {
  grid-column: 2;
}
@media (max-width: 992px) {
  .overview {
    grid-template-columns: 1fr;
  }
  .overview .attention-panel,
  .overview .leaderboard-panel,
  .overview .incidents-panel,
  .overview .activity-panel {
    grid-column: 1;
  }
}

/* ---- 1) KPI ROW (primary anchor) ----

   THE ONLY PLACE THE COLUMN COUNT LIVES (07-UI-SPEC.md §7 / R11). The view emits
   `class="kpi-row"` and nothing else; it used to emit an inline column count as well, which
   silently beat every breakpoint below. Adding a seventh tile is one number, here.

   Six tiles across a 1200px viewport, minus the 236px nav rail, leaves about 145px per tile
   — too narrow for a 34px numeral above a caption. So THREE BY TWO IS THE DEFAULT and
   six-across is the 1600px-and-up treatment, not the other way round. The 6-tile ladder has
   no design reference (the design draws four); the fall-down is the UI contract's decision.

   Desktop-first max-width steps below the default, matching the rest of this file. Their
   order matters: at 400px both the md and the xs query match and the last one wins. */
.kpi-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-bottom: 24px;
}
@media (min-width: 1600px) {
  .kpi-row {
    grid-template-columns: repeat(6, 1fr);
  }
}
@media (max-width: 992px) {
  .kpi-row {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 576px) {
  .kpi-row {
    grid-template-columns: 1fr;
  }
}

/* ---- Shared panel chrome ---- */
.overview-panel {
  padding: 24px 32px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
}
.overview-panel__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}
.overview-panel__title {
  margin: 0;
  font-size: 24px;
  font-weight: 700;
  color: #111111;
}
.overview-panel__subtitle {
  margin: 2px 0 0;
  font-size: 12px;
  color: #959a9e;
}
.overview-panel__link {
  flex-shrink: 0;
  font-size: 14px;
  font-weight: 600;
  color: #f86349;
  text-decoration: none;
  white-space: nowrap;
}
.overview-panel__link:hover {
  color: #ef4022;
}

/* ---- Lists inside the panels ---- */
.attention-list,
.leaderboard,
.incident-list,
.activity-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.attention-list__item,
.leaderboard__item,
.incident-list__item,
.activity-list__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  font-size: 14px;
}
.attention-list__item + li,
.leaderboard__item + li,
.incident-list__item + li,
.activity-list__item + li {
  border-top: 1px solid #cfd0d4;
}

/* ---- 2) Attention: dot + 2-line meta + reason chip ---- */
.attention-list__dot {
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #959a9e;
}
.attention-list__dot--good {
  background: #30b55e;
}
.attention-list__dot--warning {
  background: #f59e0b;
}
.attention-list__dot--poor {
  background: #dc3545;
}
.attention-list__dot--neutral {
  background: #959a9e;
}

.attention-list__meta {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}

.attention-list__name {
  font-weight: 600;
  color: #111111;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.attention-list__name:hover {
  color: #f86349;
}

.attention-list__url {
  font-size: 12px;
  color: #959a9e;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.attention-list .reason-chip {
  flex-shrink: 0;
  margin-left: auto;
}

/* ---- 3) Leaderboard: rank + name + score bar + score ---- */
.leaderboard {
  counter-reset: rank;
}
.leaderboard__item {
  counter-increment: rank;
}
.leaderboard__item::before {
  content: counter(rank);
  flex: 0 0 1.25em;
  font-size: 12px;
  font-weight: 700;
  color: #959a9e;
  font-variant-numeric: tabular-nums;
}
.leaderboard__name {
  flex: 0 1 auto;
  max-width: 42%;
  font-weight: 600;
  color: #111111;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.leaderboard__name:hover {
  color: #f86349;
}
.leaderboard__bar {
  flex: 1;
  height: 6px;
  border-radius: 30px;
  background: #f6f6f8;
  overflow: hidden;
}
.leaderboard__bar-fill {
  display: block;
  height: 100%;
  border-radius: 30px;
  background: #959a9e;
}
.leaderboard__bar-fill--good {
  background: #30b55e;
}
.leaderboard__bar-fill--needs-improvement {
  background: #f59e0b;
}
.leaderboard__bar-fill--poor {
  background: #dc3545;
}
.leaderboard__score {
  flex: 0 0 auto;
  min-width: 2.4em;
  text-align: right;
  font-weight: 700;
  color: #111111;
  font-variant-numeric: tabular-nums;
}

/* ---- 4/5) Incidents + activity (supporting) ---- */
.incident-list__site,
.activity-list__site {
  font-weight: 600;
  color: #111111;
}

.incident-list__ago,
.activity-list__ago {
  margin-left: auto;
  font-size: 12px;
  color: #959a9e;
}

.activity-list__what {
  color: #959a9e;
}

.incident-list__state {
  font-weight: 600;
  color: #959a9e;
}

/*
    Report view (CLI-02 / D-02 / D-04 / UI-SPEC report-view)

    The client-facing monthly report DOCUMENT — rendered entirely from the frozen
    snapshot (template-parts/dashboard/report.php) — plus the report-history list view.
    A report is a narrative document, so the content column has a bounded reading width
    (~780px, matching the theme's contentSize convention) and a generous vertical
    rhythm. Print-legible: no fixed chrome, colours preserved, page background white.

    Anchor (UI-SPEC visual hierarchy): the Scores (score-vs-target) block; the trend is
    secondary; uptime + summary are supporting reading.

    Tokens only (_variables.scss). Absent field data uses the shared .metric-absent
    glyph (never 0/red). Status colour is always paired with a text label.
*/
.report-view {
  max-width: 780px;
  margin: 0 auto;
  padding-bottom: 64px;
  color: #111111;
}
.report-view__back {
  display: inline-block;
  margin-bottom: 16px;
  color: #959a9e;
  font-weight: 600;
  font-size: 14px;
  text-decoration: none;
}
.report-view__back:hover {
  color: #111111;
}
.report-view__header {
  margin-bottom: 24px;
}
.report-view__eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #f86349;
  margin-bottom: 4px;
}
.report-view__titlerow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.report-view__title {
  font-size: 32px;
  font-weight: 600;
  line-height: 1.2;
  color: #111111;
  margin: 0;
}
.report-view__partial {
  margin-bottom: 24px;
  padding: 12px 16px;
  border-radius: 10px;
  background: #f6f6f8;
  border-left: 3px solid #959a9e;
  font-size: 14px;
  line-height: 1.5;
  color: #111111;
}
.report-view__shot {
  margin: 0 0 24px;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
  background: #f6f6f8;
}
.report-view__shot img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
}
.report-view__retention {
  margin-top: 48px;
  padding-top: 24px;
  border-top: 1px solid #cfd0d4;
  font-size: 14px;
  line-height: 1.5;
  color: #959a9e;
}
.report-view__retention strong {
  color: #111111;
}

/* ---- a report section: a heading + its body, on a card surface ---- */
.report-section {
  margin-top: 48px;
  padding: 24px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
}
.report-section__heading {
  font-size: 18px;
  font-weight: 600;
  line-height: 1.2;
  color: #111111;
  margin: 0 0 16px;
}

/* ---- Scores: score-vs-target (the anchor). Reuses the .score-card component. ---- */
.report-scores__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}
.report-scores__row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.report-scores__row:has(.report-scores__delta--improved) .score-card {
  box-shadow: inset 0 0 0 2px rgba(248, 99, 73, 0.4);
}
.report-scores__delta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
}
.report-scores__cwv {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-top: 16px;
}
@media (max-width: 576px) {
  .report-scores__cwv {
    grid-template-columns: 1fr;
  }
}
.report-scores__cwv-card {
  padding: 16px;
  border-radius: 10px;
  background: #f6f6f8;
  text-align: center;
}
.report-scores__cwv-abbr {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #959a9e;
}
.report-scores__cwv-value {
  font-size: 24px;
  font-weight: 600;
  line-height: 1.2;
  margin: 4px 0 2px;
}
.report-scores__cwv-name {
  font-size: 12px;
  color: #959a9e;
}

/* ---- Trends: the Chart.js canvas from the frozen snapshot series ---- */
.report-trend {
  position: relative;
  min-height: 260px;
}
.report-trend__canvas {
  width: 100%;
  max-height: 320px;
}
.report-trend__empty {
  color: #959a9e;
  font-size: 14px;
  line-height: 1.5;
  padding: 16px 0;
}

/* ---- Uptime & incidents ---- */
.report-uptime__figure {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 16px;
}
.report-uptime__pct {
  font-size: 32px;
  font-weight: 600;
  line-height: 1;
}
.report-uptime__unit {
  font-size: 18px;
}
.report-uptime__label {
  font-size: 14px;
  color: #959a9e;
}
.report-uptime__clean {
  font-size: 14px;
  line-height: 1.5;
  color: #959a9e;
  margin: 0;
}
.report-uptime__clean strong {
  color: #111111;
}
.report-uptime__list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.report-uptime__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid #f6f6f8;
  font-size: 14px;
}
.report-uptime__dot {
  flex: 0 0 9px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
}
.report-uptime__state {
  flex: 1;
  font-weight: 600;
  color: #111111;
}
.report-uptime__when {
  color: #959a9e;
  font-size: 12px;
}

/* ---- Security headers + Technical SEO (D-27/D-28, 07-UI-SPEC §9) ------------------

    LAYOUT ONLY. These two sections reuse `.report-section` for their card chrome and
    `.report-section__heading` for their titles, so NO new typography token enters the
    report type scale and both inherit the print rules below unchanged. The item rows
    reuse `.source-panel__item` and its five status modifiers from
    `components/_source-panel.scss` — the closed set PHP selects from — and the grade
    circle reuses `.grade-circle` from `components/_grade-circle.scss`.

    WHAT THIS BLOCK DELIBERATELY DOES NOT DO: it does not re-declare the grade circle's
    print behaviour. `_grade-circle.scss` already ships both mechanisms (print-color-adjust
    plus an `@media print` inversion to a ring in the tone colour), and a second copy here
    is exactly how the two drift until a client prints a white letter on white paper.
*/
.report-source__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}
.report-source__head .report-section__heading {
  margin-bottom: 0;
}
.report-source__subtitle {
  font-size: 14px;
  line-height: 1.5;
  color: #959a9e;
  margin: 4px 0 0;
}
.report-source__grade {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
}
.report-source__score {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  color: #959a9e;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.report-source__empty {
  font-size: 14px;
  line-height: 1.5;
  color: #959a9e;
  margin: 0;
}
.report-source__list {
  margin: 0;
}
.report-source__grid {
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
}

/* ---- Summary & recommendations: the approved AI prose (rendered via wp_kses_post) ---- */
.report-summary__prose {
  font-size: 16px;
  line-height: 1.5;
  color: #111111;
}
.report-summary__prose p {
  margin: 0 0 16px;
}
.report-summary__prose ul,
.report-summary__prose ol {
  margin: 0 0 16px;
  padding-left: 24px;
}
.report-summary__prose li {
  margin-bottom: 4px;
}
.report-summary__prose a {
  color: #f86349;
}
.report-summary__prose a:hover {
  color: #ef4022;
}
.report-summary__prose strong {
  font-weight: 600;
}

/* ---- Report history (the list view; the report-card component is styled separately) ---- */
.report-history {
  max-width: 780px;
  margin: 0 auto;
}
.report-history__heading {
  font-size: 32px;
  font-weight: 600;
  line-height: 1.2;
  color: #111111;
  margin: 0 0 24px;
}
.report-history__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.report-history__empty {
  margin-top: 16px;
}

/* ---- Print legibility: drop the app chrome, keep the document + its colours ---- */
@media print {
  .report-view {
    max-width: none;
    margin: 0;
    padding: 0;
  }
  .report-view__back,
  .report-view__shot {
    display: none;
  }
  .report-section {
    box-shadow: none;
    border: 1px solid #cfd0d4;
    break-inside: avoid;
  }
  .report-source__grid .source-panel__item {
    break-inside: avoid;
  }
}
/*
    Site detail view (UI-SPEC Site detail — ADM-04 / D-13 / D-16)

    Two-column layout (design cwv screenshot): a wide MAIN column with the Lighthouse
    scores, Core Web Vitals and the trend, and a narrower SIDE rail with the live
    screenshot, an Uptime card and the incident list. Header spans the full width.
    Panels are white, soft-shadowed, borderless — matching the rest of the dashboard.

    Markup: template-parts/dashboard/site-detail.php
*/
.site-detail {
  display: flex;
  flex-direction: column;
  gap: 24px;
  /* ---- HEADER (full width) ---- */
  /* ---- TWO-COLUMN BODY ---- */
  /* ---- PANELS ---- */
  /* ==================================================================
     THE PHASE-7 SOURCE-PANEL BANDS (07-UI-SPEC.md §"1-4. Site detail")

     WHAT THESE RULES DO: position the four Phase-7 panels on this screen —
     two full-width bands beneath the two-column body, their responsive
     collapse, the orphan case and the vertical rhythm between them.

     WHAT THEY DELIBERATELY DO NOT DO: style a panel. Every visual property
     of the panel itself — the card chrome, the head, the item row, the five
     status modifiers, the SEO and schema cell grids, the accent chip, the
     out-link — lives in css/components/_source-panel.scss, and the grade
     circle and breakdown bar in _grade-circle.scss / _breakdown-bar.scss.
     Re-declaring any of it here would fork the single home of the
     status → modifier-class map, which is the phase's security control.

     WHY A CLASS-BASED BAND SITS BESIDE INLINE-STYLED NEIGHBOURS: 07-UI-SPEC.md
     §"Styling idiom, assigned per surface" assigns these panels to tokenised
     classes because a payload-derived `status` must select a class and can
     never reach a `style=` attribute, and because an inline style cannot
     express :hover, @media or @media print. Its token → inline-neighbour
     equivalence table is why the two idioms are visually indistinguishable
     here: same $color-card-bg white, same $border-radius-md 10px,
     byte-identical $shadow-card, and $spacing-lg padding against the design's
     off-scale 22px. The reconciliation direction is towards tokens, never
     away — no new colour, spacing, breakpoint or font value enters below.
     ================================================================== */
  /*  THE ORPHAN RULE. Emitted by the template when exactly one of security /
      SEO renders, and unconditionally by the structured-data band. One
      full-width column at every size: a lone narrow card beside empty space
      reads as a layout bug, not as a check that is switched off. The rule
      lives here rather than in a second inline grid declaration in the
      template so there is one place to change it. */
  /*  The major band break above the structured-data band (07-UI-SPEC.md
      §Spacing Scale: $spacing-2xl "major band break above the structured-data
      panel"). It overrides the ordinary between-band $spacing-lg because this
      is the break between "what your server and markup say" and the schema
      readout, not another panel in the same group. */
  /*  The head right-slot stack: a grade circle with its "{score}/{max}" line
      beneath. Pure positioning — the circle's size and tone come from
      _grade-circle.scss and the caption reuses .source-panel__subtitle, so
      this declares no colour, no size and no typography of its own. */
  /* ---- RUNNING-FIRST-SCAN (enabled but never scanned) ---- */
}
.site-detail--forbidden {
  max-width: 640px;
}
.site-detail__header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 16px;
}
.site-detail__title {
  margin: 0;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #111111;
}
.site-detail__url {
  font-size: 14px;
  color: #f86349;
  text-decoration: none;
}
.site-detail__url:hover {
  text-decoration: underline;
}
.site-detail__ago {
  font-size: 12px;
  color: #959a9e;
}
.site-detail__actions {
  margin-left: auto;
  display: flex;
  gap: 8px;
  align-items: center;
}
.site-detail__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 336px;
  gap: 24px;
  align-items: start;
}
@media (max-width: 992px) {
  .site-detail__grid {
    grid-template-columns: 1fr;
  }
}
.site-detail__main, .site-detail__side {
  display: flex;
  flex-direction: column;
  gap: 24px;
  min-width: 0;
}
.site-detail__panel {
  padding: 24px 32px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0px 309px 87px 0px rgba(0, 0, 0, 0), 0px 198px 79px 0px rgba(0, 0, 0, 0.01), 0px 111px 67px 0px rgba(0, 0, 0, 0.02), 0px 49px 49px 0px rgba(0, 0, 0, 0.03), 0px 12px 27px 0px rgba(0, 0, 0, 0.03);
}
.site-detail__panel-title {
  margin: 0 0 16px;
  font-size: 18px;
  font-weight: 700;
  color: #111111;
}
.site-detail__panel-band {
  display: grid;
  /*  Security narrower than technical SEO on purpose: the header list is a
      column of short rows, the SEO grid is eight cells that want the room. */
  grid-template-columns: 1fr 1.4fr;
  gap: 16px;
  margin-top: 24px;
  align-items: start;
  /*  Collapses with the rest of the layout, at the same breakpoint the
      two-column body above uses. */
}
@media (max-width: 992px) {
  .site-detail__panel-band {
    grid-template-columns: 1fr;
  }
}
.site-detail__panel-band--single {
  grid-template-columns: 1fr;
}
.site-detail__panel-band--major {
  margin-top: 48px;
}
.site-detail__panel-grade {
  flex: 0 0 auto;
  text-align: center;
}
.site-detail__first-scan {
  padding: 24px;
  background: #fffbeb;
  border-radius: 10px;
  color: #111111;
}
.site-detail__first-scan-badge {
  margin: 0 0 4px;
  color: #f59e0b;
}

/* ---- SCORE CARD GRID (per Lighthouse tab panel) ---- */
.score-card-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}
@media (max-width: 1200px) {
  .score-card-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 576px) {
  .score-card-grid {
    grid-template-columns: 1fr;
  }
}

/* ---- CORE WEB VITALS BLOCK ---- */
.cwv-block {
  margin-top: 32px;
}
.cwv-block__title {
  margin: 0 0 16px;
  font-size: 16px;
  font-weight: 700;
  color: #111111;
}
.cwv-block__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px;
}
.cwv-block__note {
  margin: 16px 0 0;
  font-size: 12px;
  color: #959a9e;
}

/* ---- UPTIME (side-rail card) ---- */
.uptime-panel__value {
  margin: 0;
  font-size: 36px;
  font-weight: 800;
  line-height: 1.05;
  color: #30b55e;
}
.uptime-panel__value .metric-absent {
  font-size: 18px;
  font-weight: 700;
}

/* ---- INCIDENT LIST (shared look with overview) ---- */
.site-detail .incident-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-detail .incident-list__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  font-size: 14px;
}
.site-detail .incident-list__item + li {
  border-top: 1px solid #cfd0d4;
}
.site-detail .incident-list__source {
  font-weight: 600;
  color: #111111;
}
.site-detail .incident-list__state {
  color: #959a9e;
}
.site-detail .incident-list__ago {
  margin-left: auto;
  font-size: 12px;
  color: #959a9e;
}

/*
    Add / edit site form view (UI-SPEC form — ADM-05 / D-06)

    A single-column native form in a white card: the primary anchor is the form
    itself, carrying one primary CTA (Add site / Save changes). Fields are styled by
    the form-field component; this lays out the view chrome + the actions row.

    Markup: template-parts/dashboard/partials/site-form.php
*/
.site-form-view {
  max-width: 640px;
}
.site-form-view__header {
  margin-bottom: 24px;
}
.site-form-view__title {
  margin: 0 0 4px;
  font-size: 32px;
  font-weight: 600;
  color: #111111;
}
.site-form-view__subtitle {
  margin: 0;
  font-size: 14px;
  color: #959a9e;
}

.site-form {
  padding: 32px;
  background: #fff;
  border: 1px solid #cfd0d4;
  border-radius: 10px;
  box-shadow: 0 25px 7px 0 rgba(105, 105, 105, 0), 0 16px 6px 0 rgba(105, 105, 105, 0.01), 0 9px 5px 0 rgba(105, 105, 105, 0.05), 0 4px 4px 0 rgba(105, 105, 105, 0.08), 0 1px 2px 0 rgba(105, 105, 105, 0.09);
}
.site-form__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid #cfd0d4;
}
.site-form__pause {
  margin-left: auto;
}

/*
    Sites list view (UI-SPEC Sites — ADM-03)

    Primary anchor: the grid of per-site score cards. Secondary control: the status
    filter bar above it, with the "Compare selected" CTA. Reconciled against
    .planning/design/ (a responsive card grid).

    Markup: template-parts/dashboard/sites.php
*/
.sites {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.sites__controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.sites__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
}

/* ---- STATUS FILTER BAR (shared with incidents) ---- */
.status-filter {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
}
.status-filter__btn {
  min-height: 44px;
  padding: 4px 16px;
  border: 1px solid #cfd0d4;
  border-radius: 30px;
  background: #fff;
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  color: #959a9e;
  cursor: pointer;
}
.status-filter__btn:hover {
  color: #111111;
  border-color: #111111;
}
.status-filter__btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(248, 99, 73, 0.45);
}
.status-filter__btn--active, .status-filter__btn--active:hover {
  background: #f86349;
  border-color: #f86349;
  color: #fff;
}

/*
    Homepage-Specific Styles

    Styles that ONLY apply to the homepage.
    Use sparingly — prefer reusable section styles instead.

    Target with body.home class from WordPress.
*/

/*# sourceMappingURL=style.css.map */
