/* Goshen Labs — shared stylesheet.
   Visual world: the accountant's green columnar ledger. Every product the
   company builds is a system of record, so the page is built as ruled
   entries rather than cards. */

/* ---- Tokens: light is the base palette ---------------------------------- */
:root {
    --paper:        #F5F7F2;
    --paper-raised: #FFFFFF;
    --band:         #EDF2EA;   /* the green bar on ledger paper */
    --rule:         #DBE2D6;
    --rule-strong:  #B2BFAC;
    --ink:          #14190F;   /* 16.56:1 on paper */
    --ink-soft:     #4A5449;   /*  7.33:1 */
    --ink-faint:    #667260;   /*  4.70:1 — was #6E7A6B at 4.18:1, below AA */
    --accent:       #0E7A57;
    --accent-deep:  #0A5A40;
    --accent-wash:  #E0EFE7;
    --ochre:        #8A6210;

    --display: Georgia, "Iowan Old Style", "Times New Roman", serif;
    --body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;

    --measure: 66ch;
    --gutter: clamp(1.25rem, 4vw, 2.5rem);

    /* Depth. The world is paper on a desk, so the third dimension is the
       thickness of a sheet and the angle you read it at — not a game engine.
       One perspective distance and one lift, used everywhere, or the page
       reads as several unrelated spaces. */
    --persp: 1400px;
    --lift: 10px;
    --tilt: 7deg;
}

/* Dark, for viewers whose OS says dark and who have not chosen light. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --paper:        #0C100D;
        --paper-raised: #131914;
        --band:         #151D17;
        --rule:         #263025;
        --rule-strong:  #3B483A;
        --ink:          #E9EEE7;
        --ink-soft:     #AAB5A7;
        --ink-faint:    #83907F;
        --accent:       #4FC79A;
        --accent-deep:  #7EDCB8;
        --accent-wash:  #10251C;
        --ochre:        #D3A94E;
    }
}

/* Explicit dark choice wins over a light OS. */
:root[data-theme="dark"] {
    --paper:        #0C100D;
    --paper-raised: #131914;
    --band:         #151D17;
    --rule:         #263025;
    --rule-strong:  #3B483A;
    --ink:          #E9EEE7;
    --ink-soft:     #AAB5A7;
    --ink-faint:    #83907F;
    --accent:       #4FC79A;
    --accent-deep:  #7EDCB8;
    --accent-wash:  #10251C;
    --ochre:        #D3A94E;
}

/* ---- Base --------------------------------------------------------------- */
* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--body);
    font-size: 17px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
    font-family: var(--display);
    font-weight: 400;
    text-wrap: balance;
    line-height: 1.15;
    margin: 0;
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--accent-deep); }
a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: 2px;
}

p { margin: 0 0 1.1em; max-width: var(--measure); }
ul, ol { max-width: var(--measure); }

.wrap {
    max-width: 76rem;
    margin: 0 auto;
    padding-inline: var(--gutter);
}

/* Section label: mono, uppercase, with the rule that runs to the margin. */
.label {
    display: flex;
    align-items: center;
    gap: 1rem;
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 2rem;
}
.label::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--rule);
}

/* ---- Masthead ----------------------------------------------------------- */
.masthead {
    border-bottom: 1px solid var(--rule);
    background: var(--paper);
    position: sticky;
    top: 0;
    z-index: 10;
}
.masthead .wrap {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    min-height: 4.25rem;
    flex-wrap: wrap;
}
.wordmark {
    font-family: var(--display);
    font-size: 1.2rem;
    letter-spacing: 0.01em;
    color: var(--ink);
    text-decoration: none;
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
}
.wordmark:hover { color: var(--ink); }
.wordmark .mark {
    font-family: var(--mono);
    font-size: 0.72rem;
    color: var(--accent);
    letter-spacing: 0.1em;
    border: 1px solid var(--rule-strong);
    padding: 0.15rem 0.4rem;
    border-radius: 2px;
}
.nav {
    display: flex;
    gap: 1.6rem;
    font-size: 0.9rem;
    flex-wrap: wrap;
}
.nav a {
    color: var(--ink-soft);
    text-decoration: none;
}
.nav a:hover { color: var(--accent); }

