/* insider
   Split from the single v22 stylesheet. Everything here is scoped to
   .card.insider and this form's own class prefix (rule 14: a change made for one
   card form is scoped to that form, by class). */
.card.open .insider-stat b{font-size:var(--fs-stat-open)}
/* The horizontal inset every other form's root carries and this one did not.
   `.closeviz`, `.ctr`, `.pl-opts`, the price/pricegap readouts, `.mv-head` and
   the shell's own `.rdout` all set `padding:0 15px`; `.insider` set none, so its
   content ran flush to the panel's rounded edge -- and the panel is
   `overflow:hidden`, so this was not merely tight. Measured on the frame before
   this rule: the right-hand values were being CUT, not crowded. `AS OF AUG 10,
   2026`, `$48.90` and `$44.76 - AUG 31, 2026` all ran into the clip, and the
   superseded note's second line lost its last word. The dividers inset with the
   content, which is what `.closeviz` already does. */
/* `.card .insider`, not `.insider`: the card root carries the form's class
   too (`.card.solo.insider`), so a bare `.insider` rule lands on the card as
   well as on the viz box inside it. With `padding:0 15px` that shrank the
   card's content box -- the size container `.cardface` measures 100cqw
   against -- to 363px, and the face drew at 363/393 = 0.92 with a black
   band under the action row. Found 2026-09-03 on the rebuilt Nadella card;
   every other form's viz class is not also the card's class. */
.card .insider{width:100%;flex:1;min-height:0;display:flex;flex-direction:column;padding:0 15px}
/* `.insider-stat` now wraps the hero figure and its price qualifier. The class
   is kept rather than replaced because `BEAT_SEL` in js/motion.js reads
   `.insider-stat b` to shrink a figure too wide for its column, and motion.js
   is not this form's file -- see the note in js/forms/insider.js. It no longer
   carries a rule: the head above it is a label, not a section, and a divider
   under the hero would make three horizontal lines in a 569px panel. */
.insider-stat{display:flex;flex-direction:column}
.insider-stat b{font-size:var(--beat-figure);line-height:.9;color:var(--stance);font-weight:700}

/* ------------------------------------------------------------------ *
   The Insider, phase 2 (docs/insider.md). `.insider` and `.insider-stat`
   above are kept -- they were this form's own, unshared with any other
   form, and `.insider-stat b` is already in BEAT_SEL for the shrink-to-fit
   pass. `.insider-plan`/`.insider-rail`/`.insider-dots`/`.insider-dot`/
   `.railends`/`.insider-flat` above are no longer drawn by anything -- the
   new payload shape does not carry `rail` -- and are left declared rather
   than deleted, on the same reasoning that keeps them out of `visualInsider`'s
   reach: nothing else in this sheet names them, and removing declared CSS
   nobody calls is not this form's job to do while reviewing this one.

   Every class below is new and prefixed `ins-`, grepped empty across this
   file before it was written (rule 17), so nothing here can be the second
   of two declarations of the same name. Nothing below touches
   `.insider-sale`/`.insider-sales`/`.legsnote`/`.beat-two`/`.beat-label`/
   `.beat-note`/`.gaugepct`/`.posbar` -- The Gauge still draws every one of
   them, unmoved (rule 14). */
/* `.ins-mid`, `.ins-position`, `.ins-pos-head`, `.ins-pos-figs`, `.ins-note`,
   `.ins-plan` and `.ins-remaining*` were declared here and are DELETED rather
   than left, which is the opposite of the call made above for the phase-1
   leftovers. The difference is that those were orphaned by an earlier change
   and merely unused; these were orphaned by THIS one, and their comments argue
   in detail for a layout the panel no longer has -- `.ins-mid`'s explained why
   the slack should be pooled and centred, which is the exact mechanism the
   block at the foot of this file replaces. Dead CSS is cheap; a stylesheet
   that reasons for two contradictory layouts is how the wrong one gets
   restored by someone reading the comments. The rail classes below stay: they
   are still drawn, for `per_leg`. */
.ins-rail{width:100%}
/* The rail follows the hero directly on a `per_leg` card and nothing else
   separates them. Caught on the fixture's frame, not in the markup: the track
   sat hard against the descenders of "at a $121.33 average price" and the two
   read as one block. Only applied where the rail actually follows the hero, so
   a card without one is unaffected. */
