/* wwwroot/css/lattice-home.css
   ==========================================================================
   The lattice homepage.

   Dark by necessity rather than taste: the walker field works by stamping at
   five per cent opacity and letting density accumulate. On a light ground
   those marks read as smudges. The effect only exists in the dark.

   The field carries no saturated colour so the blocks can. Structure is blue,
   notional amber, income green — and they are the only saturated things on the
   page, which is what makes them read as significant rather than decorative.
   ========================================================================== */

.lat-stage {
    --lat-void: #070E1A;
    --lat-ink: #E7EEF8;
    --lat-mute: #8A9BB4;
    --lat-faint: #5E708A;
    --lat-line: rgba(255, 255, 255, 0.07);
    --lat-line-strong: rgba(255, 255, 255, 0.13);
    --lat-accent: #4FA8FF;
    --lat-amber: #E8B44A;
    --lat-green: #4ADE80;

    /* A variable because the stamp animation has to return to it. Two literals
       would drift the moment one theme's value changed. */
    --lat-block-bg: rgba(10, 20, 36, 0.72);
    --lat-block-bg-hover: rgba(12, 24, 44, 0.86);

    position: relative;
    isolation: isolate;

    /* The lattice is now the whole page. .im-main is flex: 1 0 auto inside a 100vh
       column, so growing into it fills the space between header and footer exactly —
       with no viewport arithmetic to keep in step when either changes. */
    flex: 1;
    display: flex;
    flex-direction: column;

    background: var(--lat-void);
    color: var(--lat-ink);
    overflow: hidden;
}

.im-main:has(.lat-stage) {
    display: flex;
    flex-direction: column;
}

/* The whole column is centred as a group, so the ticker sits directly under the lattice
   rather than being pushed to the foot of the stage with a gap between them. The two read
   as one object — filings and the aggregates they add up to.

   width: 100% because the auto margins below would otherwise shrink this to its content
   inside a flex column, taking the lattice with it. */
.lat-inner {
    width: 100%;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* Absolutely positioned and behind everything. The canvas sizes itself from
   this element, so the stage must establish the box. */
.lat-field {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: block;
    pointer-events: none;
}

.lat-inner {
    position: relative;
    z-index: 1;
    max-width: 1680px;
    margin: 0 auto;
    padding: 32px 32px 36px;
}

/* --------------------------------------------------------------------------
   Head
   -------------------------------------------------------------------------- */

.lat-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 32px;
    flex-wrap: wrap;
    margin-bottom: 28px;
    flex: 0 0 auto;
}

.lat-state {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--lat-mute);
}

/* Three states, three meanings.

   Green rather than the brand accent, which is deliberate: blue is already the
   structure label, the stamp and the lit cell, and a live market should not be
   the same colour as a link. Green for open is also the convention this reader
   already parses without thinking about it.

   Amber while connecting, because it is neither good news nor bad yet — and
   grey when closed, because nothing is happening and nothing should look as
   though it is. */
.lat-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--lat-mute);
}

.lat-stage[data-state="live"] .lat-dot {
    background: #22C55E;
    animation: lat-pulse 2.4s ease-in-out infinite;
}

.lat-stage[data-state="connecting"] .lat-dot {
    background: #E8B44A;
    animation: lat-pulse-wait 1.4s ease-in-out infinite;
}

.lat-stage[data-state="closed"] .lat-dot {
    background: var(--lat-mute);
    animation: none;
}

@keyframes lat-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.45); }
    70%      { box-shadow: 0 0 0 7px rgba(34, 197, 94, 0); }
}

/* Faster than the live pulse. Waiting should feel like waiting, not like a
   market ticking over. */
@keyframes lat-pulse-wait {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.35; }
}

.lat-title {
    margin: 14px 0 0;

    /* No measure constraint. The break is set in the markup, one sentence per
       line, so a character count has nothing to decide. */
    max-width: none;

    font-size: clamp(30px, 3.4vw, 46px);
    font-weight: 500;
    letter-spacing: -0.032em;
    line-height: 1.06;
    color: #FFFFFF;
}