/* ---- Hero --------------------------------------------------------------- */
.hero {
    padding-block: clamp(3.5rem, 9vw, 7rem) clamp(2.5rem, 6vw, 4.5rem);
    border-bottom: 1px solid var(--rule);
}
.hero h1 {
    font-size: clamp(2.3rem, 5.6vw, 4rem);
    letter-spacing: -0.015em;
    max-width: 20ch;
}
.hero .standfirst {
    font-size: clamp(1.05rem, 2vw, 1.28rem);
    color: var(--ink-soft);
    max-width: 54ch;
    margin-top: 1.6rem;
}
.locus {
    font-family: var(--mono);
    font-size: 0.72rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 1.8rem;
}
.locus span { color: var(--accent); }

/* ---- Generic section ---------------------------------------------------- */
.section {
    padding-block: clamp(3rem, 7vw, 5rem);
    border-bottom: 1px solid var(--rule);
}
.section h2 {
    font-size: clamp(1.6rem, 3.2vw, 2.2rem);
    margin-bottom: 1.2rem;
}
.lede { font-size: 1.06rem; color: var(--ink-soft); }

.cols {
    display: grid;
    gap: clamp(2rem, 5vw, 3.5rem);
    grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
    align-items: start;
}
.cols h3 {
    font-size: 1.24rem;
    margin-bottom: 0.7rem;
}
.cols p:last-child { margin-bottom: 0; }

/* ---- The ledger: products as ruled entries ------------------------------ */
.ledger-scroll { overflow-x: auto; }

.ledger {
    width: 100%;
    min-width: 44rem;
    border-collapse: collapse;
    font-size: 0.96rem;
}
.ledger caption {
    text-align: left;
    font-family: var(--mono);
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-faint);
    padding-bottom: 0.9rem;
}
.ledger th {
    text-align: left;
    font-family: var(--mono);
    font-weight: 400;
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    padding: 0 1rem 0.6rem 0;
    border-bottom: 2px solid var(--rule-strong);
    vertical-align: bottom;
}
.ledger td {
    padding: 1.15rem 1rem 1.15rem 0;
    border-bottom: 1px solid var(--rule);
    vertical-align: top;
}
/* The green bar. Real columnar pads banded alternate rows.
   Rows come in pairs — an entry followed by its hidden detail — so banding
   alternates every FOUR rows to keep a pair on the same stripe. Plain
   nth-child(odd) would band every entry and no detail, losing the stripe. */
.ledger tbody tr:nth-child(4n+1),
.ledger tbody tr:nth-child(4n+2) { background: var(--band); }
.ledger td:first-child, .ledger th:first-child { padding-left: 1rem; }

.entry-name {
    font-family: var(--display);
    font-size: 1.15rem;
    color: var(--ink);
    display: block;
}
.entry-kind {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
    display: block;
    margin-top: 0.3rem;
}
.ledger .desc { color: var(--ink-soft); max-width: 42ch; }
.ledger .figures { font-variant-numeric: tabular-nums; white-space: nowrap; }

.status {
    display: inline-block;
    font-family: var(--mono);
    font-size: 0.66rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.2rem 0.5rem;
    border-radius: 2px;
    border: 1px solid currentColor;
    white-space: nowrap;
}
.status.live    { color: var(--accent); }
.status.build   { color: var(--ochre); }
.status.service { color: var(--ink-faint); }

/* ---- Notes / callout ---------------------------------------------------- */
.note {
    border-left: 3px solid var(--accent);
    background: var(--accent-wash);
    padding: 1.1rem 1.3rem;
    margin: 2rem 0 0;
    max-width: var(--measure);
    font-size: 0.94rem;
    color: var(--ink-soft);
}
.note strong { color: var(--ink); }
.note p:last-child { margin-bottom: 0; }

/* ---- Contact ------------------------------------------------------------ */
.contact-grid {
    display: grid;
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    margin-top: 2rem;
}
.contact-grid > div {
    background: var(--paper-raised);
    padding: 1.4rem 1.5rem;
}
.contact-grid dt {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 0.45rem;
}
.contact-grid dd { margin: 0; font-size: 1rem; }