.ins-hero + .ins-rail{margin-top:30px}
.ins-track{position:relative;height:6px;border-radius:3px;background:var(--line)}
.ins-track i{position:absolute;inset:0;border-radius:3px;background:var(--stance-wash);
  transform:scaleX(0);transform-origin:left;transition:transform .8s cubic-bezier(.16,1,.3,1) .18s}
.card.in .ins-track i{transform:scaleX(1)}
.ins-mark{position:absolute;top:50%;width:11px;height:11px;border-radius:50%;
  background:var(--ground);border:2px solid var(--stance);
  transform:translate(-50%,-50%) scale(.35);opacity:0;
  transition:opacity .26s ease-out var(--d),transform .38s cubic-bezier(.34,1.56,.64,1) var(--d)}
.card.in .ins-mark{opacity:1;transform:translate(-50%,-50%) scale(1)}
/* The average mark reads as a single measurement, not a fill: smaller than
   a per-leg dot, filled solid rather than hollow, no per-mark stagger. */
.ins-track-band b{position:absolute;top:50%;width:9px;height:9px;border-radius:50%;
  background:var(--stance);transform:translate(-50%,-50%);box-shadow:0 0 0 4px var(--ground);
  opacity:0;transition:opacity .3s ease-out .5s}
.card.in .ins-track-band b{opacity:1}
.ins-rail-ends{display:flex;justify-content:space-between;align-items:baseline;margin-top:9px;
  font-size:var(--fs-9-5);letter-spacing:var(--ls-13);text-transform:uppercase;color:var(--dim)}
.ins-rail-ends em{font-style:normal;opacity:.8}
.ins-rail-flat{display:flex;align-items:baseline;gap:9px}
.ins-flat-price{font-size:18px;font-weight:700;color:var(--ink)}
.ins-rail-flat span{font-size:var(--fs-9-5);letter-spacing:var(--ls-13);text-transform:uppercase;color:var(--dim)}


/* ------------------------------------------------------------------ *
   The deck, and why this form stops drawing it.

   This card was shipped baselined -- knowingly overflowing -- since session 18:
   its action row ended at y=1013.77, 181.4px past the pinned bottom at 832.36.
   The deck was the whole of it, and the reason is not that this deck is long.
   It is that the closed media_first column has no line item for a deck at all.

   Measured in the page on 2026-09-01-feed-4, this card, by emptying `.hook .sub`
   and re-reading the action row:

     deck emptied (91 -> 0 chars)   action row 832.36   over by   0.00
     one beat     (35 chars, 2 ln)  action row 905.53   over by  73.17
     two beats    (65 chars, 4 ln)  action row 977.69   over by 145.33
     as shipped   (91 chars, 5 ln)  action row 1013.77  over by 181.41

   An empty deck lands EXACTLY on the pinned bottom. The column is full without
   one. The 17px `.actions{margin-top:auto}` reserves is the only give in it,
   and `.card.solo .hook .sub` carries an 18px margin-top before it sets a single
   line -- so a deck of zero height still overflows, and the shortest one-line
   deck the fit floor can produce (0.68 x 32.23 = 21.9px, a 24.5px line) costs
   18 + 24.5 - 17 = 25.5px. There is no length, no `--band` and no font size that
   fits. That is why a length bound at the builder is not the fix here and a band
   is not either: both assume a slot with some height, and this slot has none.

   `.vizsec` cannot absorb it. It is `flex:none;height:var(--panelh)` on closed
   solo cards, deliberately (see shell.css: fixing the panel is what glues the
   claim to its credit line). Confirmed rather than assumed -- forcing
   `.ins-mid{flex:none}`, `.insider{min-height:0}` and `.insider{flex:1}` in the
   page, singly and together, left the panel at 569px and the overflow at
   181.41px in every combination.

   So the fix is the one The Move and The Habit already made, for the same
   reason and in the same words: the deck's figures are already inside the
   panel, so the form no longer draws it. Here that is literally every figure --
   $2,502,684 is the hero count-up, $48.89 sits between the rail's disclosed
   endpoints, and `1,378,226 shares, 3.86% larger` is the position row verbatim
   and better, because the panel dates it and carries the superseded caveat the
   deck cannot. The deck was the third printing of one set of numbers.

   The payload keeps `sub`, exactly as `.card.replay` and `.card.habit` keep
   theirs: v21 draws the stored aptv card and still wants a sentence there, and
   the card contract refuses an edit that CREATES a path ("adding a `sub` where
   the builder wrote none is a new claim, not a rewording"), so deleting the
   field would close that door permanently.

   This is a third form reaching the same conclusion by overflowing first, which
   says the finding is the column's and not this form's. It now lives there:
   `.card.insider .hook .sub{display:none}` moved to shell.css, consolidated
   with The Move's and The Habit's copies of the same rule -- three local
   fixes for one structural omission, stated once. Nothing here changed what
   this card renders; see shell.css for the current declaration and for what
   showing this deck at one line (37.09px over) and at its real five-line
   length (181.41px over, confirmed unchanged from the numbers above) would
   cost. */

