/* ============================================================
   CASE STUDY PAGE — scrolling story layout
   Page-scoped stylesheet, loaded only by /projects/*.html case
   study pages. Every value below is either an existing --sc-*
   custom property or a font-size already present in
   section-components.css (12 / 13.5 / 15 / 17 px). No new
   colours, no new spacing values, no new type sizes.

   The single new value is --cs-measure, a prose line-length
   limit. No width token existed for this: --sc-container-max is
   1200px, which measures ~180 characters per line at 15px.
   ============================================================ */

:root {
    /* 30em at 17px = 510px = ~70 characters with the Inter/Arial
       average advance of 0.43em. Measured, not estimated —
       see _work/measure-line-length.py. Expressed in em so the
       character count stays constant as the root size steps down
       at the 768px and 480px breakpoints. */
    --cs-measure: 30em;
}

/* --- Prose column ------------------------------------------------------- */

.cs-prose {
    max-width: var(--cs-measure);
    margin-left: auto;
    margin-right: auto;
    padding-left: var(--sc-space-md);
    padding-right: var(--sc-space-md);
    font-size: 17px;
    line-height: 1.7;
    color: var(--sc-color-text-default);
}

/* style.css applies `* { margin: 0 }`, so paragraphs butt together.
   Restore a rhythm using the existing spacing scale. */
.cs-prose p {
    margin: 0 0 var(--sc-space-lg);
}

.cs-prose p:last-child {
    margin-bottom: 0;
}

.cs-prose a {
    color: var(--sc-brand-red);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* --- Section ------------------------------------------------------------ */

.cs-section {
    padding: var(--sc-spacing-section-y-mobile) 0;
    background-color: var(--sc-color-page);
}

/* .sc-section-header ships with margin-bottom: 48px and a centred
   720px block. Inside a 510px prose column that gap reads as a
   break rather than a heading. Tighten it and left-align. */
.cs-section .sc-section-header {
    margin-bottom: var(--sc-space-lg);
    margin-left: 0;
    margin-right: 0;
    max-width: none;
    text-align: left;
}

.cs-section .sc-section-header__underline {
    margin-left: 0;
}

/* --- Figures ------------------------------------------------------------ */

.cs-figure {
    margin: var(--sc-space-2xl) 0 0;
}

.cs-figure img {
    display: block;
    width: 100%;
    height: auto;
}

.cs-figure__caption {
    max-width: var(--cs-measure);
    margin: var(--sc-space-sm) auto 0;
    padding: 0 var(--sc-space-md);
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--sc-color-text-muted);
}

/* Full-bleed: the figure is a direct child of the full-width section,
   so it needs no viewport-width trickery and cannot cause overflow. */
.cs-figure--bleed img {
    border-radius: 0;
}

/* Offset single: steps out past the prose column without going full width. */
.cs-figure--offset {
    max-width: var(--sc-container-max);
    margin-left: auto;
    margin-right: auto;
    padding: var(--sc-space-2xl) var(--sc-space-md) 0;
}

.cs-figure--offset img {
    border-radius: var(--sc-radius-card);
    box-shadow: var(--sc-shadow-soft);
}

/* Portrait sources sit in a shorter, centred column so they do not
   dominate the scroll. */
.cs-figure--portrait {
    max-width: 620px;
}

/* Portrait-heavy pages (every frame is 9:16) get a wider portrait figure.
   Scoped by body class so pages with landscape sources — Alkhafaji, where the
   620px figure was approved — are untouched. Note the trade: at 780px a 9:16
   frame is 1387px tall rather than 1102px, so this widens the figure and
   lengthens it at the same time. The portrait --pair is the stronger rhythm
   device; see _work/batch2-report-v1.md. */
body.cs-portrait-heavy .cs-figure--portrait {
    max-width: 780px;
}

/* Pair. */
.cs-figure--pair {
    max-width: var(--sc-container-max);
    margin-left: auto;
    margin-right: auto;
    padding: var(--sc-space-2xl) var(--sc-space-md) 0;
}

.cs-figure__pair-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sc-space-sm);
}

.cs-figure--pair img {
    border-radius: var(--sc-radius-card);
    box-shadow: var(--sc-shadow-soft);
}

/* --- Overlay caption ----------------------------------------------------
   Used only on frames measured dark enough to carry white text over a
   light scrim. Contrast verified against the brightest band of the real
   caption region — see _work/check-overlay-contrast.mjs. With the 0.45
   scrim below, the three frames that use this measure 13.4:1, 6.5:1 and
   9.2:1 against white; WCAG AA body text needs 4.5:1.
   Below 600px the caption drops out of the image instead of shrinking. */

