/* Covenra-Ghoshen Ltd — 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;
    white-space: nowrap;
}
.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); }
    }
}

/* ---- Hero calls to action ---------------------------------------------- */
.hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 2.2rem;
}
.btn-solid {
    background: var(--accent);
    color: var(--paper);
}
.btn-solid:hover { background: var(--accent-deep); border-color: var(--accent-deep); color: var(--paper); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---- Proof strip: what we have built, straight after the claim ----------
   Our own platforms rather than client logos — the names are the evidence,
   and each one opens its entry in the work ledger. Set as a ruled line of
   mono entries, not a logo carousel. */
.proof {
    border-bottom: 1px solid var(--rule);
    background: var(--band);
    padding-block: 1.4rem;
}
.proof .wrap {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.6rem 2rem;
}
.proof-label {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin: 0;
}
.proof-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.6rem;
    max-width: none;
}
.proof-list a {
    font-family: var(--display);
    font-size: 1.02rem;
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px solid var(--rule-strong);
}
.proof-list a:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* ---- Outcomes: the three things every engagement is for ---------------- */
.outcomes {
    display: grid;
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    margin-top: 2.5rem;
}
.outcome {
    background: var(--paper-raised);
    padding: 1.8rem 1.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
}
.outcome h3 { font-size: 1.24rem; }
.outcome p { margin: 0; font-size: 0.95rem; color: var(--ink-soft); max-width: none; }
.outcome .outcome-eg {
    margin-top: auto;
    padding-top: 1rem;
    border-top: 1px solid var(--rule);
    font-size: 0.88rem;
}
.outcome-eg span {
    display: block;
    font-family: var(--mono);
    font-size: 0.66rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 0.35rem;
}

/* ---- Services: Rebuild / Automate --------------------------------------
   Tabs styled as the index tabs on a ledger binder: flat, ruled, and joined
   to the sheet they open. */
.engage { margin-top: 2.5rem; }
.engage-tabs {
    display: flex;
    gap: 0;
    border-bottom: 2px solid var(--rule-strong);
}
.engage-tab {
    font-family: var(--mono);
    font-size: 0.74rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    background: transparent;
    color: var(--ink-faint);
    border: 1px solid transparent;
    border-bottom: none;
    border-radius: 2px 2px 0 0;
    padding: 0.8rem 1.4rem;
    margin-bottom: -2px;
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
}
.engage-tab:hover { color: var(--accent); }
.engage-tab[aria-selected="true"] {
    color: var(--accent);
    background: var(--paper-raised);
    border-color: var(--rule-strong);
    box-shadow: inset 0 2px 0 var(--accent);
    border-bottom: 2px solid var(--paper-raised);
}
.engage-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.engage-panel {
    background: var(--paper-raised);
    border: 1px solid var(--rule);
    border-top: none;
    padding: clamp(1.5rem, 4vw, 2.5rem);
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
    animation: unfold 0.42s cubic-bezier(0.2, 0.8, 0.3, 1) both;
    transform-origin: 50% 0;
}
.engage-panel[hidden] { display: none; }
.engage-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.engage-head h3 { font-size: clamp(1.3rem, 2.4vw, 1.6rem); margin-bottom: 0.9rem; }
.engage-head p { color: var(--ink-soft); }
.engage-head .btn { margin-top: 0.4rem; }
.engage-cols {
    display: grid;
    gap: 1.5rem;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}
.engage-label {
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin: 0 0 0.6rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--rule);
}
.engage-cols ul { margin: 0; padding-left: 1.1rem; font-size: 0.93rem; color: var(--ink-soft); }
.engage-cols li { margin-bottom: 0.45rem; }

/* ---- No sideways page scroll --------------------------------------------
   The scroll-linked section tilt projects a few pixels wider than the column
   while it is mid-angle, which on a phone let the page shift sideways. clip
   (not hidden) keeps vertical overflow and position: sticky working. */
main { overflow-x: clip; }

/* ---- Reading progress along the masthead -------------------------------- */
@supports (animation-timeline: scroll()) {
    @media (prefers-reduced-motion: no-preference) {
        .masthead::after {
            content: "";
            position: absolute;
            left: 0;
            right: 0;
            bottom: -1px;
            height: 2px;
            background: var(--accent);
            transform-origin: 0 50%;
            transform: scaleX(0);
            animation: read-progress linear both;
            animation-timeline: scroll(root block);
        }
        @keyframes read-progress { to { transform: scaleX(1); } }
    }
}

/* ---- Entrance motion ----------------------------------------------------
   Everything here is gated on html.motion, which the head script sets only
   when JS runs and the reader has not asked for reduced motion. Without it
   nothing starts hidden. Movement uses the standalone `translate` property so
   it never fights the `transform` depth effects above. */