/* ------------------------------------------------------------------ *
   The panel, placed rather than pooled.

   WHAT WAS WRONG. `.ins-mid{flex:1;justify-content:center}` pooled every unused
   pixel in the panel into the hero group and split it symmetrically. Measured
   on 2026-09-01-feed-4-007 before this rule: `.ins-mid` was 366.56px tall
   around 138.38px of content, so 228.18px of nothing, as 114.09px above the
   rail and 114.09px below the position block. Two holes rather than one, and
   neither chosen -- `justify-content:center` picked them, and it would pick
   different ones on a card with a plan line. (The brief called this ~500px in
   two ~250px gaps; measured it is 228.18 in two of 114.09. The mechanism named
   was exactly right, the magnitude was not.)

   WHAT REPLACES IT. Three blocks, each with a stated position, and the slack
   lands in ONE place because only one place is left free:

     .ins-head      top of the panel. Label over date.
     .ins-hero      a fixed 74px below the head. The one primary fact.
     .ins-holding   margin-top:auto, so it takes the bottom -- less a chosen
                    44px, so the block stops above the panel's edge instead of
                    sitting on it.

   `margin-top:auto` on the last block is what takes the slack out of the hero's
   hands: it collects in the single gap between the hero and the divider, which
   is the breathing room the composition is built around rather than an
   accident of how many optional rows this filing happened to have. It is the
   same device `.actions{margin-top:auto}` uses in the shell's own column.

   Targets, in card coordinates (the panel is 569px at y=16-585, and
   `.card.solo .vizsec` pads it 16px top / 12px bottom, so the content box is
   y=32 to y=573):

     head       32 - 71        hero      145 - 252
     free       252 - 405      divider   ~405
     holding    426 - 529      padding   529 - 573

   These are a target and not a contract -- measure the frame, not this comment.

   SECOND PASS (docs/insider-animation.md, "Second pass"): the block above
   described a panel that pooled the eyebrow, the figure and two qualifier
   lines at the top. Reviewer, 2026-09-03: *"needs to compare to the other
   bottom third stuff. I don't think we need as much info at the very top."*
   The eyebrow is now ONE line, not two (`.ins-head` below), and the hero is
   the figure alone -- no `SALE VALUE` label, no average-price note, no share
   count. All three still print, once, on the sold row inside `.ins-zoom`
   further down this file, which is also where "the other bottom third
   stuff" (The Close's `BEST`/`WORST` rows, `forms/close.css`'s `.cl-end`) is
   answered. What that frees at the top goes to the stage's own height --
   see the zoom block below for the measurement. */
.ins-head{display:flex;flex-direction:row;align-items:baseline;gap:0}
.ins-kind{font-size:var(--fs-10);letter-spacing:var(--ls-15);text-transform:uppercase;color:var(--dim)}
/* The middot is CSS content, not a text node -- `review/formcheck.mjs`
   reads `.ins-when`'s `textContent`, which does not include `::before`
   generated content, so the join here cannot be mistaken for a second date
   by anything that asserts the date string. */
.ins-when{font-size:var(--fs-10);letter-spacing:var(--ls-15);text-transform:uppercase;color:var(--dim);opacity:.75}
.ins-when::before{content:"\00a0\00b7\00a0"}
/* The hero is one child now (just the figure), so the flex gap the
   multi-line version needed is gone -- `margin-top` alone places it under
   the eyebrow. 10px is the smallest gap already in use on this face
   (`.ins-zoom-row-foot`'s own gap below) that still reads as a break between
   two different kinds of line rather than one crowded block. */