@media (min-width: 600px) {
    .cs-figure--overlay {
        position: relative;
    }

    .cs-figure--overlay .cs-figure__caption {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        max-width: none;
        margin: 0;
        padding: var(--sc-space-4xl) var(--sc-space-xl) var(--sc-space-lg);
        color: var(--sc-color-text-on-dark);
        font-size: 15px;
        background-image: linear-gradient(to top, rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0));
    }

    .cs-figure--overlay.cs-figure--offset .cs-figure__caption,
    .cs-figure--overlay.cs-figure--portrait .cs-figure__caption {
        left: var(--sc-space-md);
        right: var(--sc-space-md);
        bottom: 0;
        border-bottom-left-radius: var(--sc-radius-card);
        border-bottom-right-radius: var(--sc-radius-card);
    }

    /* Constrain the overlay text itself, so it does not run the full
       width of a bleed image. */
    .cs-figure--overlay .cs-figure__caption > span {
        display: block;
        max-width: var(--cs-measure);
        margin: 0 auto;
    }
}

/* --- Responsive --------------------------------------------------------- */

@media (min-width: 768px) {
    .cs-section {
        padding: var(--sc-spacing-section-y-tablet) 0;
    }

    .cs-figure__pair-grid {
        grid-template-columns: 1fr 1fr;
        gap: var(--sc-space-md);
    }
}

@media (min-width: 1024px) {
    .cs-section {
        padding: var(--sc-spacing-section-y) 0;
    }
}

/* --- Scroll reveal ------------------------------------------------------
   Extends the existing .sc-reveal pattern; js/scroll-reveal.js adds
   .sc-reveal--in as elements enter the viewport.

   IMPORTANT: section-components.css sets `.sc-reveal { opacity: 0 }` with
   no no-JS fallback, so with JavaScript disabled every revealed element on
   the site stays invisible. A one-line inline script in the page head adds
   `js` to <html> before first paint; if it never runs, the rule below keeps
   all content visible. Scoped to this stylesheet, so no existing page is
   affected. */

.cs-figure.sc-reveal {
    transition: opacity var(--sc-transition-reveal), transform var(--sc-transition-reveal);
}

html:not(.js) .cs-figure.sc-reveal,
html:not(.js) .cs-section.sc-reveal,
html:not(.js) .sc-reveal {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    .cs-figure.sc-reveal,
    .cs-section.sc-reveal {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }
}

/* ============================================================
   BATCH 1 ADDITIONS — portrait sources and constrained widths
   Added 2 September 2026. Existing --sc-* tokens throughout;
   the two new custom properties below are sizing values for
   which no token existed, declared here alongside --cs-measure.
   ============================================================ */

:root {
    /* A bleed figure built from a 9:16 source is ~2.5 screens tall at its
       natural height. Cap it, in the same viewport-relative idiom that
       style.css already uses for .spot-hero (height: 85vh). Slightly
       shorter than the hero so the hero still leads. */
    --cs-bleed-max-h: 72vh;
    /* Fallback only; each constrained figure sets its own native width inline. */
    --cs-native-w: 100%;
}

/* --- Portrait sources in a bleed figure ---------------------------------
   object-position is authored per image on the <img> itself and is never
   defaulted: a centre-weighted frame is not the same as one where the lit
   element sits high. */
.cs-figure--bleed.cs-figure--crop img {
    max-height: var(--cs-bleed-max-h);
    object-fit: cover;
}

/* --- Portrait pair ------------------------------------------------------
   Two 9:16 frames side by side are ~1030px tall and rarely match, because
   source ratios differ slightly. A fixed 3:4 box bounds the height and makes
   both frames identical — the same mechanism .gallery-item already uses at
   4/3. */
.cs-figure--pair.cs-figure--portrait .cs-figure__pair-grid img {
    aspect-ratio: 3 / 4;
    object-fit: cover;
}

.cs-figure--pair.cs-figure--portrait {
    max-width: 900px;
}

/* --- Constrained width --------------------------------------------------
   For projects whose best frame is below the role's target width. The image
   sits at its native size, centred, with page background either side. Sharp
   at native size beats soft at full width. Each figure sets --cs-native-w
   inline to its own emitted width. */
.cs-figure--constrained {
    background-color: var(--sc-color-surface-tint);
    padding-top: var(--sc-space-2xl);
    padding-bottom: var(--sc-space-2xl);
}

.cs-figure--constrained img {
    width: 100%;
    max-width: var(--cs-native-w);
    margin-left: auto;
    margin-right: auto;
    max-height: none;
    /* Square corners on a near-invisible tint read as a broken full-width image.
       Borrowing the offset figure's radius and shadow makes the narrower width
       read as a deliberate frame instead. Verified against a real 1280px source
       in _work/constrained-test/. */
    border-radius: var(--sc-radius-card);
    box-shadow: var(--sc-shadow-soft);
}

.cs-figure--constrained .cs-figure__caption {
    padding-top: var(--sc-space-sm);
}

/* --- Category page cards ------------------------------------------------
   Server-rendered, never JS-injected. Built on the existing card idiom. */
