/* =========================================
   1. CSS Custom Properties
   ========================================= */

:root {
    --dark-main: #151515;
    --light-main: #F2F0EF;
    --subtitle-color: #888888;
    --hover-color: var(--light-main);

    --serif-font: "Hedvig Letters Serif", serif;
    --sans-serif-font: "DM Sans", sans-serif;
    --font-weight: 400;

    --content-width: 700px;
    --gap-lg: 40px;
    --radius-sm: 4px;

    /* Case-study image width at >=1100px: scales to 1000px at a 1500px
       viewport, capped so the sticky nav keeps clearance at narrow
       laptop widths. */
    --breakout-width: max(var(--content-width), min(66.6667vw, 100vw - 340px));

    /* Fixed width for the sticky nav column so separators/toggle reach
       the menu's true edge. */
    --nav-inset: 150px;

    /* Header/footer width at >=1100px, chosen so their centered left
       edge lines up with the nav's left edge. */
    --header-breakout-width: max(var(--content-width), calc(50vw + var(--breakout-width) / 2 + var(--nav-inset)));
}

/* =========================================
   2. Base / Element Resets
   ========================================= */

html {
    box-sizing: border-box;
    height: 100%;
    min-height: 650px;
    margin: 0;
    padding: 0;
    width: 100%;
    /* Disables iOS Safari's automatic font-boosting. */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;

    /* flex-direction: column lets body grow past one viewport height;
       row would clamp body's height via align-items: stretch. */
    display: flex;
    flex-direction: column;

    background-color: var(--dark-main);
    color: var(--light-main);
    stroke: var(--light-main);

    font-family: var(--serif-font);
    font-weight: var(--font-weight);

    transition: background-color 0.8s ease;
    scroll-behavior: smooth;

    fill: none;
}

body {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;

    flex: 1;
    padding: 0;
    margin: 0;

    line-height: 1.6;

    /* .header is a flex sibling of .page-grid, not a grid item, so its
       sticky containing block is body's full height. */
    display: flex;
    flex-direction: column;
}

.page-grid {
    flex: 1;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
}

a {
    color: var(--light-main);
}

h1,
h2,
h3,
h4,
h5 {
    margin-block: 6px;
    font-weight: var(--font-weight);
}

.hero-title {
    text-align: center;
    font-size: 52px;
    line-height: 1.15;
    padding-top: 24px;
}

.chapter-title {
    font-size: 32px;
}

.subsection-title {
    font-size: 24px;
}

hr {
    flex-grow: 1;
    border: none;
    border-top: 1px solid var(--subtitle-color);
    opacity: 0.2;
    margin-inline: 12px;
}

ul {
    list-style-type: none;
    padding: 0;
    margin: 0;
}

li {
    padding: 10px 6px;
}

.look-here {
    list-style-type: disc;
    padding-left: 20px;
}

.look-here li {
    padding-block: 0 6px;
}

video {
    width: 100%;
    border-radius: 8px;
    margin-block: 20px 12px;
}

/* =========================================
   3. Typography / Text Utilities
   ========================================= */

.slide-counter,
.chrome-label,
.body-text,
.meta-label,
.caps-label {
    font-family: var(--sans-serif-font);
}

.body-text,
.meta-label {
    font-size: 16px;
    line-height: normal;
}

.slide-counter,
.chrome-label {
    font-size: 14px;
    line-height: normal;
}

.slide-counter,
.chrome-label,
.body-text {
    font-weight: 400;
}

.chrome-label {
    color: var(--subtitle-color);
    font-weight: 500;
}

.slide-counter {
    text-align: center;
    padding: 16px;
}

.meta-label {
    font-weight: 500;
    width: 80px;
}

.caps-label {
    font-weight: 500;
    font-size: 14px;
    text-transform: uppercase;
    color: var(--subtitle-color);
}

.body-link {
    color: var(--hover-color);
    text-decoration: underline var(--subtitle-color) solid 1px;
    text-underline-offset: 3px;
    text-decoration-skip-ink: auto;
}

