/* public/src/css/hero.css
   THE HERO, and the front page under it.

   Materials (CLAUDE.md rule 3), and every rule below belongs to exactly one:

     Furniture   .hero band, .hero-head, .hero-stand, .hero-cta, the teasers,
                 and the front page's own grid. Structure and navigation.
                 None of it depends on the catalogue, the clock, or where the
                 reader is standing.
     Reported    .above - the WHAT'S ABOVE YOU panel. The number in it is the
                 count of catalogued objects over the reader's horizon, off
                 the same sweep that draws the scope below. It wears
                 cards.css's LIVE badge, and front.js takes that badge OFF in
                 every state that has no real count behind it.
     Marginalia  .hero-hand. The bloke. Last in its block, lime, on the tilt -
                 page.css's .hand does the work, this only places it.

   No Clipping on this page: nothing here is a snapshot the station has
   committed to print.

   Every colour is a tokens.css semantic name. The pairs used are the ones
   already measured in test/contrast.js - ink/void, ink/panel, ink-dim/void,
   ink-dim/panel, signal/void, signal/panel, on-signal/signal and
   edge-strong/panel. No new pair is introduced anywhere in this file. */

/* ── The band (Furniture) ────────────────────────────────────────────────
   Full-bleed, and it gets there by sitting outside .paper in index.html
   rather than by any 100vw trick: 100vw counts the scrollbar, so a vw-based
   break-out puts a desktop page ~15px sideways and fails the "nothing
   overflows at 390px" rule the moment a scrollbar appears. This element is
   just a block at width 100%; .hero-in does the centring.

   The tint is decoration - a soft lift of --panel over the --void ground.
   Both ends of it are measured grounds for both inks, so no text sitting on
   it can land on an unmeasured colour. */
.hero{
  background:
    radial-gradient(115% 95% at 76% 24%, var(--panel) 0%, transparent 64%),
    var(--void);
  border-bottom:1px solid var(--edge);
}

/* ON THE GRID, and this is the whole point of splitting .hero from .hero-in.
   The BACKGROUND above runs the full width of the viewport; the CONTENT is
   held to .paper's own 64rem measure with .paper's own horizontal padding
   clamp, so the headline's left edge lands on exactly the same pixel as the
   masthead wordmark's and the dateline's. An earlier version widened this to
   76rem to buy the headline room, and the result was a hero hanging 95px
   left of everything above it - which reads as a slip, not a decision. The
   band still feels wider than the column; it does it with the background,
   which is what a full-bleed band is supposed to do. */
.hero-in{
  max-width:64rem;
  margin:0 auto;
  padding:clamp(1.25rem,4vw,2.75rem) clamp(1rem,4vw,2.5rem) clamp(1.75rem,4vw,3rem);
  display:grid;
  gap:clamp(1.5rem,2.5vw,2rem);
}

/* The copy column. container-type is what makes the headline size itself
   against THIS column instead of the viewport - the two stop agreeing the
   moment the panel appears beside it at 56rem, and a vw-based clamp that
   fits at 1440 overflows badly at 900. */
.hero-main{
  container-type:inline-size;
  position:relative;
  min-width:0;
}

/* ── The headline (Furniture) ──
   Three lines, three spans, because voice.js decides where they break.
   font-stretch:75% is the wdth axis index.html requests for this page: it
   is what makes twenty-one characters of 800-weight display type fit the
   column at a size that still outranks the masthead. */
.hero-head{
  font-family:var(--f-head);
  font-weight:800;
  font-stretch:75%;
  /* Optical sizing OFF, and this is load-bearing rather than taste.
     Bricolage's opsz axis is auto-driven by font-size, and the small-size
     cut is a full 16% wider per em than the display cut (measured: 9.06em
     for the longest line at 38px against 7.83em at 74px). That means the
     headline's width-per-em CHANGES as it scales, so no single cqw
     coefficient can fit it at both ends - the first attempt fitted at 1440
     and wrapped at 390. Pinned, the ratio is a flat 7.83em everywhere.

     12cqw then fills 94% of the column at every width the layout produces,
     leaving 6% for a font that renders a hair wider than measured. The
     lines may still wrap rather than being held on one line: if the webfont
     fails to load the fallback is far wider than Bricolage at 75%, and a
     wrapped headline is ugly where an overflowing one is broken. */
  font-optical-sizing:none;
  font-size:clamp(1.9rem,12cqw,6.5rem);
  line-height:.86;
  letter-spacing:-.005em;
  text-transform:uppercase;
  color:var(--ink);
  margin:0 0 clamp(1rem,2.2cqw,1.5rem);
}
.hero-head span{display:block}
/* The third line, lit. The one place --signal appears at display size. */
.hero-head .lit{color:var(--signal)}