.ins-hero{margin-top:10px}
/* A panel that draws the fills-rail has one more block below the hero
   (`.ins-hero + .ins-rail`'s own 30px) -- unaffected by this pass, kept for
   the one stored card that exercises it (2026-09-01-insider-fixture). */
.ins-hero:has(+ .ins-rail){margin-top:8px}
/* `.ins-hero-label` is deleted (nothing draws it any more; its equivalent
   is `.ins-zoom-row-tag` below). `.ins-hero-note`/`.ins-txn` stay, narrowed
   to a fallback: `js/forms/insider.js`'s header comment on `heroFallback`
   explains the one case that still needs them -- a modern payload whose
   `remaining.value` is null, where the zoom's rows never draw and these two
   are the only place the price qualifier and the share count can still
   appear. No stored card takes this path today. */
.ins-hero-note{margin-top:8px;font-size:var(--fs-14);line-height:1.3;color:var(--dim)}
.ins-txn{margin-top:9px;font-size:var(--fs-13-5);line-height:1.35;color:var(--ink);opacity:.74}
/* The grounded comparison, at the foot. One rule in the panel, and it is here:
   it separates the magnitude from what the magnitude was against, which is the
   only boundary on this face that carries meaning. */
/* `padding-top` is how the divider is positioned, and it is worth saying so
   because it reads backwards: the block is anchored from the BOTTOM
   (margin-top:auto, then a chosen 44px off the panel's edge), so its content
   sits where it sits and growing the padding moves the RULE up, not the text
   down. At 21px the divider measured y=441 against a target of ~405 and the
   free space above it was 219px rather than ~152 -- one hole big enough to
   read as the hero having been stranded at the top. 52px puts the rule at
   y=411 and gives the label the blank line above it the composition wants. */
.ins-holding{margin-top:auto;margin-bottom:44px;padding-top:52px;
  border-top:1px solid var(--line);display:flex;flex-direction:column;gap:7px}
/* Tightened where the zoom (below) is what fills the panel's middle third
   now -- the 52px/44px above were tuned for a mostly-empty panel (see the
   comment on them) and that reasoning does not carry once a stage full of
   bar sits above this block: the divider no longer needs to manufacture its
   own breathing room, the stage already gave the eye somewhere to land.
   Adjacent-sibling, not `:has()`, because this needs to select on what
   PRECEDES `.ins-holding`, and a pre-v19 card (whose hero is followed by
   nothing this file draws a `.ins-zoom` for) keeps the base rule above. */
.ins-zoom + .ins-holding{padding-top:18px;margin-bottom:14px;gap:6px}
.ins-holding-label{font-size:var(--fs-10);letter-spacing:var(--ls-14);text-transform:uppercase;color:var(--dim)}
.ins-holding-figs{display:flex;align-items:baseline;justify-content:space-between;gap:9px}
.ins-holding-figs b{font-size:var(--fs-22);font-weight:700;color:var(--ink);line-height:1}
.card.open .ins-holding-figs b{font-size:var(--fs-28)}
/* The direction reads in the stance colour, which is the only colour on this
   card that means anything. Brand colour is identity and never direction. */
.ins-holding-figs i{font-style:normal;font-size:var(--fs-13);font-weight:700;white-space:nowrap}
.ins-holding-figs i.up{color:var(--up)}
.ins-holding-figs i.down{color:var(--down)}
/* The two quiet lines under the position figure, one weight and one colour so
   they read as a pair of footnotes to it rather than as two more figures.
   Declared together rather than as a second block: adding a rule can retire a
   guard as surely as deleting one, and this file has already paid for a
   `min-height` block sliding between two declarations that had to stay
   adjacent.

   `-prev` is what makes the percentage legible without a paragraph: 3.86% of
   WHAT. It carried the transaction date until session 22 -- the comment here
   used to explain why -- and the date came off because the eyebrow two inches
   above already prints it, and a date beside a superseded figure reads as an
   older, different one.

   `-worth` is the only line on the face in the position's own currency. Every
   other figure in this block is a share count. */