.lat-head-right {
    padding-top: 6px;
}

.lat-asof {
    text-align: right;
}

@media (max-width: 1040px) {
    .lat-asof {
        text-align: left;
    }
}

.lat-asof-label {
    display: block;
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--lat-mute);
}

.lat-asof-value {
    display: block;
    margin-top: 3px;
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    color: var(--lat-ink);
}

/* --------------------------------------------------------------------------
   The lattice

   Four across, three down. Blocks are bordered rather than filled, so the
   field shows through and they read as windows onto it rather than cards
   sitting on top.
   -------------------------------------------------------------------------- */

.lat-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 12px;
}

.lat-block {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 200px;
    padding: 16px 18px 14px;
    background: var(--lat-block-bg);
    border: 1px solid var(--lat-line);
    backdrop-filter: blur(2px);
    transition: border-color 180ms ease, background 180ms ease;
}

.lat-block:hover {
    border-color: var(--lat-line-strong);
    background: var(--lat-block-bg-hover);
}

/* Empty positions. Visible enough to hold the grid's shape, faint enough that
   nobody reads them as content that failed to load. */
.lat-block--ghost {
    background: rgba(255, 255, 255, 0.012);
    border-style: dashed;
    border-color: rgba(255, 255, 255, 0.05);
}

/* An arrival. The border lights and a wash passes through, then both settle —
   the same gesture as a walker stamping a cell, at the scale of a filing. */
.lat-block--new {
    animation: lat-stamp 2.2s ease-out;
}

@keyframes lat-stamp {
    0% {
        border-color: var(--lat-accent);
        background: rgba(79, 168, 255, 0.16);
        box-shadow: 0 0 0 1px rgba(79, 168, 255, 0.5), 0 0 26px rgba(79, 168, 255, 0.18);
    }
    28% {
        border-color: rgba(79, 168, 255, 0.72);
        background: rgba(79, 168, 255, 0.10);
        box-shadow: 0 0 0 1px rgba(79, 168, 255, 0.22), 0 0 18px rgba(79, 168, 255, 0.10);
    }
    100% {
        border-color: var(--lat-line);
        background: var(--lat-block-bg);
        box-shadow: 0 0 0 1px rgba(79, 168, 255, 0), 0 0 0 rgba(79, 168, 255, 0);
    }
}

.lat-block-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}

.lat-time {
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    color: var(--lat-mute);
}

.lat-structure {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lat-accent);
    text-align: right;
}

.lat-issuer {
    margin-bottom: 8px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.25;
    color: #FFFFFF;

    /* Two lines at most. Issuer names run long, and a third line would come out
       of the description's space rather than the block's. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.lat-desc {
    flex: 1;
    margin: 0 0 12px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--lat-mute);

    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.lat-block-foot {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    padding-top: 11px;
    border-top: 1px solid var(--lat-line);
}

.lat-metric-label {
    display: block;
    font-size: 9px;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #5E708A;
}

.lat-metric-value {
    display: block;
    margin-top: 3px;
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
    color: var(--lat-ink);

    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.lat-metric-value--notional { color: var(--lat-amber); }
.lat-metric-value--income   { color: var(--lat-green); }

.lat-empty {
    margin-top: 16px;
    text-align: center;
    font-size: 13px;
    color: var(--lat-mute);
}

/* --------------------------------------------------------------------------
   Ticker
   -------------------------------------------------------------------------- */

/* Aligned with the lattice rather than bled to the edges. Running full width is
   a device for pages that are full width; under a contained grid it reads as a
   mistake rather than as intent.

   A full border now, because it has become an object alongside the blocks
   rather than a band across the page. */
.lat-ticker {
    margin: 20px 0 0;
    padding: 0;
    border: 1px solid var(--lat-line);
    background: rgba(4, 10, 20, 0.7);
    overflow: hidden;
}

.lat-ticker-track {
    display: flex;
    align-items: center;
    gap: 44px;
    padding: 13px 22px;
    white-space: nowrap;
    animation: lat-scroll 46s linear infinite;
    width: max-content;
}

.lat-ticker:hover .lat-ticker-track {
    animation-play-state: paused;
}

@keyframes lat-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

.lat-stat {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
}

.lat-stat span {
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--lat-mute);
}