/* ── The standfirst (Furniture) ──
   A plain reading measure while the hero is one column. The column-relative
   cap that keeps it clear of the mascot is applied at 56rem and up, where
   the mascot is actually beside it - applied here as well it squeezed this
   paragraph into four short lines on a phone, for a collision that cannot
   happen at that width. */
.hero-stand{
  font-family:var(--f-body);
  font-size:var(--step-1);
  line-height:1.5;
  color:var(--ink-dim);
  max-width:34rem;
  margin:0 0 1.5rem;
}

/* ── The call to action (Furniture) ──
   The same measured pair as page.css's masthead .cta (--on-signal on
   --signal), at poster size. Hover and active only move brightness and
   shadow, so that pair never changes underneath them. */
.hero-cta{
  display:inline-flex;align-items:center;justify-content:center;
  white-space:nowrap;
  font-family:var(--f-head);font-weight:800;
  /* Column-relative, and measured: held at a flat --step-1 the label is
     313px wide, which overflows a 320px phone (sw 329 against cw 320 - the
     sweep caught it). Shrinking the type on the narrowest screens keeps the
     label on one line instead of stacking it inside the pill, and it is
     what leaves the illustration clear room at the 56rem breakpoint too. */
  font-size:clamp(.95rem,3.6cqw,1.25rem);
  letter-spacing:-.01em;
  background:var(--signal);color:var(--on-signal);
  border:1px solid var(--signal);border-radius:999px;
  padding:.85rem 1.9rem;
  text-decoration:none;
  transition:filter .15s ease,box-shadow .15s ease;
}
.hero-cta:hover{filter:brightness(1.08);box-shadow:0 8px 24px rgb(0 0 0 / .45)}
.hero-cta:active{filter:brightness(.95)}

/* ── Marginalia. Last in the block, and page.css's .hand already owns the
   face, the colour and the tilt - this only sets where it sits. ── */
.hero-hand{
  max-width:28rem;
  margin-top:1.1rem;
}

/* The copy, and the guarantee that the illustration can never cover it.
   The mascot is absolutely positioned at desktop widths and comes after this
   block in the DOM, so with auto z-index it would paint on top of the text
   if the two ever met. Raising this one step - both values are far under the
   ceiling of 100 that test/shell.test.js enforces, and neither creates an
   overlay across the page - puts the text permanently in front. */
.hero-lede{position:relative;z-index:1}

/* ── The mascot ──
   Decorative, so it carries no information and is aria-hidden in the markup.
   Never drawn small: it is a detailed illustration and turns to mush under
   about 100px, so at phone widths it stays large and centred under the copy
   rather than shrinking into the corner. */
.hero-mascot{
  width:clamp(9rem,46cqw,15rem);
  margin:1.5rem auto 0;
}

