/* ============================================================================
   news-experience.css — the /news cinematic daily briefing.

   Design rules this file holds itself to:
     - typography IS the layout; cards are the exception, not the grid
     - two canvases only (paper + ink), alternating, so section changes read as
       lighting changes rather than as widget boundaries
     - the Defex accent is a highlight, never a fill
     - every animatable property is transform/opacity/clip-path

   Theme: the web host does not stamp `.mud-theme-dark`, so newsExperience.js
   measures the live MudBlazor surface colour and toggles `.news-dark` on the
   root. `.mud-theme-dark` is honoured too for the /mobile frame host.

   Anti-flash: the root is hidden until JS has applied initial tween states and
   added `.news-ready`. The delayed keyframe is the safety net — if GSAP never
   loads, the content still appears.
   ============================================================================ */

.news-root {
    --news-canvas: #FFFFFF;
    --news-canvas-alt: #F3F4F6;
    --news-ink: #0B1220;
    --news-text: #101828;
    --news-text-muted: #667085;
    /* AA floor, not a tint. This carries the timeline scale, chart labels, the insight
       index and the input placeholder — all text a reader has to actually read. The /news
       editorial exemption covers scale and voice; DESIGN.md is explicit that it does not
       cover contrast. Was rgba(16,24,40,.42) ≈ 2.6:1. */
    --news-text-faint: rgba(16, 24, 40, .68);
    --news-on-ink: #F8FAFC;
    --news-on-ink-muted: rgba(248, 250, 252, .60);
    --news-on-ink-faint: rgba(248, 250, 252, .62);
    /* Non-text marks only — dots, bar segments, rules. Free to stay light because nothing
       here has to be legible, only visible. Keeps the decorative weight the faint text
       colour used to carry before it was raised to the AA floor. */
    --news-mark-faint: rgba(16, 24, 40, .34);
    --news-line: rgba(16, 24, 40, .10);
    --news-line-strong: rgba(16, 24, 40, .22);
    --news-line-ink: rgba(248, 250, 252, .14);
    /* Resolved from the MudBlazor palette, never frozen. When a platform operator acts
       inside a customer tenant the whole app turns red as a SAFETY signal about whose data
       is on screen; a hard-coded #155DFC would leave this page blue and silently opt out of
       it. Secondary is the slot that carries the action blue in the default theme. */
    --news-accent: var(--mud-palette-secondary, #155DFC);
    --news-accent-soft: color-mix(in srgb, var(--mud-palette-secondary, #155DFC) 10%, transparent);
    --news-accent-ink: color-mix(in srgb, var(--mud-palette-secondary, #155DFC) 55%, #FFFFFF);
    --news-warn: #B54708;
    --news-warn-ink: #FDB022;
    --news-good: #067647;
    --news-good-ink: #47CD89;

    --news-display: 'Montserrat', 'Roboto', -apple-system, sans-serif;
    --news-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

    /* Horizontal rhythm. One value, used everywhere, so every section's left
       edge lines up down the whole page — the single strongest cue that this is
       one document and not seven widgets. */
    --news-gutter: clamp(20px, 6vw, 128px);
    --news-max: 1560px;

    position: relative;
    width: 100%;
    /* `.main-container` is a column flex box, so without this the page would be
       squashed to the container's height instead of scrolling. */
    flex: 0 0 auto;
    background: var(--news-canvas);
    color: var(--news-text);
    font-family: var(--news-display);
    -webkit-font-smoothing: antialiased;
    opacity: 0;
    animation: news-failsafe-in 1ms linear 1.6s forwards;
}

.news-root.news-ready {
    opacity: 1;
    animation: none;
}

/* Holds the viewport steady between navigation and first paint so the hero animates
   into a settled page rather than into a jump. Lives here rather than in an inline
   <style> in NewsExperience.razor — all CSS in this project is global (CLAUDE.md). */
.news-boot {
    min-height: calc(100dvh - var(--app-bar-offset, 60px));
}

@keyframes news-failsafe-in {
    to { opacity: 1; }
}

.news-root.news-dark,
.mud-theme-dark .news-root {
    --news-canvas: #0B1220;
    --news-canvas-alt: #101B30;
    --news-ink: #05080F;
    --news-text: #F8FAFC;
    --news-text-muted: #98A2B3;
    /* AA floor on the dark canvas too — was .38 ≈ 3:1. */
    --news-text-faint: rgba(248, 250, 252, .62);
    --news-mark-faint: rgba(248, 250, 252, .30);
    --news-line: rgba(248, 250, 252, .12);
    --news-line-strong: rgba(248, 250, 252, .24);
    --news-accent: var(--news-accent-ink);
    --news-accent-soft: color-mix(in srgb, var(--news-accent-ink) 12%, transparent);
    --news-warn: #FDB022;
    --news-good: #47CD89;
}

/* ---------------------------------------------------------------- structure */

.news-section {
    position: relative;
    width: 100%;
    background: var(--news-canvas);
    /* `clip` (not `hidden`) so the horizontal overspill of oversized type is cut
       without turning the section into a scroll container — and, unlike a clip on
       the page root, it can't interfere with the viewport-fixed progress rail. */
    overflow-x: clip;
}

.news-section--alt { background: var(--news-canvas-alt); }

/* Ink canvases stay dark in both themes — the contrast shift between paper and
   ink is the page's main cinematic device, so it must not invert. */
.news-section--ink {
    background: var(--news-ink);
    color: var(--news-on-ink);
    --news-text: var(--news-on-ink);
    --news-text-muted: var(--news-on-ink-muted);
    --news-text-faint: var(--news-on-ink-faint);
    --news-line: var(--news-line-ink);
    --news-line-strong: rgba(248, 250, 252, .28);
    --news-accent: var(--news-accent-ink);
    --news-accent-soft: color-mix(in srgb, var(--news-accent-ink) 12%, transparent);
    --news-warn: var(--news-warn-ink);
    --news-good: var(--news-good-ink);
}

.news-shell {
    max-width: var(--news-max);
    margin: 0 auto;
    padding-left: var(--news-gutter);
    padding-right: var(--news-gutter);
}

.news-pad { padding-top: clamp(88px, 14vh, 180px); padding-bottom: clamp(88px, 14vh, 180px); }
.news-pad-sm { padding-top: clamp(56px, 8vh, 104px); padding-bottom: clamp(56px, 8vh, 104px); }

/* Hairline that visually stitches one section to the next. Sits ON the boundary
   so the sections read as ruled columns of one page, not as stacked panels. */
.news-rule {
    height: 1px;
    background: var(--news-line);
    transform-origin: left center;
}

/* ------------------------------------------------------------------ type */

.news-eyebrow {
    font-family: var(--news-mono);
    font-size: clamp(10px, .72vw, 12px);
    font-weight: 500;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--news-text-faint);
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 0 0 clamp(28px, 4vh, 56px);
}

.news-eyebrow::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--news-line);
}

/* The one status treatment on this page that is NOT editorial. It inherits
   `.status-pill--warning` from utilities.css so a caveat about data truth reads
   the same here as anywhere else in the product; only its box behaviour inside
   the eyebrow's flex row is set here. `flex: none` stops the hairline's `flex: 1`
   squeezing it. */
.news-sample-tag {
    flex: none;
    margin-left: -4px;
}

.news-display {
    font-weight: 600;
    letter-spacing: -.035em;
    line-height: .94;
    margin: 0;
    font-size: clamp(2.6rem, 6.2vw, 6rem);
}

.news-display--xl {
    font-size: clamp(3.4rem, 13vw, 13rem);
    letter-spacing: -.05em;
    font-weight: 600;
}

.news-display--lg { font-size: clamp(3rem, 8vw, 8rem); letter-spacing: -.045em; }

.news-lede {
    font-size: clamp(1.05rem, 1.6vw, 1.6rem);
    font-weight: 400;
    line-height: 1.45;
    color: var(--news-text-muted);
    max-width: 46ch;
    margin: clamp(20px, 3vh, 36px) 0 0;
}

.news-note {
    font-size: clamp(.9rem, 1vw, 1.05rem);
    color: var(--news-text-muted);
    line-height: 1.6;
    margin: 0;
}

/* States what a capped list is not showing, and gives the route to the rest.
   Sits below the list it qualifies, in the same measure. */
.news-truncation {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 12px;
    margin-top: clamp(20px, 3vh, 36px);
}

.news-figure {
    font-variant-numeric: tabular-nums;
    font-feature-settings: 'tnum' 1;
    letter-spacing: -.045em;
    font-weight: 600;
    line-height: .86;
}

.news-accent { color: var(--news-accent); }

/* Word-mask reveal target. Each word is wrapped by JS in a clipping span so the
   line can rise out of its own baseline rather than fading in place. */
/* The padding/negative-margin pair keeps descenders (g, y, p) from being clipped
   by the mask's own overflow while the word is at rest. */
.news-mask {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    padding-bottom: .14em;
    margin-bottom: -.14em;
}

.news-mask > span { display: inline-block; will-change: transform; }

/* ------------------------------------------------------------ links / CTAs */

.news-link {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: var(--news-display);
    font-size: clamp(.9rem, 1.05vw, 1.05rem);
    font-weight: 500;
    letter-spacing: -.01em;
    color: var(--news-text);
    text-decoration: none;
    padding: 10px 0;
    border-bottom: 1px solid var(--news-line-strong);
    transition: color 240ms cubic-bezier(.22,1,.36,1), border-color 240ms cubic-bezier(.22,1,.36,1);
}

.news-link .news-link__arrow {
    display: inline-block;
    transition: transform 420ms cubic-bezier(.22,1,.36,1);
}

.news-link:hover { color: var(--news-accent); border-color: var(--news-accent); }
.news-link:hover .news-link__arrow { transform: translateX(6px); }
.news-link:focus-visible { outline: 2px solid var(--news-accent); outline-offset: 4px; }

/* Whole blocks that navigate. Kept borderless — the hover is a line and a
   colour shift, never a card lifting off the page. */
.news-hit {
    display: block;
    color: inherit;
    text-decoration: none;
    cursor: pointer;
}

.news-hit:focus-visible { outline: 2px solid var(--news-accent); outline-offset: 8px; border-radius: 4px; }

/* ================================================================== 1. HERO */

.news-hero {
    position: relative;
    min-height: calc(100dvh - var(--app-bar-offset, 60px));
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-top: clamp(72px, 10vh, 140px);
    padding-bottom: clamp(64px, 9vh, 120px);
    overflow: hidden;
}

/* Depth layer: an oversized, very low-contrast wordmark that parallaxes behind
   the greeting. Not decoration for its own sake — it gives the hero a back
   plane so the foreground type has somewhere to sit in front of. */
.news-hero__depth {
    position: absolute;
    inset: 0;
    pointer-events: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: var(--news-gutter);
    font-size: clamp(12rem, 34vw, 34rem);
    font-weight: 700;
    letter-spacing: -.06em;
    line-height: 1;
    color: var(--news-text);
    opacity: .028;
    user-select: none;
    will-change: transform;
}

.news-hero__grid {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(44px, 7vh, 96px);
}

.news-hero__greeting {
    font-size: clamp(2.6rem, 7.4vw, 7.2rem);
    font-weight: 600;
    letter-spacing: -.045em;
    line-height: .96;
    margin: 0;
}

.news-hero__greeting em {
    font-style: normal;
    color: var(--news-accent);
}

.news-hero__sub {
    font-size: clamp(1.15rem, 2.1vw, 2.1rem);
    font-weight: 400;
    letter-spacing: -.02em;
    color: var(--news-text-muted);
    margin: clamp(14px, 2vh, 26px) 0 0;
}

/* The four operational numbers. Deliberately a ruled row, not four cards:
   hairlines between columns, numbers doing the work. */
.news-metrics {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    border-top: 1px solid var(--news-line);
}

.news-metric {
    padding: clamp(24px, 3.4vh, 44px) clamp(14px, 2vw, 32px) clamp(20px, 2.6vh, 34px) 0;
    border-right: 1px solid var(--news-line);
    position: relative;
}

.news-metric:last-child { border-right: 0; }
.news-metric:not(:first-child) { padding-left: clamp(14px, 2vw, 32px); }

.news-metric__value {
    font-size: clamp(3rem, 6.4vw, 6.4rem);
    display: block;
}

.news-metric__label {
    display: block;
    margin-top: clamp(10px, 1.4vh, 18px);
    font-family: var(--news-mono);
    font-size: clamp(10px, .72vw, 12px);
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--news-text-muted);
}

.news-metric--flag .news-metric__value { color: var(--news-warn); }

.news-metric--flag .news-metric__label { color: var(--news-warn); }

/* Supporting line: prose, with the numbers inside it emphasised. */
.news-hero__support {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: clamp(16px, 2.4vw, 44px);
    font-size: clamp(1rem, 1.35vw, 1.35rem);
    font-weight: 400;
    color: var(--news-text-muted);
    letter-spacing: -.01em;
}

.news-hero__support b {
    font-weight: 600;
    color: var(--news-text);
    font-variant-numeric: tabular-nums;
}

.news-hero__scroll {
    position: absolute;
    left: var(--news-gutter);
    bottom: clamp(20px, 3.5vh, 44px);
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: var(--news-mono);
    font-size: 11px;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--news-text-faint);
}

