/* ===========================================================
   Digest — the summary a case study opens on, and the machinery
   that hands over to the full read.

   Shared by every case study. The per-page parts are the copy, the
   band's generated grid and the read time; everything here is the
   same on all four.

   Expected markup, in this order, as siblings after the hero image:

     <section class="digest" id="digest">
       <div class="digest-inner"> ...blocks..., .digest-cta </div>
     </section>
     <div class="band-wrap"> <svg class="pixel-band" .../> </div>
     <div class="full-case" id="full-case" hidden> ...sections... </div>

   Regenerate a band with:
     node _band-pattern.js "<seed>" 92 12 1.2 0.92 0
   =========================================================== */

/* ===== Digest =====
   The page's first read. Reuses the case study's own type scale and
   accent rather than inventing a second visual language: the digest
   should feel like the top of this page, not a card bolted onto it. */
.digest {
    padding: 4.5rem 3rem 0;
    /* Stated, not inherited: the brief and the section that opens the
       case study share this tone, and The Problem is the first step off
       it. That step is what separates the two now the rule has gone. */
    background: #FDF9F5;
    transition: background 0.6s ease;
}

body.dark-mode .digest {
    background: #1a1428;
}

.digest-inner {
    max-width: 760px;
    margin: 0 auto;
}

.digest-label {
    display: block;
    font-family: 'Nunito Sans', sans-serif;
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: #b5572a;
    margin-bottom: 1.5rem;
}

body.dark-mode .digest-label { color: #C9A0E8; }

/* The product line, set larger: most readers have never used Yorba. */
.digest-lead {
    font-family: 'Lora', Georgia, serif;
    font-size: clamp(1.15rem, 2.2vw, 1.45rem);
    line-height: 1.55;
    margin: 0 0 1.5rem;
    text-wrap: pretty;
}

.digest-situation {
    font-size: 1rem;
    line-height: 1.8;
    opacity: 0.75;
    margin: 0 0 2.75rem;
}

.digest-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2.5rem;
    padding-top: 2rem;
    border-top: 1px solid rgba(0,0,0,0.09);
}

body.dark-mode .digest-grid { border-top-color: rgba(255,255,255,0.1); }

.digest-block-title {
    font-family: 'Nunito Sans', sans-serif;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    opacity: 0.45;
    margin: 0 0 0.9rem;
}

.digest-block p {
    font-size: 0.92rem;
    line-height: 1.75;
    opacity: 0.8;
    margin: 0;
}

.digest-figures {
    display: flex;
    flex-wrap: wrap;
    gap: 1.75rem;
    margin-bottom: 1rem;
}

.digest-figure-value {
    display: block;
    font-family: 'Lora', Georgia, serif;
    font-size: clamp(1.5rem, 2.6vw, 1.9rem);
    font-weight: 600;
    line-height: 1.1;
    color: #c2572a;
    letter-spacing: -0.015em;
}