@media (min-width:56rem){
  /* 20rem, not 22: inside the 64rem grid every rem given to the panel comes
     straight off the headline, and the headline has to stay the largest type
     on the site (the masthead wordmark caps at 67.2px). At 20rem the copy
     column is 592px at 1440, which puts the headline at 71px. The panel is
     measured too - its longest line still sets comfortably at 20rem. */
  .hero-in{grid-template-columns:minmax(0,1fr) minmax(0,20rem)}

  /* Bottom-right of the copy column, tucked beside the two short headline
     lines and the standfirst. 30cqw against the standfirst's 64cqw and the
     hand line's 60cqw means the two can never reach each other, at any
     column width - no text is ever set over the illustration. Text over an
     illustration would also be text on an unmeasured ground, which is the
     other reason it is arithmetic here and not a judgement call. */
  /* The copy is pulled in to 56cqw/54cqw so the illustration can have 40cqw
     and still never touch it: 56 + 40 = 96, four points of clearance at any
     column width. Text over an illustration is also text on an unmeasured
     ground, which is why this is arithmetic and not a judgement call. */
  .hero-stand{max-width:min(32rem,56cqw)}
  .hero-hand{max-width:min(26rem,54cqw)}
  .hero-mascot{
    position:absolute;right:0;z-index:0;
    /* Bigger and lower than the first pass, which left him reading as a small
       icon parked between the text and the panel rather than a character in
       the scene. 40cqw is 237px at 1440 - larger than the 216px he had in the
       wider band - and the negative bottom lets him sit down into the band's
       floor padding instead of hovering above it. The 9rem floor is what
       holds him over the 100px below which the illustration turns to mush;
       the narrowest two-column container puts him at 178px, well clear. */
    bottom:clamp(-1rem,-1.6cqw,-.4rem);
    /* Two constraints, and the second one is why this is a min() and not a
       plain clamp. 40cqw is the size the illustration WANTS. The call to
       action's width is set by its label in rem, not by the column, so at a
       narrow two-column container the column can be wide enough for 40cqw
       and still not have room for the button beside it - the sweep caught
       exactly that at a 900px viewport, 23px of overlap. `100cqw - 19rem`
       reserves the button's footprint first and hands the illustration what
       is genuinely left, and the 9rem floor keeps it clear of the 100px
       below which it turns to mush. */
    width:clamp(9rem,min(40cqw,100cqw - 19rem),15.5rem);
    margin:0;
  }
}

/* ── WHAT'S ABOVE YOU (Reported) ─────────────────────────────────────────
   cards.css owns the container, the heading rule and the LIVE badge. This
   only adds what is specific to the panel. */
.above{align-self:start}
.above .card-body{text-align:center}

/* The badge gets its dot. cards.css's .live-badge rule already colours and
   spaces the word; this puts a lime disc in front of it without touching
   that rule, so there is still exactly one place the badge's own type style
   is defined. A graphic, not text: --signal on --panel measures 10.99, well
   over the 3:1 floor. */
.above.card--live .card-hd .live-badge{
  padding-left:1.15em;
  background:radial-gradient(circle at .4em 50%,
    var(--signal) .29em, transparent .31em);
}

/* Where the reader is. geo.js's own label, verbatim - it says "(ASSUMED)"
   when nobody has told us, and that is the honest reading. */
.above-where{
  display:flex;align-items:center;flex-wrap:wrap;gap:.4rem .55rem;
  text-align:left;
  font-family:var(--f-data);font-size:var(--step--1);letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink);
  margin:0 0 .9rem;
}
.above-pin{width:.95rem;height:.95rem;flex:0 0 auto;color:var(--signal)}
.above-place{min-width:0;overflow-wrap:anywhere}

/* A control, so its boundary is gated at 3:1 (--edge-strong), unlike the
   decorative --edge outline around the card itself. */
/* No margin-left:auto. The card is 22rem at most, so the place name and this
   control do not fit on one line and the control wraps - pushed right it
   wraps to a lonely right-aligned second row, flowing normally it lands
   under the pin where the eye already is. */
.above-change{
  flex:0 0 auto;
  font-family:var(--f-data);font-size:var(--step--1);letter-spacing:.08em;
  text-transform:uppercase;
  background:transparent;color:var(--ink-dim);
  border:1px solid var(--edge-strong);border-radius:999px;
  padding:.3rem .7rem;cursor:pointer;
}
.above-change:hover{color:var(--ink);background:var(--panel-lift)}

/* Device geolocation said no. Printed, and true: nothing changed. */
.above-note{
  text-align:left;font-size:var(--step--1);line-height:1.45;
  color:var(--ink-dim);margin:-.4rem 0 .9rem;
}

.above-art{width:5.5rem;margin:.25rem auto .9rem}

.above-when{
  font-family:var(--f-data);font-size:var(--step--1);letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink-dim);margin:0;
}

/* The number. Reported material, so it is set in the data face like every
   other real figure on the site, not in the display face - the size is what
   makes it the headline of the panel, not the typeface. */