.lat-stat b {
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 14px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: #FFFFFF;
}

/* The coverage qualification, directly beneath the claim it qualifies. Quiet
   enough not to compete with the headline, present enough that nobody can say
   it was buried. */
.lat-coverage {
    margin: 14px 0 0;
    max-width: 52ch;
    font-size: 11.5px;
    line-height: 1.5;
    color: #5E708A;
}

/* --------------------------------------------------------------------------
   Narrower viewports

   Three across, then two, then one. The block never narrows below the point
   where a description reads — a squeezed lattice is worse than a taller one.
   -------------------------------------------------------------------------- */

@media (max-width: 1400px) {
    .lat-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 1040px) {
    .lat-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .lat-head {
        flex-direction: column;
        gap: 20px;
    }

    .lat-head-right {
        padding-top: 0;
    }
}

@media (max-width: 680px) {
    .lat-inner {
        padding: 26px 18px 30px;
    }

    .lat-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* The stamp is the one thing on this page that must not move for someone who
   has asked motion to stop. The border still changes, so an arrival is still
   visible — it simply arrives rather than animating. */
@media (prefers-reduced-motion: reduce) {
    .lat-block--new {
        animation: none;
        border-color: var(--lat-accent);
    }

    .lat-ticker-track {
        animation: none;
    }

    .lat-stage[data-state="live"] .lat-dot,
    .lat-stage[data-state="connecting"] .lat-dot {
        animation: none;
    }
}


/* --------------------------------------------------------------------------
   Tuning panel

   Development only. Deliberately utilitarian — it is a tool, and making it
   look designed would invite somebody to ship it.
   -------------------------------------------------------------------------- */

.lat-tuner {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 60;
    width: 230px;
    max-height: 78vh;
    overflow-y: auto;
    padding: 14px;
    background: rgba(6, 12, 24, 0.94);
    border: 1px solid rgba(255, 255, 255, 0.14);
    backdrop-filter: blur(6px);
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 10px;
    color: #C9D6E8;
}

.lat-tuner-title {
    margin-bottom: 10px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #4FA8FF;
}

.lat-tuner-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 2px 8px;
    margin-bottom: 9px;
    cursor: pointer;
}

.lat-tuner-row span {
    color: #8A9BB4;
}

.lat-tuner-row b {
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: #FFFFFF;
}

.lat-tuner-row input[type="range"] {
    grid-column: 1 / -1;
    width: 100%;
    height: 3px;
    margin: 3px 0 0;
    accent-color: #4FA8FF;
}

.lat-tuner-row--check {
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 8px;
    margin: 14px 0 12px;
    padding-top: 11px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.lat-tuner-copy {
    width: 100%;
    padding: 7px;
    background: #FFFFFF;
    border: 0;
    color: #07142F;
    font-family: inherit;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    cursor: pointer;
}

.lat-tuner-copy:hover {
    background: #D9E4F2;
}


/* --------------------------------------------------------------------------
   The four facets

   Four ways of working the same market. Not steps — nobody does Live Market
   before Explorer — so they are divided by hairlines rather than numbered in
   sequence, and each carries the same mark with a different cell lit.

   That is the headline rendered as a figure: the lattice never changes, the
   question does.
   -------------------------------------------------------------------------- */

.lat-facets {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin-top: 30px;
    padding-top: 26px;
    border-top: 1px solid var(--lat-line);
}

.lat-facet {
    padding: 0 26px;
    border-left: 1px solid var(--lat-line);
}

/* No rule on the first, so the row reads as one object divided rather than as
   four things placed side by side. */
.lat-facet:first-child {
    padding-left: 0;
    border-left: 0;
}

.lat-facet:last-child {
    padding-right: 0;
}

.lat-facet-mark {
    display: block;
    width: 20px;
    height: 29px;
    margin-bottom: 16px;
}

.lat-cell {
    fill: rgba(255, 255, 255, 0.20);
    transition: fill 600ms ease;
}

/* The one cell that differs. Deliberately the only accent in the band — four
   marks with four lit squares is the whole idea, and anything else coloured
   here would dilute it. */
.lat-cell--lit {
    fill: var(--lat-accent);
}

.lat-facet-index {
    display: block;
    font-family: 'IBM Plex Mono', ui-monospace, Consolas, monospace;
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.28em;
    color: #5E708A;
}

.lat-facet-name {
    margin: 8px 0 5px;
    font-size: 19px;
    font-weight: 500;
    letter-spacing: -0.022em;
    line-height: 1.15;
    color: #FFFFFF;
}

.lat-facet-line {
    margin: 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--lat-mute);
}