body.dark-mode .digest-figure-value { color: #C9A0E8; }

.digest-figure-label {
    display: block;
    font-size: 0.72rem;
    line-height: 1.4;
    opacity: 0.55;
    margin-top: 0.35rem;
    max-width: 15ch;
}

/* The caveat belongs with the number, not in a footnote. */
.digest-caveat {
    font-size: 0.8rem !important;
    line-height: 1.65 !important;
    opacity: 0.5 !important;
}

.digest-hook {
    font-family: 'Lora', Georgia, serif;
    font-style: italic;
    font-size: clamp(1.05rem, 2vw, 1.25rem);
    line-height: 1.55;
    margin: 2.75rem 0 0;
    padding-left: 1.25rem;
    border-left: 2px solid #c2572a;
    text-wrap: pretty;
}

body.dark-mode .digest-hook { border-left-color: #C9A0E8; }

.digest-cta {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 3rem;
}

/* The button leaves the way the band does: covered block by block, on
   the same grid and the same wave. It sits directly above the band, so
   the two together read as one front travelling down the page rather
   than a fade followed by an unrelated effect. */
.cta-dissolve {
    position: absolute;
    inset: 0;
    pointer-events: none;
    display: grid;
}

.cta-dissolve span {
    opacity: 0;
    transition: opacity 140ms linear;
}

.cta-dissolve.is-on span {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .cta-dissolve span { transition: none; }
}

/* After the footer button on dapper.agency. At rest the tile carries
   the accent and the arrow is drawn in the page's ground colour; on
   hover a panel scales up inside the tile while both icons slide down
   by exactly their own height, so the duplicate waiting above lands
   where the first one was. The colours invert and the arrow appears to
   be replaced rather than recoloured.

   Two things differ from the reference. The arrow points down rather
   than diagonally: theirs navigates away, this one opens what is below
   it, and the diagonal is only their down arrow rotated 225 degrees
   anyway. And the tile is square-cornered to sit with the pixel band
   rather than the reference's rounded one. */
.digest-more {
    display: inline-flex;
    align-items: center;
    gap: 0.75em;
    font-family: 'Nunito Sans', sans-serif;
    font-size: 0.9rem;
    /* 500, and the tracking goes back to neutral with it. The -0.01em
       was there to stop 700 looking loose; at this weight it only makes
       the label feel cramped. 500 is one of the weights this page
       already loads, so it is a real cut rather than a synthesised one. */
    font-weight: 500;
    letter-spacing: 0;
    line-height: 1;
    color: #3a3344;
    background: #f0e8dd;
    border: 0;
    border-radius: 0.5em;
    padding: 0.5em 0.5em 0.5em 1.1em;
    cursor: pointer;
    transition: background 0.3s ease;
}

.digest-more:hover { background: #e8ddcd; }
.digest-more:focus-visible { outline: 2px solid #c2572a; outline-offset: 3px; }

.digest-more__label { white-space: nowrap; }

.btn-arrow {
    position: relative;
    flex-shrink: 0;
    width: 2.5em;
    height: 2.5em;
    border-radius: 0.25em;
    /* A step up the accent ramp from the brand terracotta. The tile is
       a small block of flat colour next to light type, so the brand
       tone at full strength sat heavier here than it does as an accent
       on text. */
    background: #D3743F;
    overflow: hidden;
}

/* Already the full size of the tile and parked directly above it, out
   of sight behind the tile's overflow, so it arrives as a panel rather
   than growing out of a point. It travels the same distance in the same
   direction as the two arrows, so the fill and the icon swap read as
   one movement instead of two effects happening at once. */
.btn-arrow__fill {
    position: absolute;
    inset: 0;
    /* #3a3344, which is the homepage's Copy email button, so the
       hover state of this tile and the site's primary button are the
       same colour. Deeper than a shade of the tile would be, and one
       step short of #2a2334, which is that button's own hover and read
       as a hole when it was tried here.

       Light only. The dark theme keeps a shade of its tile, since the
       ink there is the page background. */
    background: #3a3344;
    transform: translateY(-100%);
    transition: transform 0.45s cubic-bezier(0.22, 1, 0.3, 1);
}

.digest-more:hover .btn-arrow__fill { transform: translateY(0); }

.btn-arrow__box {
    position: absolute;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #FDF9F5;
    transition: transform 0.45s cubic-bezier(0.22, 1, 0.3, 1);
}

/* Parked directly above the tile, so one translateY(100%) brings it in
   as the other leaves. */
.btn-arrow__box.is--duplicate {
    bottom: 100%;
    /* Warm gold on the deeper rust. The old pairing put the accent on
       near-black, which only worked because the fill was so dark. */
    color: #F2CE8C;
}

.digest-more:hover .btn-arrow__box { transform: translateY(100%); }

/* Pinned to 18px, not sized in em. The glyph is a 9x9 grid, so it is
   only crisp at multiples of 9; anything else puts a soft edge on
   every block, which is the one thing a pixel arrow cannot afford.
   18px gives each cell exactly 2px. */
.btn-arrow__svg {
    width: 18px;
    height: 18px;
}

body.dark-mode .digest-more {
    color: #e8dff0;
    background: #2a2334;
}

body.dark-mode .digest-more:hover { background: #342b42; }
body.dark-mode .digest-more:focus-visible { outline-color: #C9A0E8; }
body.dark-mode .btn-arrow { background: #D4B3EE; }
body.dark-mode .btn-arrow__fill { background: #9469BE; }
body.dark-mode .btn-arrow__box { color: #140e20; }
body.dark-mode .btn-arrow__box.is--duplicate { color: #EFE3FA; }

@media (prefers-reduced-motion: reduce) {
    .btn-arrow__fill,
    .btn-arrow__box { transition: none; }
}

.digest-more-meta {
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    opacity: 0.45;
}

/* Collapsed by default; the button removes [hidden]. */
.full-case[hidden] { display: none; }

/* No container-level entrance. Every section inside already carries
   .reveal-on-scroll, and running a translate on the wrapper at the
   same time meant the whole block slid while its sections were
   independently sliding, over a scroll that was also moving: three
   motions at once, which is what made the reveal feel like a jolt.
   The sections' own reveal is the effect now. */

/* The band is empty once the wave has passed, so its 197px goes back
   to the page and the case study rises into the space. */
.band-wrap.is-collapsed {
    overflow: hidden;
    will-change: height;
    transition: height 620ms cubic-bezier(0.4, 0, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
    .band-wrap.is-collapsed { transition: none; }
}

/* Once expanded the digest has done its job, but removing it would
   yank the page out from under the reader, so it stays and quiets. */
/* Two steps, not display:none. The button fades where it stands and
   holds its space, so nothing under it moves while the band is still
   clearing and the sections are arriving. Only once they have finished
   does the space itself go. */
/* No opacity on the button itself any more; the blocks above it do the
   work. This only stops it being clicked while it is being covered. */
.digest-cta.is-leaving {
    pointer-events: none;
}

/* Eased in and out, not expo-out. 0.16, 1, 0.3, 1 leaves the start of
   the curve at full speed, which is fine for something arriving and
   wrong for something that has been sitting still: the page below
   lurched into motion. This one begins from rest.

   Slower too. It is the last movement in the sequence and it carries
   the whole page up 98px, so it wants to read as a settle rather than
   a snap. will-change lets the browser prepare for it, since animating
   height relayouts everything underneath on every frame. */
.digest-cta.is-collapsing {
    overflow: hidden;
    will-change: height;
    transition: height 620ms cubic-bezier(0.4, 0, 0.2, 1),
                margin-top 620ms cubic-bezier(0.4, 0, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
    .digest-cta.is-leaving,
    .digest-cta.is-collapsing { transition: none; }
}

@media (max-width: 700px) {
    .digest { padding: 3rem 1.5rem 0; }
    .digest-inner { padding-bottom: 2.5rem; }
    .digest-grid { grid-template-columns: 1fr; gap: 2rem; }
}

@media (prefers-reduced-motion: reduce) {
    .full-case { animation: none; }
    .digest-more, .digest-more svg { transition: none; }
}

.digest { position: relative; padding-bottom: 0; }

.digest-inner { padding-bottom: 4rem; }

/* The artwork is 46 blocks wide by 4 tall, so its height follows from
   the viewport rather than being set: forcing a height would either
   stretch the squares into rectangles or crop the pattern. */
.pixel-band {
    display: block;
    width: 100%;
    height: auto;
    pointer-events: none;
    /* Near the page ground first, furthest last. Cells in the top rows
       draw from the low end and the bottom rows from the high end,
       which is what fades the band without any opacity. */
    --band-0: #FFF9F0;
    --band-1: #FFF4E3;
    --band-2: #FFEFD1;
    --band-3: #FAE3B5;
    --band-4: #F2CE8C;
}

body.dark-mode .pixel-band {
    --band-0: #241B35;
    --band-1: #2D2242;
    --band-2: #372A50;
    --band-3: #43335F;
    --band-4: #57427C;
}

.band-wrap {
    position: relative;
}

/* On a narrow viewport the band's 92:12 aspect collapses it: at 375px
   it is 49px tall with 4px squares, which is a stripe rather than a
   pattern. Rather than generate a second grid, the band keeps its
   natural height and the wrapper crops it, so the squares scale up to
   12.5px and roughly a third of the columns show. All twelve rows are
   still there, which is what the density gradient needs; it is the
   columns that go. */
@media (max-width: 700px) {
    .band-wrap {
        height: 150px;
        overflow: hidden;
        display: flex;
        justify-content: center;
    }

    .band-wrap .pixel-band {
        flex: none;
        width: auto;
        max-width: none;
        height: 150px;
    }
}

/* The band mirrored downward, so the two meet as a seam. It takes its
   space immediately and then builds: blocks arrive in a front running
   from the seam outward, a few rows of them at a time in no order, the
   way the homepage cards resolve. Animating the height instead would
   slide a finished band into view, which is a different thing. */
.band-mirror {
    overflow: hidden;
}

.pixel-band-mirror {
    transform: scaleY(-1);
}

.band-mirror rect {
    opacity: 0;
    transition: opacity 140ms linear;
}

.band-mirror.is-populated rect {
    opacity: 1;
}

/* The band that was already there empties as the mirror fills, on the
   same front travelling the same way, so it reads as one wave crossing
   the seam: erasing above it, drawing below. */
.pixel-band rect {
    transition: opacity 140ms linear;
}

/* :not(.pixel-band-mirror) matters. The mirror is a clone, so it
   carries .pixel-band too, and without this it would match the
   clearing rule at higher specificity than the rule filling it, fill
   in and then empty straight back out. */
.band-wrap.is-clearing .pixel-band:not(.pixel-band-mirror) rect {
    opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
    .band-mirror rect { transition: none; opacity: 1; }
    .pixel-band rect { transition: none; }
}

/* ---- Band dissolve ----
   Expanding the case study clears the band the way the homepage cards
   reveal themselves, run backwards: a wavefront crosses top to bottom
   and, inside a band around it, blocks flip in random order rather
   than in a clean line. Per-block delays are set in script; this only
   says what a block does when its turn comes. */
@media (prefers-reduced-motion: reduce) {
}