.news-hero__scroll i {
    display: block;
    width: 44px;
    height: 1px;
    background: currentColor;
    transform-origin: left center;
}

/* ========================================================== 2. ATTENTION */

/* DEFAULT = the plain, always-readable flow layout. The pinned/travelling
   composition is opt-IN via `.news-attention--pinned`, which newsExperience.js
   adds only on a wide viewport with GSAP present and motion allowed. If the
   animation system never starts, this section still reads as three ruled
   blocks rather than three panels stacked on top of each other. */
.news-attention__stage {
    padding-top: clamp(64px, 9vh, 120px);
    padding-bottom: clamp(64px, 9vh, 120px);
}

.news-attention--pinned .news-attention__stage {
    min-height: calc(100dvh - var(--app-bar-offset, 60px));
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: hidden;
}

.news-attention--pinned .news-attention__stage > .news-shell { width: 100%; }

.news-attention__head { max-width: 40ch; }

.news-attention__deck {
    position: relative;
    margin-top: clamp(40px, 6vh, 88px);
}

/* Reserve the tallest panel's height so the pinned deck never reflows as items
   swap in and out. */
.news-attention--pinned .news-attention__deck {
    min-height: clamp(300px, 40vh, 440px);
}

.news-attention__item {
    display: grid;
    grid-template-columns: minmax(0, .48fr) minmax(0, .52fr);
    gap: clamp(28px, 5vw, 88px);
    align-items: start;
    border-top: 1px solid var(--news-line);
    padding-top: clamp(22px, 3vh, 40px);
    margin-bottom: clamp(40px, 6vh, 80px);
}

