/* --------------------------------------------------------------------------
   home.css — the three moving parts of the homepage
   Loaded only by /index.html, after styles.css, and it adds nothing that the
   page needs in order to be correct. Every animation here is an enhancement
   layered on top of a complete static page:

     * the hero degrades to its first photograph
     * the shelf degrades to five covers, face out
     * the ride figures are baked into the HTML and merely count up to what
       is already written there

   which is why prefers-reduced-motion and a JavaScript failure both land in
   the same, correct, place.
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   1. The rotating hero

   The first frame is an ordinary in-flow image: it sizes the box, it is the
   LCP candidate, it loads eagerly and at high priority, and it is never
   faded in from blank. Every later frame is absolutely positioned over it and
   starts transparent, so with no JavaScript — or with reduced motion — the
   page shows exactly the photograph it showed before.

   The cross-fade only ever fades a frame IN over an opaque one, and drops the
   outgoing frame once the incoming one has arrived. Fading both at once would
   let the base image show through the middle of the transition.
   -------------------------------------------------------------------------- */
.home-hero { position: relative; }

.home-hero .hero-frame {
    /* Keep the card's own hover scale — a bare `transition: opacity` here
       would out-specify .feature-media img and lose it. */
    transition: opacity 1600ms ease-in-out, transform var(--transition-base);
}

/* Every frame after the first is stacked on top at zero opacity, so with
   JavaScript off exactly one photograph shows and it is the right one.
   object-position is set per image in the markup: these are 3:2 originals in a
   16:7 frame, so a third of the height goes, and taking it from the middle
   beheads the riders. Three of the ten needed the crop taken from the top. */
.home-hero .hero-frame + .hero-frame {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    opacity: 0;
}

.home-hero .hero-frame.is-showing { opacity: 1; }

/* These three are 3:2 originals in a 16:7 frame, so roughly a third of the
   height is cropped away. Left to itself the crop takes the middle, which
   beheads the riders; each is nudged to where its subject actually sits. */
/* The caption for the photograph currently showing. Sits over the foot of the
   image, which is where the eye lands last. */
.hero-caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0;
    padding: 2.6rem 1.1rem 0.85rem;
    background: linear-gradient(to top, rgba(42, 35, 24, 0.82), transparent);
    pointer-events: none;
}

.hero-caption-line {
    display: block;
    grid-area: 1 / 1;
    font-family: var(--font-body);
    font-size: 0.9rem;
    line-height: 1.35;
    color: var(--color-band-text);
    opacity: 0;
    transition: opacity 700ms ease-in-out;
}

.hero-caption { display: grid; }

/* Without JavaScript the first caption shows, because the first photograph is
   the one on screen. Once the script takes over it adds .js-caps and drives
   them explicitly — otherwise :first-child would keep caption one visible
   underneath every later one. */
.hero-caption-line:first-child { opacity: 1; }
.js-caps .hero-caption-line { opacity: 0; }
.js-caps .hero-caption-line.is-showing { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    .hero-caption-line { transition: none; }
}


/* --------------------------------------------------------------------------
   2. Ride figures

   The numbers are written into the HTML at build time from cycling/_rides.json
   (which is deliberately not deployed), so they are right in view-source, in
   a feed reader, and with scripting off. The script counts up TO them; it
   never supplies them.
   -------------------------------------------------------------------------- */
.activity-stats {
    max-width: var(--container-max);
    margin: 0 auto;
    padding: var(--space-2xl) var(--container-padding) 0;
}

.activity-stats-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-md);
    padding-bottom: var(--space-sm);
    border-bottom: 1px solid var(--color-border-light);
    margin-bottom: var(--space-lg);
}

.activity-stats-heading {
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.activity-stats-all {
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--color-accent);
    border-bottom: 1px solid currentColor;
    white-space: nowrap;
}

.activity-stats-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-lg) var(--space-md);
    margin: 0;
}