.body-link:hover {
    color: var(--subtitle-color);
    cursor: pointer;
    transition: color 0.2s;
}

.chrome-link {
    text-decoration: none;
}

.chrome-link:hover {
    color: var(--hover-color);
    cursor: pointer;
    transition: color 0.2s;
}

/* =========================================
   4. Page Layout
   ========================================= */

.left {
    grid-column: 1;
    min-width: 0;
}

.right {
    grid-column: 3;
    min-width: 0;
    /* Empty, but sits after .middle in DOM order and would otherwise
       intercept clicks meant for content overflowing into it. */
    pointer-events: none;
}

.middle {
    grid-column: 2;

    max-width: var(--content-width);
    min-width: 300px;

    display: flex;
    flex-direction: column;
    gap: var(--gap-lg);

    padding: 24px;
}

.center {
    flex: 1;

    display: flex;
    flex-direction: column;
    gap: var(--gap-lg);
    justify-content: center;
    margin-top: -24px;
    margin-bottom: 36px;
}

.tight-footer .center {
    margin-bottom: 0;
}

.header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* Sticky above 1100px; position: fixed below that (see media query)
       works around a real iOS Safari sticky-positioning bug. */
    position: sticky;
    top: 0;
    z-index: 10;
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
    background-color: var(--dark-main);
    transition: background-color 0.8s ease;
    height: 72px;
    padding-top: 24px;
    padding-bottom: 24px;
    width: min(calc(100vw - 48px), var(--content-width));
    margin-inline: auto;
    box-sizing: border-box;
    padding-inline: 6px;
}

.footer {
    display: flex;
    align-items: center;
    height: 22px;
    width: 100%;
    box-sizing: border-box;
    padding-inline: 6px;
}

.footer-item {
    flex: 1;
}

.footer-item-middle {
    text-align: center;
}

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

.row {
    display: flex;
    align-items: center;

    width: 100%;
}

.row+.row {
    margin-top: 4px;
}

.paragraph {
    display: flex;
    flex-direction: column;
    gap: 0;
    padding-block-end: 20px;
}

.overview-metadata {
    display: flex;
    flex-direction: row;
    gap: 8px;
}

.metadata-right {
    flex: 1;
}

.bottom-spacer {
    margin-bottom: 12px;
}

.bottom-spacer-sm {
    margin-bottom: 16px;
}

.bottom-spacer-lg {
    margin-bottom: 24px;
}

.top-spacer-sm {
    margin-top: 16px;
}

/* Case-study content rhythm: spacing derived from adjacency rather than
   hand-tagged classes, in increasing order of specificity below. */
.paragraph>*+* {
    margin-top: 12px;
}

.hero-title+* {
    margin-top: 34px;
}

.chapter-title {
    margin-top: 64px;
}

.subsection-title {
    margin-top: 42px;
}

.overview-metadata+.body-text {
    margin-top: 36px;
}

*+.image,
*+.exclude,
*+.image-scroll,
*+.compare,
.image+*,
.exclude+*,
.image-scroll+*,
.compare+* {
    margin-top: 64px;
}


/* =========================================
   5. Theming (light / dark mode)
   ========================================= */

/* WebKit transitions the root element's background-color from transparent
   on initial page load (unlike other elements, which just paint their
   final value immediately) when a transition is set on html, even though
   nothing actually changed -- .header's identical transition doesn't have
   this quirk, so the two appeared to settle at different times on load.
   .preload is present in the raw HTML and removed by app.js after first
   paint, so only real theme toggles (not the initial load) animate. */
html.preload,
html.preload .header {
    transition: none;
}

.html-light-mode {
    background-color: var(--light-main);
    color: var(--dark-main);
    stroke: var(--dark-main);
    --hover-color: var(--dark-main);
}

.anchor-light-mode {
    color: var(--dark-main);
}