.ins-holding-prev,.ins-holding-worth{font-size:var(--fs-11-5);line-height:1.35;color:var(--dim)}

/* ------------------------------------------------------------------ *
   The zoom, second pass (docs/insider-animation.md, "Second pass"). Two
   bars, one scale that changes: the sale grows to the WHOLE stage -- full
   width as well as full height, not a square sharing a flex column with an
   invisible sibling -- holds long enough to be read, then the one axis
   rescale brings the stake up beside it AT THE SAME WIDTH, so height is the
   only difference left for the eye. ~4.8s, judged from film (AGENTS.md rule
   1) -- the still of this design still shows two bars at one scale, but the
   card is the moment the red one was the whole chart.

   Reviewer, 2026-09-03, on the first build: *"the zoom needs to be better.
   Right now it just looks like we are making the sold part smaller than the
   other graph that appears. We need a better comparison of the two
   differences."* Measured against that build: its stage was 164px tall and
   `.ins-bar{flex:1}` split its WIDTH between the two bars from the first
   frame, sale included -- so even at "full height" the sale bar was a
   square in the left half, and the rescale only ever changed a height
   nothing had established as "the whole chart" to begin with. `js/forms/
   insider.js`'s `initInsiderZoom` now sets `left`/`width`/`height` on each
   bar directly rather than leaving width to flexbox: beat 1 is a single bar
   at the stage's full width, beat 3 (the rescale) shrinks that width to half
   the stage -- with a fixed gutter -- while the stake bar grows into the
   other half from zero, both changes landing together in one CSS
   transition. Nothing here owns the clock; this file only says what each
   state looks like.

   Sized up again (second pass), on top of lane-insider-zoom-2's own pass:
   the top of the panel dropped `SALE VALUE`, the average-price note and the
   share line (see `.ins-head`/`.ins-hero` above) -- reviewer: *"I don't
   think we need as much info at the very top."* Measured, 393x852,
   2026-09-03-insider-msft, before this pass: the hero's own box was 122.84px
   tall (a label, the figure, a note, a txn line); after, it is the figure
   alone. That frees the stage to grow from 164px toward the card's actual
   available height rather than a number chosen in the abstract -- the exact
   figure is set below, verified by rendering rather than derived a second
   way (`.ins-holding`'s own `margin-top:auto` is the tell: it still lands
   within a few px of the panel's own foot after this change, the same
   zero-slack property the panel had before).

   `ins-zoom` and every child below are grepped-empty names (rule 17), same
   discipline the rest of this file uses instead of a literal `.card.insider`
   prefix on every rule -- the blast radius is the same grep either way. */
.ins-zoom{margin-top:14px;display:flex;flex-direction:column}
/* The stage. Absolutely positioned bars, not a flex row -- flex gives every
   child a share of the row's width whether or not it has any height, which
   is exactly the "square in a shared column" defect above. `left` is set
   once per bar and never transitions (0 for the sale, the far side of the
   gutter for the stake); only `width` and `height` ever move, which is what
   lets ONE `transition` declaration carry both the grow beat (height only)
   and the rescale beat (width and height together) without a third property
   ever needing to animate. `js/forms/insider.js` reads this box's own
   `offsetWidth`/`offsetHeight` back (layout, not `getBoundingClientRect` --
   see that file's comment on why it has to be the unscaled ones) rather than
   assuming a number, so this is the one and only place the stage's size is
   decided. 220px: the freed space from the top (above) applied to this box
   and rendered, not a round number -- see the file header for the
   before/after measurement. */
.ins-zoom-stage{position:relative;margin-top:6px;height:172px}
/* The one card shape that draws the fills-rail ABOVE the zoom
   (2026-09-01-insider-fixture -- `p.method === "per_leg"`, both blocks true
   at once, the stacking `js/forms/insider.js`'s own header comment already
   flagged as unverified before this pass) has less budget left: the rail
   costs this composition ~58px (its own height plus the 30px
   `.ins-hero + .ins-rail` margin-top) that a zoom-only card does not spend.
   Scaled down from the base stage by the same ratio the first pass used
   (110/164), rendered and re-measured rather than reasoned to a round
   number, so `.ins-holding` stays inside the panel's own foot the same way
   the zoom-only case does. */