@media (max-width: 1040px) {
    .lat-facets {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 24px 0;
    }

    /* At two across the third would carry a left rule and sit against nothing,
       so the rule follows the column rather than the order. */
    .lat-facet:nth-child(odd) {
        padding-left: 0;
        border-left: 0;
    }

    .lat-facet:nth-child(even) {
        padding-right: 0;
    }
}

@media (max-width: 680px) {
    .lat-facets {
        grid-template-columns: minmax(0, 1fr);
        gap: 22px;
    }

    .lat-facet {
        padding: 0;
        border-left: 0;
    }
}

/* ==========================================================================
   Light palette

   Not a light version of the page — the same page on a white ground.

   The blocks stay exactly as they are: dark, glassy, blue-accented. What
   changes is the surface they sit on and the text that touches it. The effect
   is different in kind rather than in tone: on navy the blocks are windows cut
   into a field, and on white they are panes floating above one.

   The walkers still have to be dark, because a pale mark on a pale ground is
   nothing at all. So the field on white is made of shadow, and the blocks are
   the only lit objects on the page.
   ========================================================================== */

.lat-stage[data-theme="light"] {
    --lat-void: #FBFCFE;

    /* Solid rather than translucent. On navy the 28% transparency lets the field
       show through as texture; on white it lets white through, and the blocks
       come out as washed-out grey instead of dark glass. */
    --lat-block-bg: #0A1424;
    --lat-block-bg-hover: #0C182C;

    /* Text that sits directly on the white ground. Everything inside a block
       keeps the dark palette, which is why these are the only overrides. */
    --lat-ink: #0B1220;
    --lat-mute: #5A6B85;
    --lat-line: rgba(11, 18, 32, 0.10);
    --lat-line-strong: rgba(11, 18, 32, 0.20);
}

.lat-stage[data-theme="light"] .lat-title {
    color: #0B1220;
}

.lat-stage[data-theme="light"] .lat-asof-value {
    color: #0B1220;
}

/* --------------------------------------------------------------------------
   The blocks are deliberately untouched.

   Their background, border, stamp, issuer, description and metric colours all
   stay as they are on the dark page. The only change is a shadow — on navy a
   block is defined by being lighter than its ground, and on white it needs to
   lift off the surface instead.
   -------------------------------------------------------------------------- */

.lat-stage[data-theme="light"] .lat-block {
    /* The blur has nothing left to blur once the background is solid, and it
       costs a compositing layer per block. */
    backdrop-filter: none;
    box-shadow: 0 1px 2px rgba(11, 18, 32, 0.06), 0 8px 24px rgba(11, 18, 32, 0.07);
}

.lat-stage[data-theme="light"] .lat-block:hover {
    box-shadow: 0 1px 2px rgba(11, 18, 32, 0.08), 0 12px 30px rgba(11, 18, 32, 0.10);
}

/* Empty positions read as absence rather than as an object, so they stay flat
   and take the ground's own logic rather than the block's. */
.lat-stage[data-theme="light"] .lat-block--ghost {
    background: rgba(11, 18, 32, 0.018);
    border-color: rgba(11, 18, 32, 0.07);
    box-shadow: none;
    backdrop-filter: none;
}