.caps-label.anchor-light-mode {
    color: var(--subtitle-color);
}

.chrome-label.anchor-light-mode {
    color: var(--subtitle-color);
}


/* =========================================
   6. Components
   ========================================= */

.switch {
    stroke: var(--subtitle-color);
    stroke-width: 1.8px;
    stroke-linecap: round;
    stroke-linejoin: round;
    width: 20px;
    height: 20px;
}

.switch:hover {
    stroke: var(--hover-color);
    cursor: pointer;
    transition: stroke 0.2s;
}

.image-placeholder {
    width: var(--content-width);
    height: 300px;
    background-color: #333333;
    border-radius: var(--radius-sm);
}

.image {
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-sm);
    cursor: zoom-in;
}

.exclude {
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-sm);
    cursor: default;
}

/* Scroll-and-dot image gallery; active slide tracked via
   IntersectionObserver in app.js. */
.image-scroll {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

.image-scroll-track {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
}

.image-scroll-track::-webkit-scrollbar {
    display: none;
}

.image-scroll-item {
    flex: 0 0 100%;
    scroll-snap-align: start;
}

.image-scroll-item img {
    width: 100%;
    height: auto;
    display: block;
    border-radius: var(--radius-sm);
    cursor: zoom-in;
}

.image-scroll-contained .image-scroll-item img {
    width: auto;
    max-height: 600px;
}

.image-scroll-contained .image-scroll-item {
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: black;
    border-radius: var(--radius-sm);
}

.image-scroll-dots {
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: center;
    width: fit-content;
    padding: 4px 12px;
    background-color: color-mix(in srgb, var(--subtitle-color), transparent 80%);
    border-radius: 999px;
}

.image-scroll-dot {
    position: relative;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: none;
    padding: 0;
    background: none;
    cursor: pointer;
    color: var(--subtitle-color);
}

.image-scroll-dot:hover,
.image-scroll-dot.active {
    color: var(--light-main);
}

.html-light-mode .image-scroll-dot:hover,
.html-light-mode .image-scroll-dot.active {
    color: var(--dark-main);
}

.image-scroll-dot::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: transparent;
    border: 1.4px solid currentColor;
    transition: background-color 0.2s, border-color 0.2s;
}

.image-scroll-dot.active::after {
    background-color: currentColor;
}

.image-scroll-dot:hover::after,
.image-scroll-dot:focus-visible::after {
    background-color: currentColor;
}

/* --- Before/after comparison slider ---
   Position driven by app.js (initCompareSliders) via inline clip-path
   on .compare-reveal and left on .compare-handle. */
.compare {}

.compare-frame {
    position: relative;
    width: 100%;
    overflow: hidden;
    border-radius: var(--radius-sm);
    cursor: ew-resize;
    user-select: none;
    touch-action: none;
}

.compare-base,
.compare-reveal img {
    display: block;
    width: 100%;
    height: auto;
}

.compare-reveal {
    position: absolute;
    inset: 0;
}

.compare-handle {
    border: none;
    padding: 0;
    cursor: ew-resize;

    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background-color: var(--light-main);
    transform: translateX(-50%);
}

.compare-handle-grip {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--light-main);
    color: var(--dark-main);
    display: flex;
    align-items: center;
    justify-content: center;
}

.compare-handle-grip svg {
    width: 14px;
    height: 14px;
    stroke: currentColor;
    stroke-width: 2px;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
}

.compare-handle:focus-visible .compare-handle-grip {
    outline: 2px solid var(--light-main);
    outline-offset: 2px;
}

.test {
    width: var(--content-width);
    margin-block: -20px;
}

/* --- Sticky side navigation --- */

.sticky-text {
    position: sticky;
    top: 72px;
    align-self: flex-start;

    display: grid;
    grid-template-columns: var(--nav-inset);
    padding-left: calc((100vw - var(--breakout-width)) / 4 - var(--nav-inset) / 2);
    justify-content: start;
    align-items: start;
}