/* Pinned: panels stack in the same box; the scroll timeline cross-fades and
   slides them past each other so the reader travels THROUGH the issues. */
.news-attention--pinned .news-attention__item {
    position: absolute;
    inset: 0;
    margin-bottom: 0;
    will-change: transform, opacity;
}

.news-attention__count {
    font-size: clamp(4.5rem, 15vw, 11rem);
    line-height: .78;
    letter-spacing: -.06em;
    color: var(--news-text);
}

.news-attention--pinned .news-attention__count {
    font-size: clamp(6rem, 20vw, 20rem);
}

.news-attention__body { padding-top: clamp(6px, 1.4vh, 20px); }

.news-attention__headline {
    font-size: clamp(1.6rem, 3.4vw, 3.4rem);
    font-weight: 600;
    letter-spacing: -.035em;
    line-height: 1.02;
    margin: 0;
}

.news-attention__detail {
    margin: clamp(14px, 2vh, 26px) 0 0;
    font-size: clamp(1rem, 1.35vw, 1.4rem);
    color: var(--news-text-muted);
    line-height: 1.4;
}

.news-attention__detail b {
    color: var(--news-text);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.news-attention__cta { margin-top: clamp(22px, 3.2vh, 44px); }

/* Position readout for the pinned deck: 01 — 03. Meaningless when the panels
   are simply listed, so it only exists in pinned mode. */
.news-attention__ticker { display: none; }

.news-attention--pinned .news-attention__ticker {
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: var(--news-mono);
    font-size: 11px;
    letter-spacing: .2em;
    color: var(--news-text-faint);
    margin-bottom: clamp(18px, 2.4vh, 30px);
}

.news-attention__ticker i {
    display: block;
    width: clamp(60px, 12vw, 160px);
    height: 1px;
    background: var(--news-line-strong);
    position: relative;
    overflow: hidden;
}

/* Fill is driven by --news-fill (written by the pinned ScrollTrigger) because a
   pseudo-element cannot be tweened directly. */
.news-attention__ticker i::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--news-accent);
    transform: scaleX(var(--news-fill, 0));
    transform-origin: left center;
}