.ride-stat {
    padding-left: var(--space-md);
    border-left: 1px solid var(--color-border-light);
}
.ride-stat:first-child {
    padding-left: 0;
    border-left: 0;
}

.ride-stat-label {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--color-stone);
    margin-bottom: var(--space-xs);
}

.ride-stat-value {
    margin: 0;
    font-family: var(--font-brand);
    font-size: clamp(1.9rem, 4vw, 2.9rem);
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--color-ink);
    /* Tabular figures so a counting number cannot jiggle its own tile. */
    font-variant-numeric: tabular-nums;
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
}

.ride-stat-unit {
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-accent);
}

.ride-stat-span {
    font-size: clamp(1.5rem, 3vw, 2.1rem);
    letter-spacing: -0.02em;
}


/* --------------------------------------------------------------------------
   3. The shelf

   The markup inside the RECENT_READING markers belongs to generate_reading.py
   and is rewritten wholesale on every run, so nothing here may depend on it
   carrying extra attributes. home.js builds the two faces at runtime out of
   the cover, title and author the generator already emits; these rules style
   whatever it builds, and match nothing at all until it does.

   The card keeps the cover's own 2:3 box, so a flip cannot move the page.
   -------------------------------------------------------------------------- */
.recent-list li { perspective: 900px; }

.shelf-card {
    display: block;
    position: relative;
    width: 100%;
    aspect-ratio: 2 / 3;
    transform-style: preserve-3d;
    transition: transform 1500ms cubic-bezier(0.45, 0, 0.2, 1);
}
.shelf-card.is-flipped { transform: rotateY(180deg); }

.shelf-face {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

.shelf-face img {
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    object-fit: cover;
}

/* A bookplate rather than a second cover: parchment, the display face the
   rest of the homepage never gets to use, and the accent for the kicker. */
.shelf-back {
    transform: rotateY(180deg);
    background: var(--color-parchment);
    border: 1px solid var(--color-border);
    box-shadow: 0 2px 10px -4px rgba(42, 35, 24, 0.35);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    padding: var(--space-sm) 0.75rem;
    overflow: hidden;
}

.shelf-back-kicker {
    font-size: 0.58rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-accent);
    margin-bottom: var(--space-xs);
}

.shelf-back-title {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.15rem;
    line-height: 1.2;
    color: var(--color-ink);
}

.shelf-back-rule {
    display: block;
    width: 26px;
    height: 1px;
    background: var(--color-rule);
    margin: var(--space-xs) 0;
}

.shelf-back-author {
    font-size: 0.7rem;
    line-height: 1.35;
    color: var(--color-stone);
}


/* --------------------------------------------------------------------------
   Reduced motion

   home.js bails out entirely, so the hero never gains .is-showing, no shelf
   card is ever built, and the figures stay as written. These rules only make
   sure that nothing can transition on the way to that resting state.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .home-hero .hero-frame,
    .shelf-card {
        transition: none;
    }
}


@media (max-width: 1000px) {
    .activity-stats-grid { grid-template-columns: repeat(2, 1fr); }
    .ride-stat:nth-child(odd) {
        padding-left: 0;
        border-left: 0;
    }
}

@media (max-width: 420px) {
    .activity-stats-grid { grid-template-columns: 1fr; }
    .ride-stat {
        padding-left: 0;
        border-left: 0;
    }
}

/* The accumulated-spice figure carries the mark rather than the word, so it
   reads in the same glance as "km" and "m" beside it. */
.ride-stat-chilli {
    /* 2.4em, not 1.15em, because this sits inside .ride-stat-unit at 0.78rem
       — sized for the words KM and M — while standing beside a numeral several
       times its height. At the old size the mark read as a stray comma rather
       than a chilli, which is the whole reason it is a mark and not a word. */
    width: 2.4em;
    height: 2.4em;
    fill: var(--color-accent);
    vertical-align: -0.62em;
}