/* ---- Footer ------------------------------------------------------------- */
.foot {
    padding-block: 2.5rem 3.5rem;
    font-size: 0.88rem;
    color: var(--ink-faint);
}
.foot-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem 1.4rem;
    margin-bottom: 1.4rem;
}
.foot-links a { color: var(--ink-soft); text-decoration: none; }
.foot-links a:hover { color: var(--accent); }
.foot p { max-width: var(--measure); margin-bottom: 0.6rem; }

/* ---- Long-form legal pages ---------------------------------------------- */
.doc { padding-block: clamp(2.5rem, 6vw, 4rem) 2rem; }
.doc-head { border-bottom: 2px solid var(--rule-strong); padding-bottom: 1.6rem; margin-bottom: 2.5rem; }
.doc-head h1 { font-size: clamp(1.9rem, 4vw, 2.7rem); }
.doc-meta {
    font-family: var(--mono);
    font-size: 0.72rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-top: 1rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.5rem;
}
.doc h2 {
    font-size: 1.35rem;
    margin: 2.6rem 0 0.9rem;
    padding-top: 1.4rem;
    border-top: 1px solid var(--rule);
}
.doc h3 { font-size: 1.08rem; margin: 1.8rem 0 0.6rem; font-family: var(--body); font-weight: 600; }
.doc li { margin-bottom: 0.5rem; }
.doc table {
    width: 100%;
    border-collapse: collapse;
    margin: 1.5rem 0;
    font-size: 0.94rem;
}
.doc th, .doc td {
    text-align: left;
    padding: 0.8rem 1rem 0.8rem 0;
    border-bottom: 1px solid var(--rule);
    vertical-align: top;
}
.doc th {
    font-family: var(--mono);
    font-weight: 400;
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    border-bottom: 2px solid var(--rule-strong);
}

/* ---- Download entries --------------------------------------------------- */
.dl {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.4rem 0;
    border-bottom: 1px solid var(--rule);
}
.dl .meta { font-family: var(--mono); font-size: 0.76rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.btn {
    display: inline-block;
    font-family: var(--mono);
    font-size: 0.76rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.6rem 1.1rem;
    border: 1px solid var(--accent);
    color: var(--accent);
    border-radius: 2px;
    text-decoration: none;
}
.btn:hover { background: var(--accent); color: var(--paper); }

/* ---- Theme toggle ------------------------------------------------------- */
.theme-toggle {
    font-family: var(--mono);
    font-size: 0.66rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    background: transparent;
    color: var(--ink-faint);
    border: 1px solid var(--rule);
    border-radius: 2px;
    padding: 0.4rem 0.65rem;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }

/* ---- Disciplines: four columns of one practice --------------------------- */
.disciplines {
    display: grid;
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    margin-top: 2.5rem;
}
.discipline {
    background: var(--paper-raised);
    padding: 1.8rem 1.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    transition: background 0.2s;
}
.discipline:hover { background: var(--accent-wash); }
.discipline .glyph {
    width: 2.4rem;
    height: 2.4rem;
    color: var(--accent);
}
.discipline h3 {
    font-family: var(--display);
    font-size: 1.14rem;
    font-weight: 400;
    margin: 0;
}
.discipline p {
    font-size: 0.92rem;
    color: var(--ink-soft);
    margin: 0;
    max-width: none;
}

/* ---- Filter controls ---------------------------------------------------- */
.filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.8rem;
}
.filter {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    background: transparent;
    color: var(--ink-faint);
    border: 1px solid var(--rule-strong);
    border-radius: 2px;
    padding: 0.45rem 0.85rem;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.filter:hover { color: var(--accent); border-color: var(--accent); }
.filter[aria-pressed="true"] {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--paper);
}

/* Rows hidden by the filter. Attribute-driven so it works without JS too. */
.ledger tbody tr[hidden] { display: none; }

/* ---- Expandable ledger entries ------------------------------------------ */
.ledger tbody tr.entry { cursor: pointer; transition: background 0.15s; }
.ledger tbody tr.entry:hover { background: var(--accent-wash); }
.ledger tbody tr.entry:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}
.disclose {
    font-family: var(--mono);
    font-size: 0.9rem;
    color: var(--ink-faint);
    display: inline-block;
    width: 1rem;
    transition: transform 0.2s;
}
tr.entry[aria-expanded="true"] .disclose { transform: rotate(90deg); color: var(--accent); }

