/* common.css - Refined Dark Authority Design System */

/* General Sans: self-hosted, no cookies */
@font-face{font-family:'General Sans';src:url('/fonts/general-sans-300.woff2') format('woff2');font-weight:300;font-style:normal;font-display:swap}
@font-face{font-family:'General Sans';src:url('/fonts/general-sans-400.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'General Sans';src:url('/fonts/general-sans-500.woff2') format('woff2');font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:'General Sans';src:url('/fonts/general-sans-600.woff2') format('woff2');font-weight:600;font-style:normal;font-display:swap}
/* Syne: self-hosted, no cookies */
@font-face{font-family:'Syne';src:url('/fonts/syne-latin.woff2') format('woff2');font-weight:400 800;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Syne';src:url('/fonts/syne-latin-ext.woff2') format('woff2');font-weight:400 800;font-style:normal;font-display:swap;unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
/* JetBrains Mono: self-hosted, no cookies */
@font-face{font-family:'JetBrains Mono';src:url('/fonts/jetbrains-mono-latin.woff2') format('woff2');font-weight:400 700;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'JetBrains Mono';src:url('/fonts/jetbrains-mono-latin-ext.woff2') format('woff2');font-weight:400 700;font-style:normal;font-display:swap;unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

:root{
    --bg-deep:#080b14;
    --bg-primary:#0c1021;
    --bg-surface:#111729;
    --bg-surface-hover:#161d33;
    --bg-elevated:#1a2240;
    --accent:#64ffda;
    --accent-warm:#f0a500;
    --accent-warm-dim:rgba(240,165,0,.12);
    /* Third accent. Already in the palette as the CVE "insane" severity;
       promoted to a token so the service router can give each buyer its own
       colour without inventing a hue. Mint is the organisation, amber the
       consultancy, purple the person learning. */
    --accent-alt:#bf5af2;
    --accent-alt-dim:rgba(191,90,242,.12);
    --accent-dim:rgba(100,255,218,.08);
    --accent-glow:rgba(100,255,218,.15);
    --danger:#ff4757;
    --text-bright:#f0f4ff;
    --text-primary:#cdd6e8;
    --text-secondary:#8494ad;
    /* Bumped from #4d5f77 (≈4:1 contrast on bg) to clear AA for normal text.
       Used for dates, read-time, group labels, footer legal, search-result
       snippets, prism comments. */
    --text-muted:#8294af;
    --border:rgba(100,255,218,.08);
    --border-hover:rgba(100,255,218,.2);
    --radius:6px;
    --radius-lg:12px;
    --radius-pill:20px;
    --space-1:.25rem;
    --space-2:.5rem;
    --space-3:.75rem;
    --space-4:1rem;
    --space-5:1.5rem;
    --space-6:2rem;
    --space-7:3rem;
    --space-8:4rem;
    --font-display:'Syne',sans-serif;
    --font-body:'General Sans','Outfit','Segoe UI',sans-serif;
    --font-mono:'JetBrains Mono',monospace
}

/* ─── Light theme ─── */
html[data-theme="light"]{
    --bg-deep:#f5f6fa;
    --bg-primary:#ecedf2;
    --bg-surface:#ffffff;
    --bg-surface-hover:#f0f1f5;
    --bg-elevated:#e8e9f0;
    --accent:#0d7d5f;
    --accent-warm:#c47f00;
    --accent-warm-dim:rgba(196,127,0,.1);
    --accent-alt:#7c2bb3;
    --accent-alt-dim:rgba(124,43,179,.09);
    --accent-dim:rgba(13,125,95,.07);
    --accent-glow:rgba(13,125,95,.12);
    --danger:#d63243;
    --text-bright:#111827;
    --text-primary:#374151;
    --text-secondary:#6b7280;
    /* Bumped from #9ca3af (≈2.6:1 on white, AA-fail) to #5e6878 (≈5.3:1). */
    --text-muted:#5e6878;
    --border:rgba(0,0,0,.08);
    --border-hover:rgba(0,0,0,.18);
    --noise-opacity:.08
}
html[data-theme="light"] .sev-critical{background:rgba(214,50,67,.1);color:#b52a38}
html[data-theme="light"] .sev-high{background:rgba(204,80,30,.1);color:#cc501e}
html[data-theme="light"] .sev-medium{background:rgba(180,140,0,.1);color:#8a6d00}
html[data-theme="light"] .sev-low{background:rgba(13,125,95,.1);color:#0d7d5f}
html[data-theme="light"] .sev-insane{background:rgba(140,50,190,.1);color:#8c32be}

*{margin:0;padding:0;box-sizing:border-box}
/* overflow-x on the root is clip, not hidden. On iOS Safari `hidden` here
   establishes a scroll container, and a scroll container on the root breaks
   `position:fixed` for descendants: with viewport-fit=cover the fixed header
   stops being pinned to the visual viewport and page content bleeds into the
   safe-area band above it. `clip` clips the same overflow without creating
   that container, so the header stays pinned. `hidden` is kept first as the
   fallback for engines that do not know `clip`. */
html{
    scroll-behavior:smooth;
    scroll-padding-top:80px;
    background:var(--bg-deep);
    overflow-x:hidden;
    overflow-x:clip
}

body{
    font-family:var(--font-body);
    background:var(--bg-deep);
    color:var(--text-primary);
    line-height:1.6;
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale;
    transition:background-color .3s,color .3s
}

/* Noise texture overlay */
body::before{
    content:'';
    position:fixed;
    inset:0;
    background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.03'/%3E%3C/svg%3E");
    pointer-events:none;
    z-index:900;
    opacity:var(--noise-opacity,.4)
}

/* Typography */
h1,h2,h3,h4,h5,h6{font-family:var(--font-display);font-weight:700;color:var(--text-bright);line-height:1.15;letter-spacing:-.01em}
/* Explicit h1 sizing so browsers don't warn about a sectioned <h1> with no
   element-level font-size or margin. Per-page class styles (.hero-title,
   .post-title, .section-title, etc.) override these. */
h1{font-size:2rem;margin:.67em 0}

/* Links */
a{color:var(--accent);text-decoration:none;transition:color .2s}
a:hover{color:var(--text-bright)}

/* Keyboard focus: visible outline on any focusable interactive element.
   Uses :focus-visible so mouse clicks don't draw rings. */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible{
    outline:2px solid var(--accent);
    outline-offset:2px;
    border-radius:var(--radius)
}
/* Light theme needs a slightly darker ring on pale surfaces */
html[data-theme="light"] a:focus-visible,
html[data-theme="light"] button:focus-visible,
html[data-theme="light"] [tabindex]:focus-visible,
html[data-theme="light"] input:focus-visible,
html[data-theme="light"] textarea:focus-visible,
html[data-theme="light"] select:focus-visible{
    outline-color:var(--accent-warm)
}

/* Icons */
.icon{width:1em;height:1em;fill:currentColor;vertical-align:-.1em}
/* Icon size modifiers: replaces inline style="width:…em;height:…em" so we
   can keep CSP style-src tight and avoid inline-style churn. */
.icon-sm{width:.8em;height:.8em}
.icon-md{width:.9em;height:.9em}
.icon-lg{width:1.2em;height:1.2em}
/* Utility: horizontally-center flex/grid children. Used on svc-cta-row. */
.u-center{justify-content:center}
/* Utility: dim monospace text for noscript fallbacks, meta strings. */
.u-noscript-hint{color:var(--text-secondary);font-size:.85rem;font-family:var(--font-mono)}

/* ─── iOS safe-area cover ─── */
body::after{
    content:'';
    position:fixed;
    top:0;left:0;right:0;
    height:constant(safe-area-inset-top);
    height:env(safe-area-inset-top);
    background:var(--bg-deep);
    z-index:1001;
    pointer-events:none
}

/* ─── Header & Nav ─── */
header{
    position:fixed;top:0;left:0;right:0;
    background:var(--bg-deep);
    z-index:1000;
    border-bottom:1px solid var(--border);
    transition:all .3s;
    padding-top:constant(safe-area-inset-top);
    padding-top:env(safe-area-inset-top)
}
header::after{
    content:'';position:absolute;bottom:0;left:0;right:0;
    height:1px;
    background:linear-gradient(90deg,transparent,var(--accent),transparent);
    opacity:.25
}

nav{
    max-width:1100px;margin:0 auto;
    padding:1rem 2rem;
    display:flex;justify-content:space-between;align-items:center;
    transition:padding .3s
}

.logo{
    font-family:var(--font-display);
    font-size:1.1rem;font-weight:700;
    color:var(--text-bright);text-decoration:none;
    letter-spacing:-.02em;
    transition:color .2s
}
.logo:hover{color:var(--accent)}

.nav-links{display:flex;gap:1.6rem;list-style:none;align-items:center}

.nav-links a{
    color:var(--text-secondary);text-decoration:none;
    font-family:var(--font-mono);font-size:.78rem;
    letter-spacing:.3px;
    transition:color .2s;
    position:relative;
    padding:.2rem 0
}
.nav-links a:hover,.nav-links a.active{color:var(--accent)}
.nav-links a::after{
    content:'';position:absolute;bottom:0;left:0;
    width:0;height:1.5px;
    background:var(--accent);
    transition:width .25s ease
}
.nav-links a:hover::after,.nav-links a.active::after{width:100%}
.nav-links a.nav-cta{
    padding:.5rem .8rem;
    border:1px solid var(--accent);
    border-radius:var(--radius);
    color:var(--accent);
    font-weight:600
}
.nav-links a.nav-cta:hover{
    background:var(--accent);
    color:var(--bg-deep)
}
.nav-links a.nav-cta::after{display:none}

/* Language toggle */
.lang-toggle{
    display:flex;
    border:1px solid var(--border);
    border-radius:var(--radius);
    overflow:hidden;
    margin-left:.3rem
}
.lang-toggle button,.lang-toggle a{
    background:0 0;color:var(--text-muted);border:none;
    padding:.3rem .55rem;
    font-family:var(--font-mono);font-size:.72rem;
    cursor:pointer;transition:all .2s;
    display:flex;align-items:center;justify-content:center;gap:.3rem;
    min-height:36px;
    text-decoration:none
}
.lang-toggle button.active,.lang-toggle a.active{background:var(--accent-dim);color:var(--accent)}
.lang-toggle button:hover:not(.active),.lang-toggle a:hover:not(.active){color:var(--text-secondary)}
.flag-icon{font-style:normal;font-size:.85rem;line-height:1}

/* Theme toggle */
.theme-toggle{
    background:0 0;border:1px solid var(--border);
    border-radius:var(--radius);
    padding:.35rem .55rem;
    cursor:pointer;transition:all .2s;
    display:flex;align-items:center;justify-content:center;
    margin-left:.3rem;
    color:var(--text-muted);
    line-height:1;
    min-width:36px;min-height:36px
}
.theme-toggle:hover{color:var(--accent);border-color:var(--border-hover)}
.theme-toggle svg{width:16px;height:16px;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.theme-toggle .icon-moon{display:block;fill:currentColor;stroke:none}
.theme-toggle .icon-sun{display:none;fill:none}
html[data-theme="light"] .theme-toggle .icon-sun{display:block}
html[data-theme="light"] .theme-toggle .icon-moon{display:none}

/* Skip-to-content link: visually hidden until keyboard-focused. The first
   tab on any page lets a keyboard or screen-reader user jump past the
   header straight into <main>. Required for WCAG 2.1 (2.4.1 Bypass Blocks).
   :focus-visible (not :focus) so a touch-tap doesn't leave the button
   parked on screen: mobile Safari treats tap as focus, and without
   :focus-visible the link would stay visible after the user jumps. */
.skip-link{
    position:fixed;
    top:.5rem;left:.5rem;
    padding:.7rem 1.1rem;
    background:var(--accent);
    color:var(--bg-deep);
    font-family:var(--font-mono);
    font-size:.85rem;
    font-weight:600;
    text-decoration:none;
    border-radius:var(--radius);
    z-index:10000;
    /* Double hide: off-screen via transform (for animation) AND
       visibility:hidden so a UA ignoring the transform (or a stale cached
       stylesheet) still keeps the link out of sight. */
    transform:translateY(-150%);
    visibility:hidden;
    transition:transform .2s ease
}
.skip-link:focus-visible{transform:translateY(0);visibility:visible}

/* Visible, accent-colored focus ring on all keyboard-focusable elements.
   Mouse clicks don't trigger :focus-visible, so this only shows for users
   navigating with Tab: which is exactly who needs it. */
:focus-visible{
    outline:2px solid var(--accent);
    outline-offset:2px;
    border-radius:2px
}
/* Buttons and links already have their own hover styles; suppress the
   default browser outline for non-keyboard focus to avoid double-ring. */
:focus:not(:focus-visible){outline:none}

/* Search button: injected into nav by common.js */
.search-btn{
    background:0 0;border:1px solid var(--border);
    border-radius:var(--radius);
    padding:.32rem .5rem;
    cursor:pointer;transition:all .2s;
    display:flex;align-items:center;justify-content:center;
    color:var(--text-muted);
    line-height:1;
    min-width:36px;min-height:36px
}
.search-btn:hover{color:var(--accent);border-color:var(--accent)}
.search-btn svg{width:15px;height:15px}

/* Search modal */
body.ss-open{overflow:hidden}
.site-search{
    position:fixed;inset:0;
    z-index:1000;
    display:flex;align-items:flex-start;justify-content:center;
    padding-top:8vh
}
.site-search[hidden]{display:none}
.ss-backdrop{
    position:absolute;inset:0;
    background:rgba(8,12,20,.72);
    backdrop-filter:blur(4px);
    -webkit-backdrop-filter:blur(4px)
}
.ss-panel{
    position:relative;
    width:min(640px,calc(100% - 2rem));
    max-height:80vh;
    box-shadow:0 20px 60px rgba(0,0,0,.5);
    display:flex;flex-direction:column;
    overflow:hidden
}
.ss-input-row{
    display:flex;align-items:center;
    gap:.6rem;
    padding:1rem 1.1rem;
    border-bottom:1px solid var(--border)
}
.ss-input{
    flex:1;
    background:0 0;border:0;outline:0;
    color:var(--text-bright);
    font-family:var(--font-display);
    font-size:1rem;
    padding:.2rem 0;
    -webkit-appearance:none;appearance:none
}
.ss-input::placeholder{color:var(--text-muted)}
.ss-close{
    background:0 0;
    border:1px solid var(--border);
    border-radius:var(--radius);
    color:var(--text-muted);
    font-family:var(--font-mono);
    font-size:1.1rem;
    line-height:1;
    padding:.25rem .55rem;
    cursor:pointer;
    transition:color .2s,border-color .2s
}
.ss-close:hover{color:var(--accent);border-color:var(--accent)}
.ss-results{
    overflow-y:auto;
    padding:.4rem 0
}
.ss-empty{
    color:var(--text-secondary);
    font-family:var(--font-mono);
    font-size:.85rem;
    text-align:center;
    padding:2rem 1rem;margin:0
}
.ss-group{padding:.4rem 0}
.ss-group-title{
    color:var(--text-muted);
    font-family:var(--font-mono);
    font-size:.7rem;
    text-transform:uppercase;
    letter-spacing:.6px;
    padding:.2rem 1.1rem .35rem
}
.ss-hit{
    display:flex;flex-direction:column;gap:.2rem;
    padding:.55rem 1.1rem;
    text-decoration:none;
    border-left:2px solid transparent;
    transition:background .15s,border-color .15s
}
.ss-hit:hover,.ss-hit.active{
    background:var(--accent-dim);
    border-left-color:var(--accent)
}
.ss-hit-title{
    color:var(--text-primary);
    font-family:var(--font-display);
    font-size:.9rem;
    font-weight:600
}
.ss-hit:hover .ss-hit-title,
.ss-hit.active .ss-hit-title{color:var(--accent)}
.ss-hit-sub{
    color:var(--text-secondary);
    font-size:.78rem;
    line-height:1.4;
    overflow:hidden;
    text-overflow:ellipsis;
    display:-webkit-box;
    -webkit-line-clamp:2;
    -webkit-box-orient:vertical
}
@media(max-width:520px){
    .site-search{padding-top:4vh}
    .ss-panel{width:calc(100% - 1rem);max-height:90vh}
}

/* Mobile menu toggle */
.menu-toggle{
    display:none;flex-direction:column;
    cursor:pointer;background:none;border:none;padding:10px;gap:5px;
    min-width:44px;min-height:44px;
    align-items:center;justify-content:center
}
.menu-toggle span{
    width:22px;height:2px;
    background:var(--accent);
    transition:transform .3s,opacity .3s;
    border-radius:2px
}
.menu-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.menu-toggle[aria-expanded="true"] span:nth-child(2){opacity:0}
.menu-toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

/* ─── Buttons ─── */
.btn{
    padding:.75rem 1.8rem;
    border:1.5px solid var(--accent);
    background:0 0;
    color:var(--accent);
    text-decoration:none;
    border-radius:var(--radius);
    font-size:.85rem;
    font-family:var(--font-mono);
    letter-spacing:.3px;
    transition:all .25s;
    cursor:pointer;
    display:inline-flex;align-items:center;gap:var(--space-2);min-height:44px}
.btn:hover{
    background:var(--accent-dim);
    color:var(--accent);
    transform:translateY(-1px);
    box-shadow:0 4px 20px rgba(100,255,218,.1)
}
.btn-primary{background:var(--accent);color:var(--bg-deep);font-weight:600}
.btn-primary:hover{background:transparent;color:var(--accent)}

.btn-warm{
    border-color:var(--accent-warm);
    color:var(--accent-warm)
}
.btn-warm:hover{
    background:var(--accent-warm-dim);
    color:var(--accent-warm);
    box-shadow:0 4px 20px rgba(240,165,0,.1)
}
.btn-warm.btn-primary{background:var(--accent-warm);color:var(--bg-deep)}
.btn-warm.btn-primary:hover{background:transparent;color:var(--accent-warm)}

/* ─── Cards ─── */
.card{
    padding:var(--space-6);
    transition:all .3s
}
.card:hover{
    border-color:var(--border-hover);
    transform:translateY(-3px);
    box-shadow:0 8px 40px rgba(0,0,0,.3)
}

/* ─── Main & Footer ─── */
main{position:relative;z-index:1}
footer{
    position:relative;z-index:1;
    background:var(--bg-primary);
    border-top:1px solid var(--border);
    padding:3.5rem 2rem;
    margin-top:6rem
}
.footer-inner{
    max-width:1100px;margin:0 auto;
    display:grid;grid-template-columns:1.35fr 1fr auto;
    gap:var(--space-7);align-items:start
}
.footer-brand p{color:var(--text-secondary);font-size:.88rem;line-height:1.6}
.footer-name{
    display:inline-block;margin-bottom:.6rem;
    color:var(--text-bright);font-family:var(--font-display);font-weight:700
}
.footer-name:hover{color:var(--accent)}
.footer-location{margin-top:.45rem;color:var(--text-muted)!important;font-family:var(--font-mono);font-size:.76rem!important}
.footer-nav{
    max-width:none;margin:0;padding:0;
    display:grid;grid-template-columns:repeat(2,minmax(90px,1fr));
    gap:.65rem 1.5rem;align-items:start
}
.footer-nav a{color:var(--text-secondary);font-family:var(--font-mono);font-size:.78rem}
.footer-nav a:hover{color:var(--accent)}
.footer-side{text-align:right}
.footer-legal{margin-top:.8rem;font-size:.8rem}
.footer-legal a{color:var(--text-muted);text-decoration:none;transition:color .2s}
.footer-legal a:hover{color:var(--accent)}
.footer-copy{color:var(--text-muted);font-size:.76rem;margin-top:.45rem}
.footer-socials{display:flex;justify-content:flex-end;gap:.65rem}
.footer-socials a{
    width:40px;height:40px;display:flex;align-items:center;justify-content:center;
    color:var(--text-muted);border:1px solid var(--border);border-radius:50%;
    text-decoration:none;transition:color .2s,border-color .2s
}
.footer-socials a:hover{color:var(--accent)}
.footer-socials svg{width:1.1em;height:1.1em;vertical-align:middle}

/* ─── Language visibility ───
   Hide opposite-language [data-lang] elements based on <html lang>. Server-
   rendered pages already strip them (HTMLRewriter in _seo.js) so this rule
   matches nothing there. It matters for:
     - Client-rendered card grids (tools, cves, challenges, home)
     - The challenge detail renderer (challenge.js)
     - 404.html, which is served statically.
   Both languages live in the DOM; CSS picks the active one from html[lang]. */
html[lang="en"] [data-lang="es"]{display:none}
html[lang="es"] [data-lang="en"]{display:none}

/* ─── Scroll to top ─── */
.scroll-top{
    position:fixed;bottom:2rem;right:2rem;
    width:44px;height:44px;
    background:var(--bg-elevated);
    border:1px solid var(--border);
    color:var(--accent);
    border-radius:50%;font-size:1.2rem;
    cursor:pointer;
    opacity:0;visibility:hidden;
    transition:all .3s;z-index:999;
    display:flex;align-items:center;justify-content:center
}
.scroll-top.visible{opacity:1;visibility:visible}
.scroll-top:hover{border-color:var(--accent);transform:translateY(-3px);box-shadow:0 4px 20px rgba(100,255,218,.1)}

/* Push <main> down by:
   • The iOS safe-area inset, because the fixed header has
     padding-top:env(safe-area-inset-top): on a notched iPhone that adds
     ~44px to the header height, which sections did not account for and
     which made the first content item slip under the header.
   Each section keeps its own padding-top to clear the regular header. */
main{padding-top:env(safe-area-inset-top,0px)}
.section{padding:7rem 2rem;max-width:1100px;margin:0 auto}

/* ═══ Shared proof components ═══
   The credibility strip, the testimonial and the sample-report box each
   lived in the stylesheet of the one page that used them. They are now on
   /services, /pentest and /case-studies too, and those pages load neither
   index.css nor compliance.css, so the components come here rather than
   being copied three times. */
.proof-strip{
    display:flex;justify-content:center;gap:3rem;
    padding:2.5rem 2rem;
    margin-top:4rem;
    border-top:1px solid var(--border);
    width:100%;max-width:1100px
}
.proof-item{text-align:center}
.proof-item strong{
    display:block;font-family:var(--font-mono);
    font-size:1.6rem;color:var(--accent);font-weight:700
}
.proof-item span{
    font-size:.78rem;color:var(--text-secondary);
    font-family:var(--font-mono);letter-spacing:.3px
}
.cp-quote{background:var(--bg-surface);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:var(--radius-lg);padding:1.8rem 2rem}
.cp-quote blockquote{margin:0}
.cp-quote p{font-size:1.1rem;line-height:1.7;color:var(--text-bright);font-style:italic;margin:0 0 1rem}
.cp-quote cite{font-family:var(--font-mono);font-size:.82rem;color:var(--accent);font-style:normal}
.cp-quote-more{margin-top:1rem;color:var(--text-secondary);font-size:.92rem;line-height:1.6}
.cp-quote-more a{color:var(--accent);text-decoration:none;border-bottom:1px dotted rgba(100,255,218,.4);transition:border-color .2s}
.cp-quote-more a:hover{border-bottom-color:var(--accent)}

.cp-report-box{background:linear-gradient(180deg,var(--accent-dim),transparent);border:1px solid var(--accent);border-radius:var(--radius-lg);padding:2rem;display:flex;gap:1.6rem;align-items:center;flex-wrap:wrap}
.cp-report-box .cp-report-txt{flex:1;min-width:260px}
.cp-report-box h3{color:var(--text-bright);font-size:1.2rem;margin:0 0 .5rem}
.cp-report-box p{color:var(--text-secondary);font-size:.95rem;line-height:1.6;margin:0}
.btn-download{font-size:1rem;padding:.85rem 1.6rem;white-space:nowrap}

/* Responsive variants for the shared proof components above. These lived
   inside index.css / compliance.css media queries; the move to common.css
   flattened them to the root, where the mobile layout applied at every
   width. Restored to their original breakpoints, and placed after the base
   rules they override: sitting before them, equal specificity meant the
   base rule won and the mobile layout never applied. */
@media(max-width:968px){
    .proof-strip{gap:2rem;flex-wrap:wrap}
}
@media(max-width:820px){
    .cp-report-box{flex-direction:column;align-items:stretch}
    .btn-download{white-space:normal;text-align:center}
}

@media(max-width:768px){
    .proof-strip{gap:1.5rem;padding:2rem 1rem}
    .proof-item strong{font-size:1.3rem}
}

/* ═══ Detail-page CTA ═══
   The conversion ask at the end of a post, a CVE, a tool or a course. It
   lived in post.css because posts were the only page type that had one;
   now that CVEs, tools and courses carry it too, it belongs here. Paired
   with .cta-band, which is the page-level closing on listing and landing
   pages: this one sits inside the article, that one closes the page. */
.detail-cta{
    padding:2.5rem 2rem;
    text-align:center;
    margin-top:var(--space-7);
    position:relative;
    overflow:hidden
}
.detail-cta::before{
    content:'';position:absolute;top:0;left:0;right:0;height:3px;
    background:linear-gradient(90deg,var(--accent),rgba(100,255,218,.3));
    opacity:.6
}
.detail-cta p{
    color:var(--text-secondary);
    margin-bottom:1.2rem;
    font-size:1rem;
    line-height:1.7
}
.detail-cta a{
    display:inline-flex;align-items:center;gap:var(--space-2);
    padding:.75rem 2rem;
    border:1.5px solid var(--accent);
    background:var(--accent);
    color:var(--bg-deep);
    text-decoration:none;
    border-radius:var(--radius);
    font-family:var(--font-mono);font-size:.85rem;
    font-weight:600;letter-spacing:.3px;
    transition:all .25s;
    cursor:pointer
}
.detail-cta a:hover{
    background:transparent;
    color:var(--accent);
    transform:translateY(-1px);
    box-shadow:0 4px 20px rgba(100,255,218,.1)
}
/* Two-button row when a post hits both audiences (client + learner).
   Primary action gets the filled button; secondary is outlined so buyers
   and learners both see their path without one drowning out the other. */
.detail-cta-actions{
    display:flex;flex-wrap:wrap;
    gap:.8rem;
    justify-content:center
}
.detail-cta-actions a.secondary{
    background:transparent;
    color:var(--accent);
    border-color:var(--accent)
}
.detail-cta-actions a.secondary:hover{
    background:var(--accent);
    color:var(--bg-deep)
}

/* ─── Next / Previous navigation ─── */
.post-nav{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:var(--space-4);
    margin-top:2.5rem
}
/* ═══ Closing band ═══
   One component for every page's closing ask. It replaces the bespoke
   .cs-cta / .about-cta / .cp-close blocks each page had grown, and putting
   one on every listing page is what stops the credibility surface being a
   set of dead ends: each band carries the internal route to the offer, not
   just a mailto. Sits on .section, so it only adds what .section does not. */
/* ═══ Page hero ═══
   Every page opened with its own header component: .hero, .svc-hero, .cp-hero,
   .training-hero, .about-hero, .cs-hero, .blog-section, .listing-section:    eight of them for thirteen pages, with padding-top drifting between 7rem,
   8rem and unset, and the h1 landing anywhere between 2.8rem and 2.85rem.
   Side by side on a phone they read as three different websites.

   One geometry, aliased onto the existing class names so no markup moves.
   Two rules the copy has to hold up its end of:
     · the label says something the h1 does not (it used to read "Tools" above
       an h1 that also said "Tools");
     · the h1 is a phrase, not a bare noun and not a paragraph: the /services
       one ran 68 characters and wrapped to four lines on a phone, pushing the
       three doors below the fold. */
.section.svc-hero,.section.cp-hero,.section.about-hero,.section.cs-hero,
.section.blog-section,.section.listing-section,.section.detail-section,
.training-hero{
    padding-top:8rem
}
.svc-hero .section-title,.cp-hero .section-title,
.about-hero .section-title,.cs-hero .section-title,
.blog-section .section-title,.listing-section .section-title,
.training-hero .section-title{
    font-size:2.85rem;line-height:1.1;margin-bottom:var(--space-3)
}
.svc-hero .section-subtitle,.cp-hero .section-subtitle,
.about-hero .section-subtitle,.cs-hero .section-subtitle,
.blog-section .section-subtitle,.listing-section .section-subtitle,
.training-hero .section-subtitle{
    max-width:680px;font-size:1.12rem;margin-bottom:var(--space-6)
}
/* Two class names deep, so this beats the generic `.section-title` step in the
   mobile block below no matter where that sits. */
@media(max-width:820px){
    .svc-hero .section-title,.cp-hero .section-title,
    .about-hero .section-title,.cs-hero .section-title,
    .blog-section .section-title,.listing-section .section-title,
    .training-hero .section-title{
        font-size:2.1rem;line-height:1.15
    }
}

.svc-hero,.cp-hero{max-width:1100px}

/* Keep long display-font words inside very narrow phones (320–375px).
   This must follow the shared 820px hero step above or that rule wins. */
@media(max-width:380px){
    .svc-hero .section-title,.cp-hero .section-title,
    .about-hero .section-title,.cs-hero .section-title,
    .blog-section .section-title,.listing-section .section-title,
    .training-hero .section-title{
        font-size:1.85rem
    }
}

/* ═══ Card surface ═══
   Twenty selectors were each declaring the same three properties. They never
   diverged, they were copy-paste: background, hairline border and large radius,
   identical in every one. Declared once here so a change is a change, not a
   sweep. What legitimately differs per family: padding, layout, hover, the
   accent rail: stays in that family's own stylesheet. */
.post-card,.post-related-card,.cve-card,.tool-card,.cs-card,.cp-card,
.course-card,.module-card,.cert-card,.booking-card,.audience-card,
.instructor-card,.test-card,.path-card,.training-path-card,
.svc-route,.svc-scope,.svc-sub,.wk-blog-card,.wk-tool-card,
.home-svc-card,.research-card{
    background:var(--bg-surface);
    border:1px solid var(--border);
    border-radius:var(--radius-lg)
}

/* ═══ Keyboard focus ═══
   Was uneven: 20 rules here, one per page stylesheet, and none at all in
   tools.css, so anyone tabbing through /tools got the browser default outline
   on a dark ground. One shared rule covering every interactive shape the site
   uses, so a new component inherits it instead of needing its own. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
.tool-card:focus-visible,
.post-card:focus-visible,
.cve-card:focus-visible,
.work-tab:focus-visible,
.tag-filter:focus-visible,
.course-card:focus-visible,
.cs-card:focus-visible{
    outline:2px solid var(--accent);
    outline-offset:3px;
    border-radius:var(--radius)
}

.cta-band{
    text-align:center;
    border-top:1px solid var(--border);
    padding-top:var(--space-8);
    padding-bottom:var(--space-8)
}
.cta-band h2{
    font-family:var(--font-display);
    font-size:1.9rem;line-height:1.15;
    color:var(--text-bright);
    margin:0 0 var(--space-3)
}
.cta-band p{
    color:var(--text-secondary);
    max-width:56ch;margin:0 auto;
    line-height:1.7
}
.cta-band-actions{
    display:flex;flex-wrap:wrap;justify-content:center;
    gap:var(--space-3);margin-top:var(--space-5)
}
@media(max-width:640px){
    .cta-band h2{font-size:1.5rem}
    .cta-band-actions .btn{width:100%;text-align:center}
    .svc-cta-row .btn,.cp-cta-row .btn{width:100%;justify-content:center;text-align:center}
}
.section-label{
    font-family:var(--font-mono);
    font-size:.72rem;
    color:var(--accent);
    letter-spacing:2px;
    text-transform:uppercase;
    margin-bottom:var(--space-4);
    display:block
}
.section-title{font-size:2.8rem;margin-bottom:var(--space-4)}
.section-subtitle{color:var(--text-secondary);font-size:1.1rem;max-width:1000px;line-height:1.7}

/* ─── Back link ─── */
.back-link{
    display:inline-flex;align-items:center;gap:.4rem;
    color:var(--text-secondary);font-family:var(--font-mono);font-size:.82rem;
    text-decoration:none;margin-bottom:var(--space-6);transition:color .2s
}
.back-link:hover{color:var(--accent)}

/* ─── Severity colors (shared across CVE cards, badges, labels) ─── */
.sev-critical{background:rgba(255,71,87,.12);color:#ff4757}
.sev-high{background:rgba(255,107,53,.12);color:#ff6b35}
.sev-medium{background:rgba(255,209,102,.12);color:#ffd166}
.sev-low{background:rgba(100,255,218,.12);color:#64ffda}
.sev-insane{background:rgba(191,90,242,.12);color:#bf5af2}

/* ─── Utility classes ─── */
.footer-location{margin-top:var(--space-2);font-size:.85rem}
.btn-sm{font-size:.8rem;padding:.6rem 1.5rem}
.btn-sm .icon{width:.8em;height:.8em}
.work-panel-footer{text-align:center;margin-top:var(--space-5)}
.waitlist-error{color:var(--danger);font-size:.9rem;margin:.5rem 0 0;text-align:center}
.waitlist-error-link{color:var(--accent);font-size:.9rem;display:block;text-align:center;margin-top:var(--space-1)}
.td-accent{font-family:var(--font-mono);color:var(--accent)}
.td-fixed{color:var(--accent);font-weight:600}

/* ─── Scroll reveal ─── */
/* Only hide reveal content when JS is present (html.js, set by the blocking
   inline head script). With JS disabled the class is absent, so .reveal stays
   fully visible instead of being stuck at opacity:0 with no way to reveal it. */
.js .reveal{opacity:0;transform:translateY(30px);transition:opacity .7s ease,transform .7s ease}
.reveal.visible{opacity:1;transform:translateY(0)}

/* ─── Reduced motion ─── */
/* Honor the OS "reduce motion" setting: drop the reveal animation and any
   transitions/animations, and show reveal content immediately. */
@media (prefers-reduced-motion: reduce){
    *,*::before,*::after{
        animation-duration:.001ms !important;
        animation-iteration-count:1 !important;
        transition-duration:.001ms !important;
        scroll-behavior:auto !important
    }
    .reveal,.js .reveal{opacity:1 !important;transform:none !important}
}

/* ─── Responsive ─── */
@media(max-width:768px){
    body.nav-open{overflow:hidden}
    .nav-links{
        position:absolute;top:100%;left:0;right:0;
        flex-direction:column;
        background:color-mix(in srgb,var(--bg-primary) 97%,transparent);
        backdrop-filter:blur(20px);
        padding:1rem 1.25rem 1.4rem;gap:.25rem;
        transform:translateY(-120%);opacity:0;visibility:hidden;
        transition:all .3s ease;
        border-bottom:1px solid var(--border)
    }
    .nav-links.active{transform:translateY(0);opacity:1;visibility:visible;max-height:calc(100vh - 60px);overflow-y:auto}
    .nav-links>li{width:100%}
    .nav-links>li>a{
        display:flex;align-items:center;
        min-height:44px;width:100%;padding:.65rem .75rem;
        border-bottom:1px solid var(--border)
    }
    .nav-links>li>a::after{display:none}
    .nav-links a.nav-cta{
        justify-content:center;margin:.65rem 0;
        border:1px solid var(--accent);background:var(--accent);color:var(--bg-deep)
    }
    .nav-links .lang-toggle{margin:.35rem 0 0;width:100%}
    .nav-links .lang-toggle a{width:50%;min-height:44px}
    .nav-links .theme-toggle,.nav-links .search-btn{width:100%;min-height:44px;margin:.25rem 0 0}
    .menu-toggle{display:flex}
    .section{padding:4rem 1.5rem}
    /* Same list as the desktop rule above. `.section` here is one class,
       exactly like `.svc-hero`, and it is declared later in the file, so
       without this the heroes that had no mobile rule of their own silently
       dropped from 8rem to 4rem while the ones that did kept 6rem. That is
       the 64px-vs-96px gap you could see between /services and /tools. */
    .section.svc-hero,.section.cp-hero,.section.about-hero,.section.cs-hero,
    .section.blog-section,.section.listing-section,.section.detail-section,
    .training-hero{
        padding-top:6rem
    }
    .section-title{font-size:2rem}
    .cve-card{gap:var(--space-4);padding:1.4rem}
    /* Was inside post.css's mobile block, so only posts got it; the CVE,
       tool and course pages carry the same component and do not load that
       stylesheet. */
    .detail-cta{padding:var(--space-6) var(--space-5)}
    .test-proof-link,.bg-link a{min-height:44px;display:inline-flex;align-items:center}
}

@media(max-width:820px){
    .footer-inner{grid-template-columns:1fr;gap:var(--space-6)}
    .footer-side{text-align:left}
    .footer-socials{justify-content:flex-start}
}

/* ─── Testimonial cards ─── Shared between home rotator, /about archive
   and /training teaching grid. Three category variants (client, colleague,
   student) share the base card; each variant colours the category pill
   only. The left accent stripe and the large faded quote-mark in the
   top-right are typographic flourishes that separate these cards from
   the flat-rectangle look they had before. */
.test-card{
    padding:2.25rem 2rem 2rem;
    position:relative;
    overflow:hidden;
    transition:all .3s
}
.test-card::before{
    content:'';
    position:absolute;top:0;bottom:0;left:0;
    width:3px;
    background:linear-gradient(180deg,var(--accent) 0%,rgba(100,255,218,.15) 100%);
    opacity:.7
}
.test-card::after{
    content:'\201C';
    position:absolute;top:-.4rem;right:1.1rem;
    font-family:var(--font-display);
    font-size:5.5rem;
    line-height:1;
    color:var(--accent);
    opacity:.08;
    pointer-events:none
}
.test-card:hover{
    border-color:var(--border-hover);
    transform:translateY(-3px);
    box-shadow:0 8px 40px rgba(0,0,0,.25)
}
.test-type{
    font-family:var(--font-mono);
    font-size:.7rem;
    text-transform:uppercase;letter-spacing:1.5px;
    margin-bottom:1.1rem;
    padding:.3rem .75rem;
    border-radius:var(--radius-pill);
    display:inline-flex;
    align-items:center;
    gap:.45rem
}
.test-type::before{
    content:'';
    width:6px;height:6px;
    border-radius:50%;
    background:currentColor
}
.test-client .test-type{background:var(--accent-warm-dim);color:var(--accent-warm)}
.test-colleague .test-type{background:var(--accent-alt-dim);color:var(--accent-alt)}
.test-student .test-type{background:var(--accent-dim);color:var(--accent)}
.test-card blockquote{margin:0;position:relative;z-index:1}
.test-card blockquote p{
    color:var(--text-primary);
    font-size:.95rem;
    line-height:1.7;
    font-style:italic
}
.test-card cite{
    display:block;
    margin-top:1.2rem;
    color:var(--accent);
    font-size:.78rem;
    font-style:normal;
    font-family:var(--font-mono)
}
.test-card cite::before{
    content:'\2014\00a0';
    opacity:.7
}
@media(max-width:768px){
    .test-card{padding:1.75rem 1.5rem 1.5rem}
    .test-card::after{font-size:4.5rem;top:-.2rem;right:.8rem}
}

/* ─── CVE cards ─── Shared between /cves (server-rendered via
   renderCveCards in functions/_render.js) and the homepage "Recent Work →
   CVEs" tab (client-rendered by loadCVEs in js/index.js). Keeping the
   styles here means every page that loads common.css can use the same
   card markup without pulling tools.css too. */
.cve-card{
    padding:1.8rem;
    transition:all .3s;
    text-decoration:none;
    display:flex;gap:1.4rem;align-items:flex-start;
    color:inherit
}
.cve-card:hover{
    border-color:var(--border-hover);
    transform:translateY(-3px);
    box-shadow:0 8px 40px rgba(0,0,0,.3);
    color:inherit
}
.cve-card-severity{
    width:52px;height:52px;flex-shrink:0;
    display:flex;align-items:center;justify-content:center;
    border-radius:50%;
    font-family:var(--font-mono);font-size:.78rem;font-weight:700
}
.cve-card-severity.sev-critical{border:1px solid rgba(255,71,87,.35)}
.cve-card-severity.sev-high{border:1px solid rgba(255,107,53,.35)}
.cve-card-severity.sev-medium{border:1px solid rgba(255,209,102,.35)}
.cve-card-severity.sev-low{border:1px solid rgba(100,255,218,.35)}
.cve-card-body{flex:1;min-width:0}
.cve-card-header{
    display:flex;align-items:center;gap:.8rem;flex-wrap:wrap;
    margin-bottom:.3rem
}
.cve-card-id{
    font-family:var(--font-display);
    font-size:1.05rem;font-weight:700;
    color:var(--text-bright)
}
.cve-card-label{
    font-family:var(--font-mono);font-size:.68rem;
    text-transform:uppercase;letter-spacing:.5px;
    padding:.15rem .5rem;border-radius:var(--radius)
}
.cve-card-info{
    display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;
    margin-bottom:.6rem;
    font-family:var(--font-mono);font-size:.72rem;color:var(--text-secondary)
}
.cve-info-sep{color:var(--text-muted);margin:0 .2rem}
.cve-card-desc{
    color:var(--text-secondary);
    font-size:.88rem;
    line-height:1.6
}