.above-count{
  font-family:var(--f-data);font-weight:500;
  font-size:var(--step-5);line-height:1.05;
  font-variant-numeric:tabular-nums;
  color:var(--signal);
  margin:.1rem 0;
}
.above-what{
  font-family:var(--f-data);font-size:var(--step--1);letter-spacing:.14em;
  line-height:1.5;text-transform:uppercase;color:var(--ink);
  margin:0 0 .35rem;
}
.above-aside{
  font-size:var(--step--1);line-height:1.45;font-style:italic;
  color:var(--ink-dim);margin:0 0 1.1rem;
}

/* The two states with no number in them. Deliberately NOT set at the
   count's size: a big stand-in where a figure belongs reads as a figure. */
.above-wait{
  font-family:var(--f-data);font-size:var(--step--1);letter-spacing:.12em;
  line-height:1.6;text-transform:uppercase;color:var(--ink-dim);
  margin:.6rem 0 1.1rem;
}

.above-go{
  display:block;width:100%;
  font-family:var(--f-data);font-size:var(--step--1);font-weight:500;
  letter-spacing:.12em;text-transform:uppercase;text-align:center;
  background:var(--signal);color:var(--on-signal);
  border:1px solid var(--signal);border-radius:999px;
  padding:.7rem 1rem;
  text-decoration:none;
  transition:filter .15s ease;
}
.above-go:hover{filter:brightness(1.08)}

/* Omitted entirely by front.js when the timestamp cannot be read - an
   unknown age under a LIVE badge would read as a value. */
.above-age{
  font-family:var(--f-data);font-size:var(--step--1);letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-dim);
  border-top:1px solid var(--edge);
  margin:1rem 0 0;padding-top:.6rem;
}

/* ── The front page under the band (Furniture) ───────────────────────────
   The lead and the founding story are both .card now. cards.css's
   `.card + .card{margin-top}` is written for a plain stack, so it has to be
   switched off wherever those cards are laid out by a grid - left on, it
   pushes the second and third items of a row down on their own and the row
   stops being a row.

   ONE column, not two. This grid used to run 20rem / 1fr for the boxed
   scope figure beside the founding story; the Live Sky Tracker superseded
   that figure and brought its own two-thirds/one-third row with it
   (.trackerrow in tracker.css), so every direct child of .front now spans
   the full measure. The grid is kept rather than unwound to a plain stack
   because .cardrow and .remind still declare `grid-column:1/-1` against it
   in frontcards.css, and a single column is exactly what 1/-1 means here. */
.front{margin-top:0}

@media (min-width:56rem){
  .front{
    display:grid;
    grid-template-columns:minmax(0,1fr);
    gap:1.5rem;
    align-items:start;
  }
  .front > .card + .card{margin-top:0}
  #founding{margin:0}
}

/* ── The section teasers (Furniture) ──
   Consolidated here, moved out of sections.css - hero.css is the one sheet
   that loads only on the page with a #teasers element, so a rule for it
   split across two sheets was two places to remember, not two things that
   disagreed. A review also caught that sections.css's own base rule - a 3px
   double border, left over from the newspaper's section break - was
   permanently overridden to zero by the raised-card treatment below it, on
   the only page either sheet could ever reach: dead weight, so it is not
   carried over. Teasers are cards now (`<a class="card">`), so their hover
   state is the same raised treatment cards.css's own .card--lift uses; the
   underline a plain newspaper link used to get on hover was the other half
   of the split and does not survive the move either. */
.teasers{
  display:grid;gap:1.5rem;margin:2.5rem 0 0;
}
.teasers a{display:block;color:inherit;text-decoration:none}
.teasers a .kicker{margin-bottom:.2rem}
.teasers a span:last-child{
  display:block;font-family:var(--f-body);font-size:var(--step-1);
  line-height:1.4;color:var(--ink);
}
.teasers .card + .card{margin-top:0}
.teasers a.card{transition:background .15s ease,border-color .15s ease}
.teasers a.card:hover{background:var(--panel-lift);border-color:var(--edge-strong)}

@media (min-width:700px){
  .teasers{grid-template-columns:repeat(3,1fr);gap:2rem}
}
