UI/IntroCardHud.razor

A UI Razor component (IntroCardHud.razor) for the game's HUD that renders an opening card in the lower-left showing the map name and place lines with a typing effect and fade opacity. It conditionally shows when IntroCard.On is true and the game is in Survival mode and not creative, computes CSS opacity with invariant culture, and builds a hash based on typed progress and opacity to control rebuilds.

File Access
@using Sandbox;
@using Sandbox.UI;
@using System.Linq;
@using NZombies;
@inherits PanelComponent

@*
    THE OPENING CARD — the map's name and a line of place, typed out in the lower left as a game fades up
    (`IntroCard`, 2026-09-28). In the map's face on basalt (`HudTheme`: Cinzel, ember-lit ivory), the HUD's own anywhere else.

    ⚠️ ITS OWN PanelComponent, mounted as the round carving is (`SurvivalHud.OnUpdate`), so no scene edit.
    ⚠️ ABOVE THE LOWER-LEFT HUD, not over it: points, health and the round sit at the bottom left (`.left`, 60 px up), and the
    room's name has the top left.
*@

<root class="intro-hud @HudTheme.Class">
    @if ( Showing )
    {
        <div class="card" style="opacity: @(Css( IntroCard.Opacity ))">
            @for ( var i = 0; i < IntroCard.Lines.Count; i++ )
            {
                var line = IntroCard.Lines[i];
                var typed = IntroCard.Typed( i );
                <div class="line @(LineClass( i ))">
                    <label class="text">@line.Substring( 0, typed )</label>
                    @if ( IntroCard.TypingLine == i )
                    {
                        <label class="cursor">_</label>
                    }
                </div>
            }
        </div>
    }
</root>

@code
{
    bool Showing => IntroCard.On && NZGame.Mode == GameMode.Survival && !NZGame.IsCreative;

    /// <summary>The first line is the name; the one under it is the place.</summary>
    static string LineClass( int i ) => i == 0 ? "name" : "place";

    /// <summary>⚠️ A POINT FOR THE DECIMAL, whatever the machine's language — this goes into a style.</summary>
    static string Css( float v ) => v.ToString( "0.###", System.Globalization.CultureInfo.InvariantCulture );

    /// <summary>⚠️ REBUILDS AS EACH LETTER LANDS AND AS IT FADES, then never again until the next card.</summary>
    protected override int BuildHash()
    {
        var typed = 0;
        for ( var i = 0; i < IntroCard.Lines.Count; i++ ) typed += IntroCard.Typed( i );

        return System.HashCode.Combine( Showing, typed, IntroCard.TypingLine, (int)(IntroCard.Opacity * 30f), HudTheme.Class );
    }
}