tr.detail > td {
    padding: 0 1rem 1.6rem 0;
    border-bottom: 1px solid var(--rule);
    color: var(--ink-soft);
    font-size: 0.93rem;
}
tr.detail .detail-in {
    border-left: 2px solid var(--accent);
    padding: 0.2rem 0 0.2rem 1.1rem;
    max-width: 62ch;
}
tr.detail ul { margin: 0.6rem 0 0; padding-left: 1.1rem; }
tr.detail li { margin-bottom: 0.35rem; }

/* ---- Outbound link on a ledger entry ------------------------------------ */
/* Sits inside a row that is itself clickable, so the JS stops propagation —
   otherwise following the link would also toggle the detail open. */
.go {
    display: inline-block;
    font-family: var(--mono);
    font-size: 0.66rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
    margin-top: 0.5rem;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--rule-strong);
    border-radius: 2px;
    color: var(--ink-soft);
    text-decoration: none;
}
.go:hover {
    color: var(--paper);
    background: var(--accent);
    border-color: var(--accent);
}
.go::after { content: " \2192"; }

/* ---- Scroll reveal, in three dimensions ---------------------------------
   A section arrives the way a sheet is laid on a desk: tipped slightly away
   from the reader, settling flat. The rotation is small on purpose — past
   about 10deg the text distorts enough to be harder to read, and a page of
   records has to stay legible while it moves. */
.reveal {
    opacity: 0;
    transform: perspective(var(--persp)) translate3d(0, 14px, -40px) rotateX(var(--tilt));
    transform-origin: 50% 0;
    transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.2, 0.7, 0.3, 1);
    will-change: transform, opacity;
}
.reveal.seen {
    opacity: 1;
    transform: perspective(var(--persp)) translate3d(0, 0, 0) rotateX(0deg);
}
/* Once it has landed, stop claiming a compositor layer for the rest of the
   session. will-change left on permanently is a memory cost, not a speedup. */
.reveal.seen { will-change: auto; }

/* ---- The hero sheet ------------------------------------------------------
   Three ruled sheets stacked in real 3D space behind the headline. It is the
   company's whole argument in one object: the record has depth, and the top
   sheet is the only one you can still write on.

   Purely decorative, aria-hidden, and it never overlaps the text measure. */