/* ============================================================== 3. TODAY */

.news-today__head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 32px;
    flex-wrap: wrap;
}

.news-timeline {
    position: relative;
    margin-top: clamp(40px, 6vh, 84px);
}

.news-timeline__scale {
    position: relative;
    height: 26px;
    margin-bottom: 10px;
}

.news-timeline__tick {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    font-family: var(--news-mono);
    font-size: 10px;
    letter-spacing: .12em;
    color: var(--news-text-faint);
}

/* The rule the whole schedule hangs off. Drawn left-to-right by GSAP, which sets
   the zeroed start state itself — CSS leaves it at rest so a missing animation
   system means "drawn already", never "invisible". */
.news-timeline__rule {
    height: 1px;
    background: var(--news-line-strong);
    transform-origin: left center;
}

.news-timeline__rows { margin-top: clamp(14px, 2vh, 26px); }

.news-appt {
    position: relative;
    display: grid;
    grid-template-columns: clamp(56px, 6vw, 84px) minmax(0, 1fr);
    align-items: center;
    gap: clamp(12px, 2vw, 28px);
    padding: clamp(9px, 1.2vh, 15px) 0;
    border-bottom: 1px solid var(--news-line);
}

.news-appt__time {
    font-family: var(--news-mono);
    font-size: clamp(11px, .85vw, 13px);
    letter-spacing: .06em;
    color: var(--news-text-muted);
    font-variant-numeric: tabular-nums;
}