/* The ticker stays dark. It belongs to the lattice above it rather than to the
   page, and breaking that would separate the filings from the figures they add
   up to. */
.lat-stage[data-theme="light"] .lat-ticker {
    background: #070E1A;
    border-color: rgba(11, 18, 32, 0.10);
    box-shadow: 0 1px 2px rgba(11, 18, 32, 0.06), 0 8px 24px rgba(11, 18, 32, 0.07);
}

/* --------------------------------------------------------------------------
   What sits on the white
   -------------------------------------------------------------------------- */

.lat-stage[data-theme="light"] .lat-facet-name {
    color: #0B1220;
}

.lat-stage[data-theme="light"] .lat-facet-index {
    color: #7A8AA3;
}

/* More weight than their dark counterparts. An unlit cell at 14% is legible on
   navy and invisible on white. */
.lat-stage[data-theme="light"] .lat-cell {
    fill: rgba(11, 18, 32, 0.22);
}

/* The accent is overridden per element rather than on the stage, because the
   variable is also what colours the structure label and the stamp inside every
   block — and those are on dark and already correct.

   #4FA8FF is tuned to carry on navy. On white it has nothing to push against
   and reads as a pale wash, so the two places the accent touches the ground get
   a heavier blue. */
.lat-stage[data-theme="light"] .lat-cell--lit {
    fill: #0B5FD0;
}

/* The dot is not themed. Green means open and amber means waiting on either
   ground — a state that changed colour with the palette would stop being a
   signal and become decoration. Only the closed grey shifts, because it has to
   stay legible against white. */
.lat-stage[data-theme="light"][data-state="closed"] .lat-dot {
    background: #7A8AA3;
}


/* --------------------------------------------------------------------------
   Open Market

   A solid button rather than a styled link. The restrained version — body
   weight, thin rule, small arrow — was indistinguishable from the text around
   it, which is a failure however principled the reasoning.

   It works here because nothing competes with it. On a page where every other
   element is a label or a fact, one filled shape is unmistakably the thing to
   press, and it needs no animation to say so.

   Always the highest-contrast object on the page: white on the dark ground,
   dark on the white one.
   -------------------------------------------------------------------------- */

.lat-open {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    align-self: center;

    /* Its own band rather than a line appended to the facets. */
    margin-top: 56px;

    padding: 14px 28px;
    background: #FFFFFF;
    border: 0;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #07142F !important;
    text-decoration: none !important;
    transition: background 160ms ease;
}

.lat-open:hover {
    background: #D9E4F2;
    color: #07142F !important;
}

/* The arrow moves rather than the label, so the button acknowledges the cursor
   without shifting the word a reader is looking at. */
.lat-open-arrow {
    font-size: 14px;
    color: #07142F;
    transition: transform 160ms ease;
}

.lat-open:hover .lat-open-arrow {
    transform: translateX(3px);
}

/* Lifted on the white ground only. A shadow needs something to fall on, and on
   the near-black page it would be invisible — so the dark version stays flat.

   Slightly heavier than the blocks carry, since this is the one object that
   should sit above them rather than alongside. */
.lat-stage[data-theme="light"] .lat-open {
    background: #0A1424;
    color: #FFFFFF !important;
    box-shadow: 0 1px 2px rgba(11, 18, 32, 0.10), 0 8px 20px rgba(11, 18, 32, 0.12);
    transition: background 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}

.lat-stage[data-theme="light"] .lat-open:hover {
    background: #12203A;
    color: #FFFFFF !important;
    box-shadow: 0 2px 4px rgba(11, 18, 32, 0.12), 0 14px 28px rgba(11, 18, 32, 0.16);
    transform: translateY(-1px);
}

@media (prefers-reduced-motion: reduce) {
    .lat-stage[data-theme="light"] .lat-open:hover {
        transform: none;
    }
}

.lat-stage[data-theme="light"] .lat-open-arrow {
    color: #FFFFFF;
}

@media (prefers-reduced-motion: reduce) {
    .lat-open:hover .lat-open-arrow {
        transform: none;
    }
}