.sheets {
    perspective: var(--persp);
    perspective-origin: 70% 30%;
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    z-index: 0;
}
.sheets-in {
    position: absolute;
    top: 14%;
    /* Held well clear of the right edge: a 3D rotation projects wider than the
       element's own box, so an inset that looks generous flat still clips. */
    right: 7%;
    width: min(26vw, 310px);
    aspect-ratio: 3 / 4;
    transform-style: preserve-3d;
    transform: rotateX(52deg) rotateZ(-32deg);
    animation: sheet-settle 1.4s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
.sheet {
    position: absolute;
    inset: 0;
    border: 1px solid var(--rule);
    /* Ledger ruling: a hairline every row, banded in pairs the way columnar
       pads are. Fine enough that the perspective foreshortening at the far
       edge does not turn it into moire. */
    background:
        repeating-linear-gradient(
            to bottom,
            transparent 0 11px,
            var(--band) 11px 22px
        ),
        var(--paper-raised);
    box-shadow: 0 18px 40px -26px rgba(0, 0, 0, 0.5);
}
/* Each sheet sits a real distance above the one below it, and slightly out of
   register — a stack nobody squared off. Without the offset the three read as
   one sheet, because a perfectly aligned stack has no visible thickness. */
.sheet:nth-child(1) {
    transform: translate3d(-14px, 10px, 0) rotate(-1.5deg);
    opacity: 0.4;
}
.sheet:nth-child(2) {
    transform: translate3d(-6px, 4px, 16px) rotate(0.8deg);
    opacity: 0.62;
}
.sheet:nth-child(3) {
    transform: translateZ(34px);
    opacity: 0.96;
    border-color: var(--rule-strong);
}
/* Two entries written on the top sheet — the only one still open to be
   written on. Short, ruled, and in the accent: this is the thing the whole
   company is about, so it is the only saturated colour in the object. */
.sheet:nth-child(3)::before,
.sheet:nth-child(3)::after {
    content: "";
    position: absolute;
    height: 2px;
    background: var(--accent);
    border-radius: 1px;
}
.sheet:nth-child(3)::before { left: 14%; top: 31%; width: 44%; }
.sheet:nth-child(3)::after  { left: 14%; top: 42%; width: 28%; opacity: 0.55; }

@keyframes sheet-settle {
    from { transform: rotateX(74deg) rotateZ(-46deg) translateY(40px); opacity: 0; }
    to   { transform: rotateX(52deg) rotateZ(-32deg) translateY(0);    opacity: 1; }
}

/* Where the browser supports scroll-linked animation, the stack goes on
   flattening as the reader scrolls — the sheet is laid down and read. This is
   progressive: without support the stack simply stays at its settled angle. */
@supports (animation-timeline: scroll()) {
    @media (prefers-reduced-motion: no-preference) {
        .sheets-in {
            animation: sheet-settle 1.4s cubic-bezier(0.2, 0.7, 0.3, 1) both,
                       sheet-lay linear both;
            animation-timeline: auto, scroll(root block);
            animation-range: normal, 0 70vh;
        }
        @keyframes sheet-lay {
            from { transform: rotateX(52deg) rotateZ(-32deg); }
            to   { transform: rotateX(18deg) rotateZ(-10deg) translateY(-60px); }
        }
    }
}

.hero { position: relative; }
.hero .wrap { position: relative; z-index: 1; }

/* The stack is the first thing on a narrow screen and the text has to win,
   so below the two-column threshold it goes. */
@media (max-width: 760px) {
    .sheets { display: none; }
}

/* ---- Depth on the ledger ------------------------------------------------
   Table rows are awkward in 3D — the box each transform creates fights the
   table's own layout — so the depth lives on things that are not rows: the
   disclosure arrow, and the detail panel, which unfolds from its top edge
   like a page being turned up toward you. */
tr.entry[aria-expanded="true"] .disclose {
    transform: rotate(90deg) translateZ(8px);
}
tr.detail .detail-in {
    transform-origin: 50% 0;
    animation: unfold 0.42s cubic-bezier(0.2, 0.8, 0.3, 1) both;
}
@keyframes unfold {
    from { opacity: 0; transform: perspective(900px) rotateX(-38deg); }
    to   { opacity: 1; transform: perspective(900px) rotateX(0deg); }
}

/* ---- Depth on the discipline cards --------------------------------------
   They already read as paper. Pointing at one tips it toward the reader by a
   couple of degrees and lifts its shadow — the amount a real card moves when
   you put a finger on the corner, not a flip. */
.discipline {
    transform: perspective(var(--persp)) translateZ(0);
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1),
                box-shadow 0.35s ease;
}
.discipline:hover,
.discipline:focus-within {
    transform: perspective(var(--persp)) translateZ(var(--lift)) rotateX(2deg);
    box-shadow: 0 22px 34px -26px rgba(0, 0, 0, 0.5);
}
.discipline .glyph {
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.discipline:hover .glyph,
.discipline:focus-within .glyph {
    transform: perspective(600px) translateZ(18px);
}

/* ---- Continuous depth, not one-shot reveals -----------------------------
   The reveal below lands a section once and is done. What makes a page feel
   three-dimensional is that the depth keeps responding while you scroll, so
   where the browser supports scroll-linked animation each section is tied to
   its own position in the viewport: tipped away as it rises, flat while you
   are reading it, tipped away again as it leaves.

   The angles are small. This is a page of records, and text past about 6deg
   of rotateX starts costing legibility for no gain. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .section > .wrap,
        .doc > .wrap {
            animation: section-depth linear both;
            animation-timeline: view();
            animation-range: entry 0% cover 22%, cover 78% exit 100%;
            transform-origin: 50% 50%;
            will-change: transform, opacity;
        }
        /* Geometry only — no opacity. An earlier pass faded the section on the
           way out and it simply looked broken: body text sitting at 55%
           opacity while still fully on screen is a contrast failure, not a
           sense of depth. Depth is carried by the angle and the distance. */
        @keyframes section-depth {
            from { transform: perspective(var(--persp)) translate3d(0, 26px, -70px) rotateX(5deg); }
            50%  { transform: perspective(var(--persp)) translate3d(0, 0, 0) rotateX(0deg); }
            to   { transform: perspective(var(--persp)) translate3d(0, -18px, -50px) rotateX(-4deg); }
        }

        /* The masthead sits above the page in the same space, so it gets the
           shadow the depth implies rather than a flat border. */
        .masthead {
            animation: masthead-lift linear both;
            animation-timeline: scroll(root block);
            animation-range: 0 120px;
        }
        @keyframes masthead-lift {
            from { box-shadow: 0 0 0 rgba(0, 0, 0, 0); }
            to   { box-shadow: 0 10px 24px -20px rgba(0, 0, 0, 0.55); }
        }
    }
}