.news-appt__track {
    position: relative;
    height: clamp(30px, 4vh, 40px);
    display: flex;
    align-items: center;
}

/* The bar is absolutely positioned along the day's hour span and grows from its
   own left edge, so the schedule literally draws itself across the screen. */
.news-appt__bar {
    position: absolute;
    top: 50%;
    /* Centred with margin rather than translateY so GSAP owns `transform`
       outright and never has to round-trip a percentage translate. */
    margin-top: -1px;
    transform-origin: left center;
    height: 2px;
    background: var(--news-line-strong);
    will-change: transform;
}

.news-appt__label {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding-left: 14px;
    white-space: nowrap;
    max-width: 60%;
    overflow: hidden;
    text-overflow: ellipsis;
}

.news-appt__who {
    font-size: clamp(.95rem, 1.25vw, 1.25rem);
    font-weight: 600;
    letter-spacing: -.02em;
}

.news-appt__where {
    font-size: clamp(.8rem, 1vw, 1rem);
    color: var(--news-text-muted);
    letter-spacing: -.01em;
}

.news-appt__dot {
    position: absolute;
    top: 50%;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    background: var(--news-mark-faint);
}

.news-appt--complete .news-appt__dot { background: var(--news-good); }
.news-appt--complete .news-appt__bar { background: var(--news-good); opacity: .5; }
.news-appt--active .news-appt__dot { background: var(--news-accent); }
.news-appt--active .news-appt__bar { background: var(--news-accent); height: 3px; margin-top: -1.5px; }
.news-appt--active .news-appt__who { color: var(--news-accent); }
.news-appt--attention .news-appt__dot { background: var(--news-warn); }
.news-appt--attention .news-appt__bar { background: var(--news-warn); }

.news-appt:hover .news-appt__where { color: var(--news-text); }

.news-idle {
    margin-top: clamp(34px, 5vh, 64px);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: clamp(14px, 2vw, 32px);
    padding-top: clamp(20px, 2.6vh, 32px);
    border-top: 1px solid var(--news-line);
}

.news-idle__label {
    font-family: var(--news-mono);
    font-size: 11px;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--news-warn);
}

.news-idle__name {
    font-size: clamp(1rem, 1.3vw, 1.3rem);
    font-weight: 500;
    letter-spacing: -.02em;
}

.news-idle__name span {
    color: var(--news-text-muted);
    font-weight: 400;
    margin-left: 8px;
    font-size: .82em;
}

/* =================================================== 4. SERVICE DELIVERY */

.news-delivery__number {
    display: block;
    font-size: clamp(4.2rem, 19vw, 19rem);
    line-height: .82;
    letter-spacing: -.055em;
}

.news-delivery__caption {
    font-size: clamp(1.15rem, 2.4vw, 2.4rem);
    font-weight: 400;
    letter-spacing: -.03em;
    color: var(--news-text-muted);
    margin: clamp(16px, 2.4vh, 32px) 0 0;
    max-width: 24ch;
}

/* The "workload landscape": a drawn SVG trace with the split bar beneath it.
   Replaces the doughnut chart the brief explicitly ruled out. */
.news-landscape {
    margin-top: clamp(48px, 7vh, 100px);
    position: relative;
}

.news-landscape__svg {
    display: block;
    width: 100%;
    height: clamp(120px, 22vh, 240px);
    overflow: visible;
}

