//! The Stripe payout-summary card, described. //! //! S4: no `hx-` attributes of its own, no id or class that any file in //! `static/` or `frontend/src` reaches for, and no form. //! //! It replaces `dashboard_tab_payout_summary`, which is deleted with its //! `PayoutSummaryPartialTemplate` and `templates/partials/tabs/payout_summary.html`. //! There is no switch and no fallback: since `64b33b26` a described screen owns //! its address outright, so the Askama half goes in the same change. //! //! # It is a card the Payments tab fetches, not a tab of its own //! //! `templates/partials/tabs/user_payments.html:74` leaves an empty //! `#payout-summary-section` and fills it on `revealed`, because the Stripe //! balance is a network round trip and the tab should not wait for it. That //! split is preserved exactly: this screen answers the same //! address on the same trigger and replaces the same region. The lazy fetch is //! the point of the split and not an artefact of Askama. //! //! That also makes it the one conversion in the batch where [`super::ssh_keys`]'s //! "a list it can read now is a list the reader should not wait for twice" //! does NOT apply. Reading the balance inline would put a Stripe round trip in //! front of the Payments tab, which is the cost the split was made to avoid. //! //! # The three things the description says that the template did not //! //! 1. **The failure branch is a readiness, not a second card.** The template's //! `{% else %}` hand-writes a near-copy of the whole card carrying "Unable //! to load balance". That is [`layout::Readiness::Failed`], which every //! renderer already draws, so it is [`Node::failed`] here and the copy goes. //! 2. **The two balances are a strip.** `.payout-stats-grid` holding two //! `.amount-big` divs with `.text-xs` captions is [`Node::stats`] over two //! [`Figure`]s. The grid was the markup spelling of "these are tiles". //! 3. **"Payouts are not yet enabled" is a banner.** The template gives it a //! bespoke `.payouts-disabled-notice` class; it is a persistent message //! dismissed by fixing its cause, which is [`layout::Notice::Banner`] at //! [`layout::Tone::Warning`]. //! //! # Two parity differences, both deliberate //! //! The parity test names each rather than blanket-ignoring them. //! //! - **`rel`.** The template writes `rel="noopener"`; quasi-webview emits //! `rel="noopener noreferrer"` for every external destination. The stricter //! one is right and it is not this screen's call to make either way. //! - **The Stripe link is an anchor, not a button inside an anchor.** The //! template nests `