/* ---- Ledger rows have thickness ----------------------------------------
   A table row cannot carry a 3D transform without fighting the table's own
   layout, so the depth is done with light instead of geometry: the row
   brightens and casts, which reads as lifting toward the reader. The inset
   line on the left is the edge of the sheet catching light. */
.ledger tbody tr.entry {
    transition: background 0.18s ease, box-shadow 0.28s ease;
}
.ledger tbody tr.entry:hover {
    box-shadow: inset 3px 0 0 var(--accent),
                0 14px 26px -22px rgba(0, 0, 0, 0.6);
}
/* The name lifts a little further than the row it sits in — parallax within
   a single row, which is what sells depth at this scale. */
.entry-name { transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.3, 1); }
.ledger tbody tr.entry:hover .entry-name {
    transform: perspective(600px) translate3d(3px, 0, 12px);
}

/* ---- Controls that push back -------------------------------------------
   A button you press should move away from you, not change colour only. */
.filter, .go {
    transform: perspective(600px) translateZ(0);
    transition: transform 0.18s cubic-bezier(0.2, 0.7, 0.3, 1),
                color 0.15s, border-color 0.15s, background 0.15s,
                box-shadow 0.18s ease;
}
.filter:hover, .go:hover {
    transform: perspective(600px) translateZ(6px);
    box-shadow: 0 8px 16px -12px rgba(0, 0, 0, 0.5);
}
.filter:active, .go:active {
    transform: perspective(600px) translateZ(-3px);
    box-shadow: none;
}

/* ---- The contact block, as cards on a desk ------------------------------ */
.contact-grid > div {
    transform: perspective(var(--persp)) translateZ(0);
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1),
                box-shadow 0.35s ease;
}
.contact-grid > div:hover {
    transform: perspective(var(--persp)) translateZ(8px) rotateX(1.5deg);
    box-shadow: 0 18px 30px -26px rgba(0, 0, 0, 0.5);
}

/* ---- The hero stack keeps breathing ------------------------------------
   Two degrees, twenty seconds. Below the threshold where anyone notices it
   moving, above the threshold where the object reads as inert. */
@media (prefers-reduced-motion: no-preference) {
    .sheet:nth-child(3) {
        animation: sheet-breathe 20s ease-in-out infinite;
    }
    .sheet:nth-child(2) {
        animation: sheet-breathe 26s ease-in-out infinite reverse;
    }
    @keyframes sheet-breathe {
        0%, 100% { transform: translateZ(34px) rotate(0deg); }
        50%      { transform: translateZ(46px) rotate(0.6deg); }
    }
}

/* ---- Motion is optional -------------------------------------------------
   Everything above is decoration. Someone who has asked their system for less
   motion gets the page flat, and gets all of it — nothing here is the only
   route to any content. */
@media (prefers-reduced-motion: reduce) {
    * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
    html { scroll-behavior: auto; }
    .reveal { opacity: 1; transform: none; }
    .sheets-in { animation: none; transform: rotateX(40deg) rotateZ(-24deg); }
    .sheet:nth-child(2), .sheet:nth-child(3) { animation: none; }
    .discipline:hover, .discipline:focus-within { transform: none; }
    .discipline:hover .glyph, .discipline:focus-within .glyph { transform: none; }
    tr.detail .detail-in { animation: none; }
    .section > .wrap, .doc > .wrap { animation: none; opacity: 1; transform: none; }
    .masthead { animation: none; }
    .filter:hover, .go:hover, .filter:active, .go:active { transform: none; box-shadow: none; }
    .ledger tbody tr.entry:hover .entry-name { transform: none; }
    .contact-grid > div:hover { transform: none; box-shadow: none; }
}