.news-landscape__trace {
    fill: none;
    stroke: var(--news-accent);
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

.news-landscape__area { fill: var(--news-accent-soft); }


.news-split {
    display: flex;
    width: 100%;
    height: 3px;
    margin-top: clamp(30px, 4vh, 56px);
    gap: 3px;
}

.news-split__seg {
    height: 100%;
    transform-origin: left center;
    will-change: transform;
}

.news-split__seg--done { background: var(--news-accent); }
.news-split__seg--sched { background: var(--news-mark-faint); }
.news-split__seg--out { background: var(--news-warn); }

.news-splitlegend {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(18px, 3vw, 56px);
    margin-top: clamp(22px, 3vh, 36px);
}

.news-splitlegend__pct {
    font-size: clamp(1.8rem, 3.4vw, 3.4rem);
    font-weight: 600;
    letter-spacing: -.04em;
    line-height: 1;
    display: block;
}

.news-splitlegend__label {
    display: block;
    margin-top: 10px;
    font-size: clamp(.85rem, 1.05vw, 1.05rem);
    color: var(--news-text-muted);
    letter-spacing: -.01em;
}

/* ========================================================== 5. LIFECYCLE */

/* Same opt-in rule as Attention: the vertical sequence below is the DEFAULT, and
   `.news-lifecycle--pinned` (added by newsExperience.js only on a wide viewport,
   with GSAP, with motion allowed) turns it into the horizontal travelling track. */
.news-lifecycle__stage { padding-bottom: clamp(56px, 8vh, 104px); }

.news-lifecycle__head { flex: 0 0 auto; }

.news-lifecycle__viewport { position: relative; }

.news-lifecycle__track {
    padding-left: var(--news-gutter);
    padding-right: var(--news-gutter);
    max-width: var(--news-max);
    margin: 0 auto;
}

.news-lifecycle__stageitem {
    position: relative;
    padding: clamp(22px, 3vh, 40px) 0;
    border-top: 1px solid var(--news-line);
    transform-origin: left center;
}

/* ---- pinned / horizontal composition ---- */

.news-lifecycle--pinned .news-lifecycle__stage {
    height: calc(100dvh - var(--app-bar-offset, 60px));
    padding-bottom: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: hidden;
}

.news-lifecycle--pinned .news-lifecycle__viewport {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    min-height: 0;
    overflow: hidden;
}

/* The horizontally travelling track. Vertical scroll drives translateX while
   the section is pinned, so work visibly flows left-to-right through the system. */
.news-lifecycle--pinned .news-lifecycle__track {
    display: flex;
    align-items: center;
    gap: clamp(48px, 9vw, 180px);
    padding-right: 40vw;
    max-width: none;
    margin: 0;
    will-change: transform;
}

.news-lifecycle--pinned .news-lifecycle__stageitem {
    flex: 0 0 auto;
    min-width: clamp(180px, 22vw, 340px);
    padding: 0;
    border-top: 0;
    will-change: transform, opacity;
}

.news-lifecycle__label {
    font-family: var(--news-mono);
    font-size: clamp(10px, .8vw, 13px);
    letter-spacing: .26em;
    text-transform: uppercase;
    color: var(--news-text-muted);
    display: block;
    margin-bottom: clamp(12px, 1.8vh, 22px);
}

.news-lifecycle__count {
    font-size: clamp(4rem, 11vw, 11rem);
    line-height: .84;
    letter-spacing: -.055em;
    display: block;
}

.news-lifecycle__caption {
    display: block;
    margin-top: clamp(12px, 1.8vh, 22px);
    font-size: clamp(.85rem, 1.05vw, 1.05rem);
    color: var(--news-text-muted);
    letter-spacing: -.01em;
}

/* Connector between stages, so the gaps read as flow rather than as padding.
   Vertical in the default sequence, horizontal once pinned. */
.news-lifecycle__link {
    display: block;
    width: 1px;
    height: clamp(28px, 5vh, 56px);
    margin-top: clamp(16px, 2vh, 24px);
    background: var(--news-line-strong);
    transform-origin: top center;
}

.news-lifecycle--pinned .news-lifecycle__link {
    position: absolute;
    top: calc(50% - 1px);
    left: 100%;
    width: clamp(48px, 9vw, 180px);
    height: 1px;
    margin-top: 0;
    transform-origin: left center;
}

.news-lifecycle--pinned .news-lifecycle__link::after {
    content: '';
    position: absolute;
    right: -3px;
    top: -2px;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--news-accent);
    opacity: var(--news-dot, 0);
}

.news-lifecycle__stageitem.is-active .news-lifecycle__count { color: var(--news-accent); }

/* ============================================================== 6. MONEY */

.news-money__grid {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    gap: clamp(40px, 6vw, 120px);
    align-items: end;
}

.news-money__headline {
    font-size: clamp(3.4rem, 11vw, 11rem);
    line-height: .84;
    letter-spacing: -.055em;
    display: block;
}

.news-money__delta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: clamp(18px, 2.6vh, 32px);
    font-size: clamp(1rem, 1.4vw, 1.4rem);
    font-weight: 500;
    letter-spacing: -.02em;
    color: var(--news-good);
}

.news-money__delta--down { color: var(--news-warn); }

.news-money__breakdown { border-top: 1px solid var(--news-line); }

.news-money__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
    padding: clamp(16px, 2.2vh, 28px) 0;
    border-bottom: 1px solid var(--news-line);
}

