*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

:root {
    /* The three colours the brand is drawn in, and the only place this page
       writes them down. They are paired with `freebody_assets::palette`, which
       the marks above are drawn from, by a test -- the page and the application
       are meant to be the same three colours, and nothing else compares one
       hexadecimal literal to another.

       Also as components, because a colour written as `#RRGGBB` cannot be given
       an alpha at the point of use, and the glow behind the mark is one of these
       three at a strength. */
    --freebody-ink: #16243F;
    --freebody-ink-rgb: 22 36 63;
    --freebody-ivory: #FBF7F0;
    --freebody-ivory-rgb: 251 247 240;
    --freebody-sky: #C9D9F2;
    --freebody-sky-rgb: 201 217 242;

    /* FreeBody is set on the ink wherever it appears. Declaring the scheme is
       what keeps the controls the platform paints for us -- scrollbars above
       all -- from arriving light over a dark page. */
    color-scheme: dark;
}

html {
    background-color: var(--freebody-ink);
}

body {
    background-color: var(--freebody-ink);
    color: var(--freebody-ivory);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

::selection {
    background-color: rgb(var(--freebody-sky-rgb) / 0.3);
}

img {
    display: block;
    max-width: 100%;
    height: auto;
}

/* The page is one column, centred on both axes, on a screen of any size. The
   viewport unit is the small one so a phone's collapsing toolbar cannot leave
   the column taller than the screen it is being centred in. */
.freebody-page {
    position: relative;
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2.5rem 1.5rem;
    overflow: hidden;
}

/* The light the mark sits in. It is the figure's own blue at a strength rather
   than a fourth colour, and it is drawn behind everything with no pointer
   interest of its own.

   The stops trace an ease-out rather than a straight ramp, the same shape the
   application fades everything along. A straight ramp stops changing all at
   once where it ends, and the eye reads that as a ring drawn around the mark --
   the fade is smooth everywhere except at the one place it is meant to
   disappear. */
.freebody-glow {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    /* The ink, less exactly what the grain below is about to add to it.
       Grain laid on by transparency can only lighten -- there is no way to
       composite a colour that darkens some pixels and lightens others -- so
       the layer pulls every channel a sixteenth of the way towards mid grey.
       Starting that far short of the ink lands the average back on it, and
       leaves the grain swinging either side, which is what a dither is.

       It is a colour rather than black at an alpha because the three channels
       are not lifted equally: the shortfall to mid grey is largest where the
       channel is darkest, so a black wash -- which scales all three by the same
       fraction -- leaves the red over-lifted and the ink drifting warm and grey.
       Derived from the palette and the grain's strength by a test, so it is
       not three literals to be re-derived by hand. */
    background-color: #0F1E3B;
    background-image: radial-gradient(circle at 50% 42%,
            rgb(var(--freebody-sky-rgb) / 0.15) 0%,
            rgb(var(--freebody-sky-rgb) / 0.111) 19%,
            rgb(var(--freebody-sky-rgb) / 0.081) 34%,
            rgb(var(--freebody-sky-rgb) / 0.057) 47%,
            rgb(var(--freebody-sky-rgb) / 0.042) 56.5%,
            rgb(var(--freebody-sky-rgb) / 0.029) 65%,
            rgb(var(--freebody-sky-rgb) / 0.019) 73%,
            rgb(var(--freebody-sky-rgb) / 0.011) 80.2%,
            rgb(var(--freebody-sky-rgb) / 0.006) 86.1%,
            rgb(var(--freebody-sky-rgb) / 0.003) 91%,
            rgb(var(--freebody-sky-rgb) / 0.001) 95.2%,
            rgb(var(--freebody-ink-rgb) / 0) 100%);
}

/* The dither that makes the fade above a fade rather than a set of rings.
   A screen holds 256 levels per channel, and this gradient crosses about
   twenty of them over most of the viewport -- so each level is a band tens of
   pixels wide, with a hard edge where it steps to the next. The eye finds
   those edges immediately and reads them as concentric circles.

   Grain that reaches a whole level, laid over the whole field, moves each pixel
   across the boundary at random and leaves the step nowhere to be seen. The
   amount matters more than it looks like it should: grain of half a level
   speckles the bands without ever crossing one, so the field reads as banded
   AND noisy, which is worse than either. It has to be able to cross.

   Which is why the noise is one octave. A stack of them is smoother and prettier
   and useless here: octaves sum towards the middle, so most pixels come out near
   flat grey and are nudged by a fraction of a level, and the contour survives
   underneath the speckle. One octave spends its range on the range.

   It is laid on plainly, at a strength the glow above has already been backed
   off by. A blend mode would be the tidier way to say "modulate this rather
   than cover it" -- and it is a trap. Software rendering ignores `mix-blend-mode`
   silently, so it measures as one thing here and paints as another on a display
   with a GPU, which is a defect that cannot be caught by looking at a rendering.
   Plain compositing paints the same everywhere.

   Two things still have to be true of the noise. It has to be flat grey, or it
   tints; and it has to be fully opaque, or the transparent half of it lets the
   field through while the opaque half lightens it, and the strength it is
   costed at is not the strength it applies. So the turbulence is desaturated
   and its own noisy alpha is flattened to one. It is also generated in sRGB
   rather than the linear space filters default to: mid grey in linear light
   arrives as three quarters grey on screen, and the field would come out lifted
   by a third of the amount it was backed off by. */
.freebody-glow::after {
    content: '';
    position: absolute;
    inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='1' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23g)'/%3E%3C/svg%3E");
    opacity: 0.06;
    pointer-events: none;
}

.freebody-column {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

/* The mark and the wordmark scale together with the viewport, so the pair keeps
   its proportions from a phone to a desktop rather than one of them running
   away from the other. */
.freebody-mark {
    width: clamp(132px, 26vw, 268px);
    height: auto;
}

.freebody-wordmark {
    width: clamp(232px, 46vw, 470px);
    height: auto;
    margin-top: 1.5rem;
}

/* Set in the face the wordmark's own lettering was drawn from, so the line
   below the mark reads as the same hand that wrote it. Pacifico's ascenders and
   descenders are long, so the line is given room rather than the face's default
   leading. */
.freebody-tagline {
    font-family: 'Pacifico', cursive;
    font-weight: 400;
    color: var(--freebody-sky);
    font-size: clamp(1.125rem, 4.6vw, 2.125rem);
    line-height: 1.6;
    margin-top: 2rem;
}