@keyframes rise {
    from { opacity: 0; translate: 0 22px; }
    to   { opacity: 1; translate: 0 0; }
}
.motion .hero .wrap > * { animation: rise 0.8s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.motion .hero .wrap > :nth-child(1) { animation-delay: 0.05s; }
.motion .hero .wrap > :nth-child(2) { animation-delay: 0.15s; }
.motion .hero .wrap > :nth-child(3) { animation-delay: 0.32s; }
.motion .hero .wrap > :nth-child(4) { animation-delay: 0.48s; }
.motion .proof { animation: rise 0.8s cubic-bezier(0.2, 0.7, 0.3, 1) 0.6s both; }

/* Groups arrive one member at a time. --i is set per child by the page. */
.motion .stagger > * {
    opacity: 0;
    translate: 0 26px;
    transition: opacity 0.6s ease calc(var(--i, 0) * 110ms),
                translate 0.75s cubic-bezier(0.2, 0.7, 0.3, 1) calc(var(--i, 0) * 110ms),
                transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1),
                box-shadow 0.35s ease,
                background 0.2s;
}
.motion .stagger.seen > * { opacity: 1; translate: 0 0; }
/* Ruled grids draw their hairlines with the container's background showing
   through a 1px gap. Until the cells arrive that background would read as a
   solid slab, so the rules fade in with the first cell instead. */
.motion .stagger {
    transition: background-color 0.4s ease, border-color 0.4s ease;
}
.motion .stagger:not(.seen) { background-color: transparent; border-color: transparent; }
.motion .stagger-one {
    opacity: 0;
    translate: 0 30px;
    transition: opacity 0.7s ease, translate 0.8s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.motion .stagger-one.seen { opacity: 1; translate: 0 0; }

/* The rule after each section label is drawn in as the section arrives. */
.motion .section .label::after {
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: transform 1.1s cubic-bezier(0.2, 0.7, 0.3, 1) 0.15s;
}
.motion .section.seen .label::after { transform: scaleX(1); }

/* Outcome cards respond to the pointer the way the discipline cards do. */
.outcome { transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1), box-shadow 0.35s ease, background 0.2s; }
.outcome:hover {
    transform: perspective(var(--persp)) translateZ(var(--lift)) rotateX(2deg);
    box-shadow: 0 22px 34px -26px rgba(0, 0, 0, 0.5);
    background: var(--accent-wash);
}

/* Buttons lift toward the pointer and press back in. */
.btn {
    transition: translate 0.18s cubic-bezier(0.2, 0.7, 0.3, 1), box-shadow 0.18s ease,
                background 0.15s, color 0.15s, border-color 0.15s;
}
.btn:hover { translate: 0 -2px; box-shadow: 0 10px 18px -12px rgba(0, 0, 0, 0.55); }
.btn:active { translate: 0 1px; box-shadow: none; }

/* ---- Hero sheets follow the pointer -------------------------------------
   --px / --py run from -0.5 to 0.5 across the hero. The stack slides a little
   against the pointer and the viewpoint shifts with it, so the sheets read
   as an object in space rather than a picture. */
.sheets {
    perspective-origin: calc(70% + var(--px, 0) * 30%) calc(30% + var(--py, 0) * 30%);
    transition: perspective-origin 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.sheets-in {
    translate: calc(var(--px, 0) * -22px) calc(var(--py, 0) * -16px);
    transition: translate 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* ---- Proof strip as a marquee -------------------------------------------
   Only once the page has doubled the list (and never under reduced motion).
   Hovering or focusing inside stops it, so a name can be read and clicked. */
.proof-viewport { flex: 1 1 100%; min-width: 0; }
.proof-track { display: flex; }
.proof.is-marquee .proof-viewport {
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
            mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.proof.is-marquee .proof-track {
    width: max-content;
    animation: marquee 48s linear infinite;
}
.proof.is-marquee .proof-list { flex-wrap: nowrap; padding-right: 1.6rem; }
.proof.is-marquee .proof-list li { white-space: nowrap; }
.proof.is-marquee .proof-list a { font-size: 1.12rem; }
.proof.is-marquee:hover .proof-track,
.proof.is-marquee:focus-within .proof-track { animation-play-state: paused; }
@keyframes marquee { to { translate: -50% 0; } }

/* ---- 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; }
    .engage-panel { animation: none; }
    .outcome:hover { transform: none; box-shadow: none; }
    .btn:hover, .btn:active { translate: none; box-shadow: none; }
    .sheets-in { translate: none; }
}