.sticky-text ul,
.sticky-text .nav-toggle {
    grid-area: 1 / 1;
    transition: opacity 0.2s ease, visibility 0.2s ease, color 0.2s ease, transform 0.2s ease;
    transform: translateX(0);
}

/* Suppresses the collapse/expand transition until app.js resolves the
   real initial state, avoiding a flash of the wrong one on load. */
.sticky-text.nav-no-transition ul,
.sticky-text.nav-no-transition .nav-toggle {
    transition: none;
    opacity: 0 !important;
    visibility: hidden !important;
}

.sticky-text .nav-toggle {
    text-align: left;
    background: none;
    border: none;
    padding: 8px 6px;
    cursor: pointer;
    color: var(--light-main);

    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateX(-16px);
}

.html-light-mode .sticky-text .nav-toggle {
    color: var(--dark-main);
}

.html-light-mode .header {
    background-color: var(--light-main);
}

.sticky-text .nav-toggle:hover,
.sticky-text .nav-toggle:focus-visible {
    color: var(--hover-color);
}

.sticky-text .nav-toggle svg {
    width: 40px;
    height: 40px;
    stroke: currentColor;
    stroke-width: 1.2px;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
    display: block;
}


.sticky-text.nav-collapsed ul {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateX(-16px);
}

.sticky-text.nav-collapsed .nav-toggle {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateX(0);
}

.sticky-text li+li {
    border-top: 1px solid color-mix(in srgb, var(--subtitle-color), transparent 80%);
}

.sticky-text li {
    padding: 0;
}

.sticky-text a {
    display: block;
    padding: 10px 6px;
    color: var(--subtitle-color);
    text-decoration: none;
    transition: color 0.2s ease;
    scroll-behavior: smooth;
}

.case-header a:hover,
.footer a:hover,
.sticky-text a:not(.active):hover {
    color: var(--light-main);
}

.case-header a.anchor-light-mode:hover,
.footer a.anchor-light-mode:hover,
.sticky-text a.anchor-light-mode:not(.active):hover {
    color: var(--dark-main);
}

.sticky-text a.active {
    color: var(--light-main);
    font-weight: 600;
}

.sticky-text a.anchor-light-mode.active {
    color: var(--dark-main);
}

/* --- Fullscreen image overlay --- */

.overlay {
    display: none;
    position: fixed;
    z-index: 9999;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.9);
    justify-content: center;
    align-items: center;
    cursor: zoom-out;
}

.overlay-scroll {
    display: flex;
    width: 100%;
    height: 100%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: auto;
    scrollbar-width: none;
}

.overlay-scroll::-webkit-scrollbar {
    display: none;
}

.overlay-scroll-item {
    flex: 0 0 100%;
    scroll-snap-align: start;
    display: flex;
    align-items: center;
    justify-content: center;
}

.overlay-content {
    width: 95%;
    height: 95%;
    max-width: 95vw;
    max-height: 95vh;
    object-fit: contain;
    cursor: zoom-out;
}

.overlay-content:hover {
    opacity: 1;
}

/* =========================================
   7. Staticrypt (password gate) component
   ========================================= */

.staticrypt-html {
    height: 100%;
}

.staticrypt-hr {
    margin-top: 20px;
    margin-bottom: 20px;
    border: 0;
}

.staticrypt-page {
    width: 100%;
    padding: 8% 0 0;
    box-sizing: border-box;
}

.staticrypt-content {
    height: 100%;
    margin-bottom: 4em;
    font-family: var(--serif-font);
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    display: flex;
    align-items: center;
}

.staticrypt-form {
    position: relative;
    z-index: 1;
    max-width: 700px;
    margin: auto;
    text-align: left;
}

.staticrypt-instructions {
    margin-top: -1em;
    margin-bottom: 1em;
}

.staticrypt-form input[type="password"],
input[type="text"] {
    background: var(--light-main);
    border: 0;
    box-sizing: border-box;
    font-size: 14px;
    outline: 0;
    padding: 10px 30px 10px 10px;
    width: 100%;
    border-radius: 4px;
    font-family: var(--sans-serif-font);
}

