@charset "UTF-8";

/* remove the green primary accent entirely from this page */
html .text-primary { color: #111111; }
html .bg-primary   { background-color: #111111; }
html .border-primary { border-color: #111111; }
html.dark .text-primary { color: #eeeeee; }
html.dark .bg-primary   { background-color: #eeeeee; }
html.dark .border-primary { border-color: #eeeeee; }

/* unified divider token — tailwind's `border-border` utility is absent from the
   purged tailwind.css, so it silently falls back to the preflight default.
   Define it once here and apply to every divider (header / project-list /
   project rows / footer) so light/dark stay perfectly consistent (§19, §25).
   light ≈ rgba(0,0,0,.09), dark = low-contrast #2a2a2a. */
.border-border { border-color: #e5e7eb; }
html.dark .border-border { border-color: #2a2a2a; }

.download-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid #888888;
    color: #666666;
    background: transparent;
    padding: 4px 8px;
    font-size: 11px;
    line-height: 1;
    letter-spacing: .04em;
    white-space: nowrap;
}

.sha-code {
    display: inline-block;
    max-width: min(520px, 72vw);
    overflow-wrap: anywhere;
    word-break: break-all;
    background: #f6f6f6;
    border: 1px solid #eeeeee;
    padding: 7px 8px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
    line-height: 1.5;
}

.tool-card,
.modal-panel,
.download-row {
    border-radius: 0 !important;
}

html.dark body {
    background: #0b0b0b !important;
    color: #eeeeee !important;
}

html.dark header,
html.dark footer,
html.dark .bg-white {
    background-color: #111111 !important;
    color: #eeeeee !important;
}

html.dark .bg-light {
    background-color: #171717 !important;
}

html.dark .text-primary {
    color: #f4f4f4 !important;
}

html.dark .text-secondary {
    color: #b8b8b8 !important;
}

html.dark .border-border,
html.dark .border-gray-100,
html.dark .border-gray-200 {
    border-color: #2a2a2a !important;
}

html.dark .rounded-full.bg-light,
html.dark .rounded-full.bg-white {
    background-color: #202020 !important;
}

html.dark #software-modal {
    background: rgba(0, 0, 0, 0.72) !important;
}

html.dark #software-modal > div,
html.dark .download-row {
    background: #111111 !important;
    color: #eeeeee !important;
}

html.dark a,
html.dark button {
    color: inherit;
}

html.dark .download-badge {
    border-color: #777777 !important;
    color: #999999 !important;
}

html.dark .sha-code {
    background: #171717 !important;
    border-color: #2a2a2a !important;
    color: #eeeeee !important;
}

html.dark .hover\:bg-primary:hover {
    background: #eeeeee !important;
    color: #111111 !important;
}

html.dark .bg-primary {
    background: #eeeeee !important;
    color: #111111 !important;
}

/* ===== custom utilities (previously inline @apply via CDN) ===== */
.text-balance { text-wrap: balance; }

.hover-lift { transition: transform .3s ease; }
.hover-lift:hover { transform: translateY(-0.25rem); }

.minimal-link { color: #000000; transition: opacity .2s ease; }
.minimal-link:hover { opacity: .8; }

.section-padding { padding-top: 6rem; padding-bottom: 6rem; }
@media (min-width: 768px) {
    .section-padding { padding-top: 8rem; padding-bottom: 8rem; }
}

/* ===== accessibility ===== */
:focus-visible {
    outline: 2px solid #111111;
    outline-offset: 2px;
}
html.dark :focus-visible {
    outline-color: #eeeeee;
}

.skip-link {
    position: absolute;
    left: 1rem;
    top: -3rem;
    z-index: 100;
    background: #111111;
    color: #ffffff;
    padding: 8px 14px;
    transition: top .2s ease;
}
html.dark .skip-link {
    background: #eeeeee;
    color: #111111;
}
.skip-link:focus { top: 1rem; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
}

/* ===== homepage refinement — editorial / developer-lab =====
   Self-contained CSS: the prebuilt tailwind.css is content-purged and lacks
   the utilities used here, so all layout/type/spacing is defined explicitly.
   Color tokens (text-secondary / border-border) are still applied via the
   existing Tailwind classes in markup to keep dark-mode overrides working. */

/* unified container width: 1200px; all visual baselines align to this */
.container { max-width: 1200px; }

/* sticky header: 72px, solid white, only a very light bottom border, no blur/glass/shadow.
   NOTE: tailwind.css is content-purged and does NOT include the `.sticky` utility,
   so position:sticky must be declared explicitly here or the header silently falls
   back to `static` (breaking the §4 sticky requirement and anchor offset). */
header.site-header { height: 72px; position: sticky; top: 0; z-index: 50; }
header.site-header .container { height: 100%; }

/* deepen secondary text for better on-screen contrast (light + dark) */
html:not(.dark) .text-secondary { color: #4a4a4a; }
html.dark .text-secondary { color: #c4c4c4; }

/* technical metadata monospace (version / status / date) */
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; }

/* nav is always visible (no hamburger) — narrow screens shrink the gap instead */
.site-nav {
    display: flex;
    align-items: center;
    gap: 2.5rem;
}
.site-nav a,
.site-nav button {
    font-size: 15px;
    color: #4a4a4a;
    white-space: nowrap;
    transition: color .18s ease;
}
.site-nav a:hover,
.site-nav button:hover { color: #111111; }
html.dark .site-nav a,
html.dark .site-nav button { color: #c4c4c4; }
html.dark .site-nav a:hover,
html.dark .site-nav button:hover { color: #eeeeee; }
.nav-active { color: #111111 !important; text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 1px; }
html.dark .nav-active { color: #eeeeee !important; }

@media (max-width: 768px) {
    .site-nav { gap: 1.5rem; }
}
@media (max-width: 430px) {
    .site-nav { gap: 0.75rem; }
    .site-nav a, .site-nav button { font-size: 14px; }
    .site-logo { font-size: 18px; }
}
@media (max-width: 390px) {
    .site-nav { gap: 0.5rem; }
    .site-nav a, .site-nav button { font-size: 13px; }
}
@media (max-width: 360px) {
    .site-nav { gap: 0.4rem; }
    .site-logo { font-size: 17px; }
    /* keep the toggle functional, drop only its text label on the narrowest screens */
    .theme-toggle-label { display: none; }
}
@media (max-width: 340px) {
    .site-logo { font-size: 16px; }
    .site-nav { gap: 0.3rem; }
    .site-nav a, .site-nav button { font-size: 12.5px; }
    .site-nav a .fa-globe { display: none; }
    .site-nav a .fa-globe, .site-nav button .fa-moon-o { margin-right: 0; }
}

/* HERO */
.hero {
    min-height: clamp(440px, 52vh, 540px);
    display: flex;
    align-items: center;
    padding-top: 6.5rem;
    padding-bottom: 4.5rem;
}
@media (max-width: 767px) {
    .hero { min-height: auto; padding-top: 5rem; padding-bottom: 3rem; }
}
.hero-title {
    font-size: clamp(64px, 5.2vw, 82px);
    line-height: 1.0;
    font-weight: 350;
    letter-spacing: -0.02em;
    margin-bottom: 18px;
}
.hero-subtitle {
    font-size: 27px;
    font-weight: 500;
    color: #5f5f5f;
    margin-bottom: 34px;
}
html.dark .hero-subtitle { color: #b0b0b0; }
.hero-desc {
    font-size: 16px;
    line-height: 1.8;
    max-width: 36rem;
    margin-bottom: 44px;
}
.hero-cta {
    display: inline-flex;
    align-items: center;
    font-size: 14px;
    color: #111;
    transition: opacity .18s ease;
}
html.dark .hero-cta { color: #eee; }
.hero-cta:hover { opacity: .7; }
.cta-arrow {
    display: inline-block;
    margin-left: .5rem;
    transition: transform .18s ease;
}
.hero-cta:hover .cta-arrow { transform: translateY(2px); }

/* SECTIONS — tighter, mature vertical rhythm */
.section { padding-top: 0; padding-bottom: 0; }
#projects { margin-top: 36px; }                 /* hero(72) + 36 ≈ 108 */
.section--gap { margin-top: 104px; }            /* Research & About gaps */
.site-footer.section--gap { margin-top: 90px; } /* About → Footer */
/* anchor jumps must clear the 72px sticky header */
#projects, #research, #about { scroll-margin-top: 88px; }
.section-head { margin-bottom: 28px; }
@media (min-width: 768px) { .section-head { margin-bottom: 42px; } }
.section-label {
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: .14em;
}
.section-sub {
    font-size: 15px;
    line-height: 1.6;
    max-width: 42rem;
    margin-top: 16px;
}
@media (max-width: 767px) {
    #projects { margin-top: 24px; }             /* hero mobile(48) + 24 ≈ 72 */
    .section--gap { margin-top: 76px; }
    .site-footer.section--gap { margin-top: 72px; }
    .section-head { margin-bottom: 26px; }
}

/* PROJECT LIST (editorial index rows, low-card) */
.project-list { border-top-width: 1px; }

.project-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto 28px;
    grid-template-areas:
        "head  status arrow"
        "desc  status arrow"
        "meta  status arrow";
    column-gap: 28px;
    row-gap: 10px;
    align-items: start;
    border-bottom-width: 1px;
    padding: 28px 8px;
    transition: background-color .18s ease;
}
.project-row:hover { background-color: rgba(0, 0, 0, 0.022); }
html.dark .project-row:hover { background-color: rgba(255, 255, 255, 0.03); }

.project-meta {
    grid-area: meta;
    align-self: start;
    margin-top: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
    font-size: 12.5px;
    color: #7a7a7a;
}
html.dark .project-meta { color: #8c8c8c; }

.project-status {
    grid-area: status;
    align-self: start;
    padding-top: 4px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .09em;
    white-space: nowrap;
}
html.dark .project-status { color: #9a9a9a; }

.project-arrow {
    grid-area: arrow;
    align-self: center;
    font-size: 18px;
    transition: color .18s ease, transform .18s ease;
}
.project-row:hover .project-arrow { color: #111; transform: translateX(3px); }
html.dark .project-row:hover .project-arrow { color: #eee; }

/* project title + downloadable tag */
.project-head-left {
    grid-area: head;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    flex-wrap: wrap;
}
.project-name {
    margin: 0;
    font-size: 22px;
    line-height: 1.25;
    font-weight: 600;
    letter-spacing: -0.01em;
    min-width: 0;
    overflow-wrap: break-word;
}
.project-desc {
    grid-area: desc;
    margin: 0;
    font-size: 15.5px;
    line-height: 1.7;
    max-width: 680px;
}

/* downloadable green frame tag — annotation only, not a button (final design, do not change) */
.project-tag {
    display: inline-flex;
    align-items: center;
    border: 1px solid #17803d;
    color: #17803d;
    background: transparent;
    padding: 3px 8px;
    font-size: 11px;
    line-height: 1;
    letter-spacing: .04em;
    white-space: nowrap;
}
html.dark .project-tag {
    border-color: #3a9d5d;
    color: #4fbf74;
}

@media (max-width: 639px) {
    .project-row {
        grid-template-columns: 1fr auto 28px;
        grid-template-areas:
            "head  head   head"
            "desc  desc   desc"
            "meta  status arrow";
        padding: 24px 16px;
        row-gap: 10px;
    }
    .project-meta { align-self: center; margin-top: 0; }
    .project-status { align-self: center; padding-top: 0; }
    .project-arrow { align-self: center; }
}

/* ABOUT */
.about-body { max-width: 760px; }
.about-body p { font-size: 16px; line-height: 1.9; }
.about-body p:first-child { font-size: 19px; font-weight: 500; color: #111; }
.about-body p + p { margin-top: 24px; }
html.dark .about-body p:first-child { color: #eee; }

/* neutral button (replaces green primary buttons inside modal/footer) */
.btn-neutral {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: .75rem 1.25rem;
    border: 1px solid #111111;
    color: #111111;
    background: transparent;
    transition: background-color .18s ease, color .18s ease;
}
.btn-neutral:hover { background: #111111; color: #ffffff; }
html.dark .btn-neutral { border-color: #eeeeee; color: #eeeeee; }
html.dark .btn-neutral:hover { background: #eeeeee; color: #111111; }
.btn-neutral.btn-sm { padding: .5rem 1rem; font-size: 14px; }

/* FOOTER */
.site-footer {
    border-top-width: 1px;
    padding-top: 4rem;
    padding-bottom: 4rem;
}
@media (min-width: 768px) {
    .site-footer { padding-top: 4.25rem; padding-bottom: 4.25rem; }
}
.footer-inner {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}
@media (min-width: 768px) {
    .footer-inner { flex-direction: row; align-items: center; justify-content: space-between; }
}
.footer-meta {
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
    font-size: 13px;
}
.footer-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1.5rem;
    font-size: 14px;
}
.footer-links a { transition: color .18s ease; }
.footer-links a:hover { color: #111; }
html.dark .footer-links a:hover { color: #eee; }

/* ===== verify.php — license verification page =====
   Same purged-tailwind problem as the homepage: assets/tailwind.css is a
   prebuilt stylesheet that was purged against the ORIGINAL page content, so
   utilities that only verify.php uses were never emitted. Every class below
   was verified absent from tailwind.css / font-awesome.min.css, and each one
   had a visible consequence (see the comment on each rule).

   Keep this list in sync: `php tests/test_css_classes.php` fails if verify.php
   references a class that no stylesheet defines. */

/* .block — the <label> sat inline, so its margin-bottom never applied and the
   textarea butted straight up against the label text. */
label.block { display: block; }

/* .font-mono — license payloads are base64/opaque text; without a monospace
   face the textarea is unreadable and wrapping looks like corruption. */
.font-mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}

/* .mt-4 — separated the button row from the textarea. */
.mt-4 { margin-top: 1rem; }

/* .gap-3 / .gap-1 / .gap-4 — flex children had no spacing at all; the status
   icon touched its label and the submit button touched the error text. */
.gap-1 { gap: .25rem; }
.gap-3 { gap: .75rem; }
.gap-4 { gap: 1rem; }

/* .text-red-600 — THE important one: verification failures rendered in the
   default text colour, so an invalid or expired license looked like a
   success with no visible warning. */
.text-red-600 { color: #dc2626; }
html.dark .text-red-600 { color: #f87171; }

/* .border-red-300 — the result panel lost its red frame on invalid licenses. */
.border-red-300 { border-color: #fca5a5; }
html.dark .border-red-300 { border-color: #7f1d1d; }

/* .p-6 / .md:p-8 — the result panel had zero padding, so the status icon and
   field list touched the border. */
.p-6 { padding: 1.5rem; }
@media (min-width: 768px) {
    .md\:p-8 { padding: 2rem; }
}

/* .md:gap-4 / .md:w-40 — the signed-field list lost its two-column alignment
   on desktop, so values no longer lined up under their labels. */
@media (min-width: 768px) {
    .md\:gap-4 { gap: 1rem; }
    .md\:w-40 { width: 10rem; }
}

/* .md:pt-48 — the desktop main block sat too close under the fixed header. */
@media (min-width: 768px) {
    .md\:pt-48 { padding-top: 12rem; }
}

/* ==========================================================================
   SELF-CONTAINED UTILITY LAYER
   ==========================================================================
   verify.php is now the only page that ever loaded assets/tailwind.css, and
   that link has been removed: the prebuilt stylesheet was purged against an
   older snapshot of this page, so roughly two thirds of the utilities the
   markup referenced were silently absent (unstyled, but never an error).

   Everything the page needs is declared below, grouped by concern rather than
   by Tailwind's alphabetical order, so the cascade reads in the same order as
   the markup does. Values are the same spacing scale Tailwind would have
   produced (1rem = 4 units), so removing the link is visually neutral.

   Guard: tests/test_css_classes.php fails if verify.php references a class
   that none of the loaded stylesheets define. Add it here, not to the markup.
   ========================================================================== */

/* --- reset (replaces Tailwind preflight) --------------------------------- */
*,
::before,
::after { box-sizing: border-box; }

body {
    margin: 0;
    line-height: 1.5;
    font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
    -webkit-text-size-adjust: 100%;
}

h1, h2, h3, h4, h5, h6, p, dl, dd, figure, blockquote { margin: 0; }
a { color: inherit; text-decoration: inherit; }
button, input, select, textarea {
    font: inherit;
    color: inherit;
    margin: 0;
    padding: 0;
}
button { cursor: pointer; background-color: transparent; border: 0; }
[role="button"], button { cursor: pointer; }
[hidden] { display: none; }
img, svg { display: block; vertical-align: middle; }

/* --- layout ------------------------------------------------------------- */
.container { width: 100%; }
@media (min-width: 640px) { .container { max-width: 640px; } }
@media (min-width: 768px) { .container { max-width: 768px; } }
@media (min-width: 1024px) { .container { max-width: 1024px; } }
@media (min-width: 1280px) { .container { max-width: 1280px; } }
@media (min-width: 1536px) { .container { max-width: 1536px; } }

.max-w-3xl { max-width: 48rem; }
.w-full   { width: 100%; }
.mx-auto  { margin-left: auto; margin-right: auto; }

/* --- flex / visibility -------------------------------------------------- */
.flex         { display: flex; }
.flex-col     { flex-direction: column; }
.flex-shrink-0 { flex-shrink: 0; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.hidden       { display: none; }

/* --- position ----------------------------------------------------------- */
.fixed  { position: fixed; }
.top-0  { top: 0; }
.left-0 { left: 0; }
.right-0 { right: 0; }
.z-50   { z-index: 50; }

/* --- spacing ------------------------------------------------------------ */
.mx-0 { margin-left: 0; margin-right: 0; }
.mt-4  { margin-top: 1rem; }
.mb-3  { margin-bottom: .75rem; }
.mb-4  { margin-bottom: 1rem; }
.mb-6  { margin-bottom: 1.5rem; }
.mb-10 { margin-bottom: 2.5rem; }
.mb-12 { margin-bottom: 3rem; }
.mr-1  { margin-right: .25rem; }
.mr-2  { margin-right: .5rem; }
.p-4   { padding: 1rem; }
.p-6   { padding: 1.5rem; }
.px-6  { padding-left: 1.5rem; padding-right: 1.5rem; }
.py-3  { padding-top: .75rem; padding-bottom: .75rem; }
.py-5  { padding-top: 1.25rem; padding-bottom: 1.25rem; }
.py-16 { padding-top: 4rem; padding-bottom: 4rem; }
.pt-40 { padding-top: 10rem; }
.pb-24 { padding-bottom: 6rem; }

.gap-1 { gap: .25rem; }
.gap-3 { gap: .75rem; }
.gap-4 { gap: 1rem; }
.space-x-12 > * + * { margin-left: 3rem; }
.space-y-3 > * + * { margin-top: .75rem; }

/* --- border ------------------------------------------------------------- */
.border        { border-width: 1px; border-style: solid; border-color: #e5e7eb; }
.border-b      { border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #e5e7eb; }
.border-t      { border-top-width: 1px; border-top-style: solid; border-top-color: #e5e7eb; }

/* --- colour ------------------------------------------------------------- */
.bg-white    { background-color: #fff; }
.text-primary   { color: #111318; }
.text-secondary { color: #626a73; }
.text-red-600   { color: #dc2626; }
html.dark .text-secondary { color: #9aa1a9; }
html.dark .text-red-600   { color: #f87171; }

.border-red-300 { border-color: #fca5a5; }
html.dark .border-red-300 { border-color: #7f1d1d; }
html.dark .border,
html.dark .border-b,
html.dark .border-t { border-color: #2a2a2a; }
html.dark .bg-white { background-color: #111111; }

/* translucent header bar: solid enough to read, still shows page behind */
.bg-opacity-90 { background-color: rgba(255, 255, 255, .9); }
html.dark .bg-opacity-90 { background-color: rgba(17, 17, 17, .9); }
.backdrop-blur-sm { -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }

/* --- typography --------------------------------------------------------- */
.text-sm   { font-size: .875rem; line-height: 1.25rem; }
.text-lg   { font-size: 1.125rem; line-height: 1.75rem; }
.text-xl   { font-size: 1.25rem; line-height: 1.75rem; }
.text-2xl  { font-size: 1.5rem; line-height: 2rem; }
.text-3xl  { font-size: 1.875rem; line-height: 2.25rem; }
.font-light   { font-weight: 300; }
.font-medium { font-weight: 500; }
.tracking-tight { letter-spacing: -.025em; }
.font-mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
                 "Liberation Mono", monospace;
}

/* --- form control -------------------------------------------------------- */
.outline-none { outline: 2px solid transparent; outline-offset: 2px; }
.outline-none:focus { outline: none; }
.focus\:border-primary:focus { border-color: #111318; }
html.dark .focus\:border-primary:focus { border-color: #eeeeee; }

/* --- interaction states -------------------------------------------------- */
.hover\:text-primary:hover   { color: #111318; }
.hover\:text-white:hover     { color: #fff; }
.hover\:bg-primary:hover     { background-color: #111318; }
html.dark .hover\:text-primary:hover { color: #eeeeee; }
html.dark .hover\:bg-primary:hover   { background-color: #eeeeee; }
html.dark .hover\:text-white:hover   { color: #111318; }
.transition-colors { transition-property: color, background-color, border-color; }
.transition-colors, button, a { transition-duration: .15s; }

/* --- responsive ---------------------------------------------------------- */
@media (min-width: 768px) {
    .md\:flex     { display: flex; }
    .md\:flex-row { flex-direction: row; }
    .md\:gap-4    { gap: 1rem; }
    .md\:w-40     { width: 10rem; }
    .md\:p-8      { padding: 2rem; }
    .md\:pt-48    { padding-top: 12rem; }
    .md\:pb-32    { padding-bottom: 8rem; }
    .md\:text-4xl { font-size: 2.25rem; line-height: 2.5rem; }
}

/* --- caught by tests/test_css_classes.php after the tailwind link was cut --- */
.text-center { text-align: center; }