.cs-cards {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sc-space-lg);
    max-width: var(--sc-container-max);
    margin: 0 auto;
    padding: 0 var(--sc-space-md);
    list-style: none;
}

@media (min-width: 700px) {
    .cs-cards { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
    .cs-cards { grid-template-columns: repeat(3, 1fr); gap: var(--sc-space-xl); }
}

.cs-card {
    display: block;
    background-color: var(--sc-color-page);
    border: 1px solid var(--sc-color-border-subtle);
    border-radius: var(--sc-radius-card);
    overflow: hidden;
    box-shadow: var(--sc-shadow-soft);
    transition: transform var(--sc-transition-base), box-shadow var(--sc-transition-base);
    color: inherit;
}

.cs-card:hover,
.cs-card:focus-visible {
    transform: translateY(-4px);
    box-shadow: var(--sc-shadow-medium);
}

.cs-card img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
}

.cs-card__body { padding: var(--sc-spacing-card-p-mobile); }

.cs-card__meta {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--sc-brand-red);
    margin: 0 0 var(--sc-space-2xs);
}

.cs-card__title {
    font-size: 19px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--sc-color-text-strong);
    margin: 0 0 var(--sc-space-2xs);
}

.cs-card__summary {
    font-size: 14.5px;
    line-height: 1.6;
    color: var(--sc-color-text-muted);
    margin: 0;
}

@media (prefers-reduced-motion: reduce) {
    .cs-card { transition: none; }
    .cs-card:hover, .cs-card:focus-visible { transform: none; }
}

/* --- Page header without a hero image -----------------------------------
   Resolution policy rule 2: where no frame can carry a hero even constrained,
   the page opens with the title block and the summary table instead. Uses the
   40px title size already present in section-components.css. */
.cs-pagehead {
    background-color: var(--sc-color-surface-alt);
    border-bottom: 1px solid var(--sc-color-border-subtle);
    padding: var(--sc-space-6xl) 0 var(--sc-space-4xl);
}

.cs-pagehead__inner {
    max-width: var(--cs-measure);
    margin: 0 auto;
    padding: 0 var(--sc-space-md);
}

.cs-pagehead__eyebrow {
    display: inline-block;
    font-size: 12px;
    font-weight: 600;
    color: var(--sc-brand-red);
    text-transform: uppercase;
    letter-spacing: 0.18em;
    margin: 0 0 var(--sc-space-sm);
}

.cs-pagehead__title {
    font-size: 34px;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.02em;
    color: var(--sc-color-text-strong);
    margin: 0 0 var(--sc-space-md);
}

.cs-pagehead__standfirst {
    font-size: 17px;
    line-height: 1.7;
    color: var(--sc-color-text-muted);
    margin: 0;
}

/* Superseded by the clamp in the narrow-viewport block at the end of this
   file, which reaches 40px at 1024px and holds there. */

/* --- Type scale on narrow viewports -------------------------------------
   Measured defect, Prompt 09: at 390px the hero H1 rendered at 14.4px, the
   section H2s at 28px and the hero standfirst at 9px, against body copy fixed
   at 17px. The page title was smaller than its own paragraphs and half the
   size of the headings beneath it.

   Cause is two independent reductions in legacy style.css multiplying. The
   root steps 15px -> 14px at 768 -> 12px at 480, and .spot-hero-title steps
   2.8rem -> 2.2 -> 1.6 -> 1.2rem across the same breakpoints, so the rem
   values shrink twice. .cs-prose is an absolute 17px and does not shrink with
   them, so the body copy overtakes the headline.

   Fixed here first, for the pages that load this sheet, by taking these
   elements off rem entirely. Prompt 14 moved the .spot-hero-title and
   .spot-hero-subtitle clamps into style.css, where those classes belong and
   where all 35 hero pages benefit; the duplicates here were then removed after
   measuring that they no longer changed the result. The two below still do:
   without them a case study H2 reaches the size of its own H1 at 390px, and a
   title-block H1 stays at a flat 34px at every width. Every ramp is expressed in px and vw so the
   root ladder cannot reach it, and every upper bound is the value the page
   already computes at 1024px and above -- so desktop rendering, including the
   approved Alkhafaji page, is unchanged to the pixel.

   style.css itself is untouched: 28 other pages depend on it and that is a
   separate change.

   Measured after: at 390px H1 28px, H2 22px, standfirst 16px, body 17px.  */


/* The title-block H1 shares the hero H1's ramp. It previously stopped at 40px,
   which is also the section H2 size, so on the no-hero pages the page title and
   the headings beneath it were the same size on desktop. */
.cs-pagehead__title {
    font-size: clamp(28px, 2.21vw + 19.4px, 42px);
}

.sc-section-header__title,
.sc-cta__title {
    font-size: clamp(22px, 2.84vw + 11px, 40px);
}