.staticrypt-password-container {
    position: relative;
    outline: 0;
    background: var(--light-main);
    width: 100%;
    border: 0;
    margin: 0 0 15px;
    box-sizing: border-box;
    border-radius: 4px !important;
}

/* The field's background is always --light-main (see above), which
   matches the page background in light mode and leaves it with no
   visible edge -- dark mode doesn't need this since the page background
   behind it is --dark-main. */
.html-light-mode .staticrypt-password-container {
    border: 1px solid var(--subtitle-color);
}

.staticrypt-toggle-password-visibility {
    cursor: pointer;
    height: 20px;
    opacity: 60%;
    padding: 13px;
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
}

.staticrypt-form .staticrypt-decrypt-button {
    font-family: var(--sans-serif-font);
    font-weight: 400;
    outline: 0;
    width: 100%;
    border: 0;
    padding: 10px;
    color: var(--dark-main);
    font-size: 16px;
    border-radius: 4px;
    cursor: pointer;
}

.staticrypt-form .staticrypt-decrypt-button:hover,
.staticrypt-form .staticrypt-decrypt-button:active,
.staticrypt-form .staticrypt-decrypt-button:focus {
    background-color: rgba(165, 188, 222, 0.8);
}

.staticrypt-decrypt-button {
    background-color: rgba(165, 188, 222, 0.9);
    margin-top: 16px;
}

label.staticrypt-remember {
    display: flex;
    align-items: center;
    margin-bottom: 1em;
    width: auto;
}

.staticrypt-remember input[type="checkbox"] {
    transform: scale(1.5);
    margin-right: 1em;
}

.staticrypt-spinner-container {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.staticrypt-spinner {
    display: inline-block;
    width: 2rem;
    height: 2rem;
    vertical-align: text-bottom;
    border: 0.25em solid gray;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spinner-border 0.75s linear infinite;
}

/* =========================================
   8. Utility
   ========================================= */

.hidden {
    display: none !important;
}

/* =========================================
   9. Keyframes
   ========================================= */

@keyframes spinner-border {
    100% {
        transform: rotate(360deg);
    }
}

/* =========================================
   10. Media Queries
   ========================================= */

@media (max-width: 1100px) {
    .sticky-text {
        display: none;
    }

    /* position: fixed works around a real iOS Safari bug where sticky
       content can render above the header during scroll. */
    .header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        width: 100%;
        padding-inline: 24px;
    }

    /* Breaks out of .middle's max-width so .footer matches .header's
       edge-to-edge width. */
    .footer {
        width: 100vw;
        max-width: 100vw;
        margin-inline: calc((100% - 100vw) / 2);
        padding-inline: 24px;
    }

    /* Compensates for .header leaving the normal flow above. */
    .page-grid {
        padding-top: 72px;
    }
}

/* --- Case-study image breakout ---
   On laptop+ viewports, images/media span wider than --content-width
   while staying centered on the page (see --breakout-width above). */
@media (min-width: 1100px) {

    .paragraph img.image,
    .paragraph img.exclude,
    .paragraph .image-scroll,
    .paragraph .compare {
        width: var(--breakout-width);
        max-width: var(--breakout-width);
        margin-inline: calc((100% - var(--breakout-width)) / 2);
    }

    .footer {
        width: var(--header-breakout-width);
        max-width: var(--header-breakout-width);
        margin-inline: calc((100% - var(--header-breakout-width)) / 2);
    }

    .header {
        width: var(--header-breakout-width);
        max-width: var(--header-breakout-width);
        margin-inline: calc((100% - var(--header-breakout-width)) / 2);
    }
}

@media screen and (-webkit-min-device-pixel-ratio: 0) {

    .staticrypt-form input[type="password"],
    input[type="text"] {
        font-size: 16px;
    }
}