.news-money__row-value {
    font-size: clamp(1.6rem, 3vw, 3rem);
    font-weight: 600;
    letter-spacing: -.04em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.news-money__row-label {
    font-size: clamp(.9rem, 1.1vw, 1.1rem);
    color: var(--news-text-muted);
    letter-spacing: -.01em;
    text-align: right;
}

.news-money__row--overdue .news-money__row-value { color: var(--news-warn); }

/* One chart, drawn as ruled columns — annual-report, not Power BI. */
.news-bars {
    display: flex;
    align-items: flex-end;
    gap: clamp(8px, 1.4vw, 22px);
    height: clamp(120px, 20vh, 220px);
    margin-top: clamp(44px, 6vh, 88px);
    border-bottom: 1px solid var(--news-line-strong);
}

.news-bars__col { flex: 1 1 0; display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }

.news-bars__bar {
    width: 100%;
    background: var(--news-line-strong);
    transform-origin: bottom center;
    will-change: transform;
}

.news-bars__col:last-child .news-bars__bar { background: var(--news-accent); }

.news-bars__label {
    margin-top: 12px;
    font-family: var(--news-mono);
    font-size: 10px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--news-text-faint);
    text-align: center;
}

/* ============================================================ 7. ASK DEX */

.news-dex { position: relative; overflow: hidden; }

.news-dex__head { max-width: 24ch; }

.news-dex__title {
    font-size: clamp(2.4rem, 6.4vw, 6.4rem);
    font-weight: 600;
    letter-spacing: -.045em;
    line-height: .96;
    margin: 0;
}

.news-dex__title span { color: var(--news-accent); }

/* The input is the section's centrepiece: a single ruled line, not a boxed
   control, so it reads as an invitation rather than a form field. */
.news-dex__field {
    position: relative;
    margin-top: clamp(44px, 6vh, 88px);
    display: flex;
    align-items: center;
    gap: clamp(14px, 2vw, 28px);
    border-bottom: 1px solid var(--news-line-strong);
    padding-bottom: clamp(14px, 2vh, 22px);
    transition: border-color 320ms cubic-bezier(.22,1,.36,1);
}

.news-dex__field:focus-within { border-color: var(--news-accent); }

.news-dex__input {
    flex: 1 1 auto;
    min-width: 0;
    background: transparent;
    border: 0;
    outline: none;
    color: var(--news-text);
    font-family: var(--news-display);
    font-size: clamp(1.1rem, 2.2vw, 2.2rem);
    font-weight: 400;
    letter-spacing: -.03em;
    padding: 0;
}

.news-dex__input::placeholder { color: var(--news-text-faint); }

.news-dex__go {
    flex: 0 0 auto;
    appearance: none;
    padding: 0;
    font-size: 1.05rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: clamp(40px, 4vw, 54px);
    height: clamp(40px, 4vw, 54px);
    border-radius: 50%;
    border: 1px solid var(--news-line-strong);
    background: transparent;
    color: var(--news-text);
    cursor: pointer;
    transition: background-color 260ms cubic-bezier(.22,1,.36,1), color 260ms, border-color 260ms;
}

.news-dex__go:hover { background: var(--news-accent); border-color: var(--news-accent); color: #fff; }
.news-dex__go:focus-visible { outline: 2px solid var(--news-accent); outline-offset: 3px; }

/* Rotating example questions sitting under the rule. One at a time, cross-faded
   by the GSAP loop — calm, not a marquee. */
.news-dex__suggestions {
    position: relative;
    height: clamp(30px, 4vh, 42px);
    margin-top: clamp(16px, 2vh, 24px);
}

.news-dex__suggestion {
    position: absolute;
    inset: 0;
    /* Button reset — these are real buttons (each one asks Dex that question),
       so none of the UA chrome is wanted. */
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    text-align: left;
    font-family: var(--news-display);
    font-weight: 400;
    display: flex;
    align-items: center;
    font-size: clamp(.95rem, 1.25vw, 1.25rem);
    color: var(--news-text-muted);
    letter-spacing: -.015em;
    cursor: pointer;
    /* Only the first is at rest; the GSAP loop takes over from there. Without
       the animation system the reader still sees one legible question rather
       than five stacked on top of each other. */
    opacity: 0;
    visibility: hidden;
    will-change: transform, opacity;
}

.news-dex__suggestion:first-child { opacity: 1; visibility: visible; }

.news-dex__suggestion:hover { color: var(--news-accent); }
.news-dex__suggestion:focus-visible { outline: 2px solid var(--news-accent); outline-offset: 4px; }

.news-insights { margin-top: clamp(72px, 11vh, 160px); }

.news-insights__lede {
    font-family: var(--news-mono);
    font-size: clamp(10px, .75vw, 12px);
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--news-accent);
    margin: 0 0 clamp(26px, 4vh, 48px);
}

.news-insight {
    display: grid;
    grid-template-columns: clamp(40px, 5vw, 72px) minmax(0, 1fr) auto;
    gap: clamp(18px, 3vw, 48px);
    align-items: baseline;
    padding: clamp(24px, 3.4vh, 44px) 0;
    border-top: 1px solid var(--news-line);
}