.ins-rail + .ins-zoom .ins-zoom-stage{height:116px}
.ins-bar{position:absolute;bottom:0;border-radius:3px 3px 0 0;
  transition:width 1.2s cubic-bezier(.16,1,.3,1),height 1.2s cubic-bezier(.16,1,.3,1)}
.ins-bar-sale{background:var(--stance)}
.ins-bar-stake{background:var(--muted)}

/* The two rows, the sibling shape (forms/close.css's `.cl-end`, `BEST`/
   `WORST`): a tinted block, a tag, a name, a number. Reviewer: *"needs to
   compare to the other bottom third stuff"* -- The Close spends its bottom
   third on exactly this, one fact per row, label / name / number, colour
   carrying direction. The Insider needs one more line than the Close does
   (a qualifier and a stake change, or a close date), so the shape gains a
   third row -- `.ins-zoom-row-foot` -- that Close's own `.cl-end` has no
   equivalent of. */
.ins-zoom-rows{margin-top:10px;display:flex;flex-direction:column;gap:8px}
.ins-zoom-row{display:grid;grid-template-columns:1fr auto;align-items:baseline;
  gap:4px 12px;padding:10px 14px;border-radius:10px;background:#0E0F11;
  opacity:0;transition:opacity .5s ease-out}
.ins-zoom-row-sale{background:var(--stance-wash)}
.ins-zoom-row-stake{background:rgba(154,157,165,.08)}
.ins-zoom-row-tag{grid-column:1/-1;font-size:var(--fs-10);font-weight:700;
  letter-spacing:var(--ls-15);text-transform:uppercase;color:var(--dim)}
.ins-zoom-row-sale .ins-zoom-row-tag{color:var(--stance)}
/* Name/number, the Close's own pair (`.cl-sector`/`.cl-move`): the share
   count on the left, the dollar figure on the right, big enough to read from
   a hand's length -- `--fs-companion` is the scale The Gauge already uses
   for its own second-tier figure (shell.css), one step under the hero's
   `--beat-figure`. The dollar figure carries the direction colour on the
   sale row (the only colour on this face that means anything); the stake
   row's is --ink, matching the grey bar it describes. */
.ins-zoom-row-shares{min-width:0;font-size:var(--fs-13-5);color:var(--ink);opacity:.74;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ins-zoom-row-value{font-size:var(--fs-companion);font-weight:700;line-height:1;
  font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--ink)}
.ins-zoom-row-sale .ins-zoom-row-value{color:var(--stance)}
.ins-zoom-row-foot{grid-column:1/-1;display:flex;justify-content:space-between;
  align-items:baseline;gap:10px;margin-top:2px}
.ins-zoom-row-note{min-width:0;font-size:var(--fs-11-5);color:var(--dim);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ins-zoom-row-pct{font-size:var(--fs-11-5);font-weight:700;white-space:nowrap}
.ins-zoom-row-pct.up{color:var(--up)}
.ins-zoom-row-pct.down{color:var(--down)}

/* The four beats, as classes on `.ins-zoom` -- insider.js's own driver adds
   them at the times its header comment gives (0, ~2.1s, ~2.6s, ~4.3s).
   Nothing here owns the clock; this only says what each beat reveals. Beat 1
   (the bar growing to the whole stage) needs no rule here -- the bars paint
   their own geometry inline, in js. p2 reveals the sold row (after the bar
   it describes, holding first); p4 reveals the still-held row (after the
   rescale has settled). Each row is ONE reveal, the reviewer's own bottom-
   third rule applied literally: its tag, shares, value and note fade in
   together as a single element, not as several landing in the same beat. */
.ins-zoom.p2 .ins-zoom-row-sale{opacity:1}
.ins-zoom.p4 .ins-zoom-row-stake{opacity:1}

/* Reduced motion draws the end state at once: two bars at their true
   heights, same width, both rows visible -- "the final still must make the
   comparison without the film" (docs/insider-animation.md). insider.js sets
   every class and every bar's geometry in the same tick rather than
   staggering them, so the only thing left for CSS to do is stop the
   transitions that would otherwise still fire between that one paint and the
   next frame. */
@media (prefers-reduced-motion:reduce){
  .ins-bar,.ins-zoom-row{transition:none}
}