.news-insight:last-child { border-bottom: 1px solid var(--news-line); }

.news-insight__index {
    font-family: var(--news-mono);
    font-size: 11px;
    letter-spacing: .16em;
    color: var(--news-text-faint);
}

.news-insight__headline {
    font-size: clamp(1.3rem, 2.4vw, 2.4rem);
    font-weight: 600;
    letter-spacing: -.035em;
    line-height: 1.1;
    margin: 0;
}

.news-insight__body {
    margin: clamp(10px, 1.4vh, 16px) 0 0;
    font-size: clamp(.95rem, 1.2vw, 1.2rem);
    color: var(--news-text-muted);
    line-height: 1.5;
    max-width: 56ch;
}

.news-insight__action { white-space: nowrap; }

/* ====================================================== PROGRESS RAIL */

/* The one element present in every section: a hairline at the viewport edge
   that fills as the briefing is read. Gives the whole page a single spine. */
.news-progress {
    position: fixed;
    right: clamp(10px, 1.6vw, 26px);
    top: calc(var(--app-bar-offset, 60px) + clamp(40px, 12vh, 120px));
    bottom: clamp(40px, 12vh, 120px);
    width: 1px;
    background: var(--news-line);
    z-index: 3;
    pointer-events: none;
}

.news-progress i {
    display: block;
    width: 100%;
    height: 100%;
    background: var(--news-accent);
    transform: scaleY(0);
    transform-origin: top center;
    will-change: transform;
}

@media (max-width: 900px) {
    .news-progress { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .news-progress { display: none; }
}

/* ============================================================== FOOTER */

.news-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: clamp(28px, 4vh, 48px) 0 clamp(40px, 6vh, 72px);
    border-top: 1px solid var(--news-line);
    font-size: .82rem;
    /* Muted, not faint. This line names which figures above are illustrative, and a
       disclosure a reader cannot comfortably read is not a disclosure — `--news-text-faint`
       is ~3:1 on ink and fails AA. The editorial exemption covers scale and voice; it does
       not cover whether a caveat is legible. */
    color: var(--news-text-muted);
    letter-spacing: -.01em;
}

.news-foot code {
    font-family: var(--news-mono);
    font-size: .78rem;
    color: var(--news-text-muted);
}

/* ============================================================ RESPONSIVE */

@media (max-width: 1200px) {
    .news-money__grid { grid-template-columns: minmax(0, 1fr); gap: clamp(36px, 6vh, 64px); align-items: start; }
    .news-attention__item { grid-template-columns: minmax(0, 1fr); gap: clamp(12px, 2vh, 24px); }
    .news-attention__count { font-size: clamp(5rem, 16vw, 13rem); }
}

@media (max-width: 900px) {
    .news-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .news-metric { border-bottom: 1px solid var(--news-line); }
    .news-metric:nth-child(2n) { border-right: 0; }
    .news-metric:nth-child(n+3) { border-bottom: 0; }
    .news-hero__depth { display: none; }
    .news-insight { grid-template-columns: minmax(0, 1fr); gap: 10px; }
    .news-insight__index { display: none; }
    .news-splitlegend { grid-template-columns: minmax(0, 1fr); gap: 18px; }
    .news-appt__label { position: static; transform: none; max-width: none; padding-left: 0; }
    .news-appt { grid-template-columns: minmax(0, 1fr); gap: 6px; }
    .news-appt__track { height: 20px; }
    .news-appt__time { order: -1; }
    .news-today__head { align-items: flex-start; }
}

@media (max-width: 600px) {
    .news-hero,
    .news-attention__stage { min-height: auto; }
    .news-hero__greeting { font-size: clamp(2.2rem, 11vw, 3.4rem); }
    .news-metrics { grid-template-columns: minmax(0, 1fr); }
    .news-metric { border-right: 0; border-bottom: 1px solid var(--news-line); padding-left: 0 !important; }
    .news-metric__value { font-size: clamp(3.2rem, 18vw, 5rem); }
    .news-hero__scroll { display: none; }
    .news-bars { height: 120px; }
}

/* ======================================================= REDUCED MOTION */

/* Reduced motion: newsExperience.js exits before creating a single tween, so the
   page is already at rest — the only work left is to neutralise the CSS
   transitions and drop the decorative rail. Pinning and the horizontal sequence
   never happen, because `--pinned` is only ever added by the animation path. */
@media (prefers-reduced-motion: reduce) {
    .news-root { opacity: 1 !important; animation: none !important; }

    .news-dex__suggestion:not(:first-child) { display: none; }

    .news-link,
    .news-link .news-link__arrow,
    .news-dex__field,
    .news-dex__go { transition: none !important; }
}
