/* ============================================================================
   MagnetERP — magneterp.com marketing site
   ----------------------------------------------------------------------------
   DIRECTION CONTRACT (read before editing; the render is audited against it)

   THESIS      The page IS the document the system produces. Magnet's only honest
               proof is structural — PRODUCT.md forbids fabricated testimonials,
               client logos, benchmarks and usage claims — so this site
               DEMONSTRATES posting rather than describing it. It refuses the SaaS
               default it cannot fill truthfully: tilted dashboard screenshot,
               logo wall, three icon-heading-text cards, pricing table.
   OWN-WORLD   Published-accounts typography drenched over Ledger Blue. TWO grounds
               only — paper white and Ledger Blue Deep — and no cards anywhere.
               Rules do the work borders normally do, including a real accounting
               DOUBLE RULE under every total. Figures are tabular-lining, right
               aligned, and they foot. Red is ledger rule / credit ink only.
   STORY       A Nigerian SME finance manager sees this is the whole back office in
               one book, believes it by watching one invoice post to stock, the
               customer account, the project and the general ledger with the
               figures agreeing, and acts by writing to info@magneterp.com.
   1ST VIEWPORT Full-bleed Ledger Blue. Wordmark small, tagline set as a statement
               heading, then the posting trace: one source document on the left,
               four destination records on the right, joined by leader rules that
               draw themselves once. Primary action sits under the heading.
   FORM        Multi-part posting document + published-accounts typography.

   ----------------------------------------------------------------------------
   THIS IS THE ONLY STYLESHEET. Bootstrap was removed deliberately (8.4 MB of
   unused assets against a product principle that names low bandwidth a
   REQUIREMENT, not polish). Section components use the primitives below; they do
   not invent new colour or type values. To re-theme, edit the token block only.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   1. TOKENS
   The Ledger Blue family is copied from the product's single source of truth,
   Magnet/wwwroot/css/theme.css. The One Accent Rule holds here: no accent
   outside this family. Two stops are ADDED for this surface only (--field-deep
   and the on-field inks) because a marketing page drenches colour at page scale
   where the app only ever accents it. Both are stops in the same family.
   --------------------------------------------------------------------------- */
/* LIGHT AND DARK.
   Both modes define the SAME token names, so no component knows which mode it is
   in — a rule that reads var(--paper) is correct in both, and there is no dark
   variant of any component anywhere in this file.

   THE HARD PART, and the thing to preserve if you edit this: the entire design
   rests on TWO ALTERNATING GROUNDS — paper and the Ledger Blue field. Dark mode
   has to keep them reading as two. So --paper goes NEUTRAL dark and --field goes
   SATURATED dark: the blue stays visibly blue against it, the rhythm of the
   scroll survives, and the page does not collapse into one flat slab.

   Mode is chosen by data-theme on <html>, set before first paint by the inline
   script in App.razor and stored in localStorage under `magnet.theme`. With no
   stored choice the OS preference decides, via the block at the end of §9. */
:root,
[data-theme="light"] {
    color-scheme: light;

    /* Ledger Blue — the product accent */
    --accent: #2563EB;
    --accent-bright: #60A5FA;
    --accent-600: #1D4ED8;
    --accent-press: #1E40AF;
    --accent-deep: #1E3A8A;
    --accent-soft: #EEF2FE;
    --accent-line: #C7D6F5;

    /* The two grounds. Everything on this site sits on one or the other.
       --paper is NOT pure white: people read this page for a while, and #ffffff
       at full display brightness is the thing they turn dark mode on to escape. */
    --paper: #FCFDFF;
    --field: #1E3A8A;      /* drenched ground — white on this is 10.3:1        */
    --field-deep: #152C6B; /* the closing stop, footer only                    */

    /* Ink on paper */
    --ink: #0f172a;        /* headings                        — 17.7:1 on paper */
    --text: #334155;       /* body                            — 10.7:1 on paper */
    --strong: #475569;     /* secondary                       —  7.3:1 on paper */
    --muted: #5F6E82;      /* tertiary, the floor             —  5.2:1 on paper */
    --line: #E7ECF3;       /* hairline rules                                    */
    --line-firm: #cbd5e1;  /* column-head and total rules                       */

    /* Ink on field — tinted from the hue, never grey (craft floor) */
    --on-field: #ffffff;      /* 10.3:1 on --field */
    --on-field-soft: #C7D6F5; /*  7.1:1 on --field */
    --on-field-rule: rgba(199, 214, 245, 0.28);

    /* The light control that sits ON the field (.btn--paper). It needs its own
       tokens rather than reusing --paper: in dark mode a --paper button on a
       --field sheet would be dark-on-dark and vanish, so this pair stays light
       in BOTH modes and keeps the call to action popping off the blue. */
    --cta-bg: #FFFFFF;
    --cta-bg-hover: #EEF2FE;
    --cta-ink: #1E40AF;

    /* Text on a filled accent button. White in BOTH modes — a filled button stays
       saturated in dark, so its label must not follow --paper down into the dark.
       Deliberately NOT overridden in the dark block; it inherits from here. */
    --on-accent: #FFFFFF;

    /* The second ink. Ledger convention: red rules the totals and marks the
       credit side. It decorates nothing. Both stops are the product's own
       documented reds (theme.css --danger-strong / --danger-border). */
    --rule-red: #b91c1c;         /* 6.4:1 on paper */
    --credit-on-field: #fecaca;  /* ~8:1 on --field  */

    /* Type */
    --face: Heebo, "Segoe UI", system-ui, -apple-system, sans-serif;
    --face-mark: CACNormHeavy, Heebo, "Segoe UI", system-ui, sans-serif;

    --t-display: clamp(2.5rem, 6.4vw, 4.5rem);
    --t-h2: clamp(1.75rem, 3.4vw, 2.5rem);
    --t-h3: clamp(1.15rem, 1.8vw, 1.4rem);
    --t-lead: clamp(1.08rem, 1.6vw, 1.3rem);
    --t-body: 1.0625rem;
    --t-small: 0.9375rem;
    --t-label: 0.72rem;
    --t-mark: 1.35rem;   /* the wordmark step — this surface only */

    /* Rhythm. More space above a heading than below it, everywhere. */
    --s-1: 8px;
    --s-2: 12px;
    --s-3: 16px;
    --s-4: 24px;
    --s-5: 40px;
    --s-6: 64px;
    --s-7: 96px;
    --wrap: 1180px;

    /* The DESIGN.md radius scale, declared rather than assumed. */
    --r-sm: 9px;
    --r-md: 11px;
    --r-lg: 16px;
    --r-pill: 999px;

    /* Motion — one strong curve, per the design-engineering floor. The built-in
       CSS easings are too weak; ease-in is never used. */
    --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
    --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

    /* How long a mode change takes. Opt-in — see §9. */
    --theme-swap: 220ms;
}

/* ---------------------------------------------------------------------------
   1b. DARK
   Not an inversion. Inverting this page would give a black ground with glaring
   white type, which is worse to read for a while than the light theme it
   replaced — and it would flatten the two grounds into one.

   --paper goes NEUTRAL dark, --field stays visibly BLUE. That is the whole
   trick: the alternating rhythm of paper sheet / field sheet is the page's
   structure, and it has to survive the switch.

   The accent lifts a step, because #2563EB on a near-black ground is muddy and
   fails on small text. Ink stops short of #ffffff for the same reason the light
   ground is not pure white.
   --------------------------------------------------------------------------- */
[data-theme="dark"] {
    color-scheme: dark;

    --accent: #60A5FA;
    --accent-bright: #93C5FD;
    --accent-600: #7DB4FB;   /* hover LIGHTENS on dark — the mirror of the light rule */
    --accent-press: #2563EB; /* filled buttons — white text ≈ 4.9:1                   */
    --accent-deep: #1D4ED8;
    --accent-soft: #16233A;  /* a blue-tinted raise, not a pale wash */
    --accent-line: #2C4370;

    --paper: #10161F;        /* neutral dark — the "paper" sheets  */
    --field: #16274F;        /* still unmistakably blue against it */
    --field-deep: #0D1730;

    --ink: #E9EEF7;          /* 15.3:1 on paper */
    --text: #C3CDDC;         /* 11.3:1 on paper */
    --strong: #A8B4C6;       /*  8.4:1 on paper */
    --muted: #8C99AD;        /*  6.1:1 on paper */
    --line: #212A36;
    --line-firm: #2F3A4A;

    --on-field: #FFFFFF;        /* 14.5:1 on --field */
    --on-field-soft: #BACBEC;   /*  8.6:1 on --field */
    --on-field-rule: rgba(186, 203, 236, 0.24);

    /* Stays light in dark mode, on purpose: this is the button on the blue
       field, and a dark button there would disappear into its own ground. */
    --cta-bg: #DCE7FB;
    --cta-bg-hover: #C4D6F6;
    --cta-ink: #0E1A34;

    --rule-red: #F87171;         /* 6.4:1 on dark paper */
    --credit-on-field: #FCA5A5;
}

/* ---------------------------------------------------------------------------
   1c. THE OPERATING SYSTEM'S PREFERENCE
   Applies only while the visitor has made no explicit choice. `:not([data-theme])`
   is what makes the toggle authoritative — someone who picks light on a machine
   set to dark keeps light, on this site and on every return visit.
   The values are the dark block above, repeated because CSS custom properties
   cannot be aliased across selectors without an indirection that would show up
   in every DevTools inspection of every token.
   --------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme]) {
        color-scheme: dark;

        --accent: #60A5FA;
        --accent-bright: #93C5FD;
        --accent-600: #7DB4FB;
        --accent-press: #2563EB;
        --accent-deep: #1D4ED8;
        --accent-soft: #16233A;
        --accent-line: #2C4370;

        --paper: #10161F;
        --field: #16274F;
        --field-deep: #0D1730;

        --ink: #E9EEF7;
        --text: #C3CDDC;
        --strong: #A8B4C6;
        --muted: #8C99AD;
        --line: #212A36;
        --line-firm: #2F3A4A;

        --on-field: #FFFFFF;
        --on-field-soft: #BACBEC;
        --on-field-rule: rgba(186, 203, 236, 0.24);

        --cta-bg: #DCE7FB;
        --cta-bg-hover: #C4D6F6;
        --cta-ink: #0E1A34;

        --rule-red: #F87171;
        --credit-on-field: #FCA5A5;
    }
}

/* The wordmark face carries the product name and nothing else (One Family Rule).
   Everything else on this site is Heebo. */
@font-face {
    font-family: CACNormHeavy;
    src: url("fonts/CACNormHeavy.ttf") format("truetype");
    font-weight: 400 900;
    font-display: swap;
}

/* ---------------------------------------------------------------------------
   2. RESET
   --------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

/* The masthead is sticky, so an anchor jump would otherwise land its target
   underneath it. Every element that can be linked to keeps the bar's height
   plus its floating gap clear above it. */
[id] { scroll-margin-top: 92px; }

body {
    margin: 0;
    background: var(--paper);
    color: var(--text);
    font-family: var(--face);
    font-size: var(--t-body);
    line-height: 1.6;
    font-weight: 400;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; }
button { font: inherit; color: inherit; }

/* The focus ring is the same promise the product makes: 2px accent, 2px offset,
   on :focus-visible, everywhere, no exceptions. */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.on-field :focus-visible,
.sheet--field :focus-visible,
.sheet--deep :focus-visible { outline-color: var(--accent-bright); }

/* Skip link — the first tab stop on every page. */
.skip {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    background: var(--paper);
    color: var(--accent-press);
    padding: var(--s-2) var(--s-3);
    font-weight: 700;
}
.skip:focus { left: var(--s-3); top: var(--s-3); }

/* ---------------------------------------------------------------------------
   3. STRUCTURE
   A sheet is a full-bleed horizontal band of the document. There are no cards
   on this site: a sheet either sits on paper or on the Ledger Blue field, and
   rules separate what borders would otherwise box.
   --------------------------------------------------------------------------- */
.sheet {
    padding: var(--s-7) var(--s-4);
    position: relative;
}
.sheet--tight { padding-block: var(--s-6); }

.sheet--field {
    background: var(--field);
    color: var(--on-field);
}
.sheet--deep {
    background: var(--field-deep);
    color: var(--on-field);
}
.sheet--field a:not(.btn),
.sheet--deep a:not(.btn) { color: var(--on-field); }

.wrap {
    max-width: var(--wrap);
    margin-inline: auto;
    width: 100%;
}
.wrap--narrow { max-width: 760px; }

/* ---------------------------------------------------------------------------
   4. TYPE
   --------------------------------------------------------------------------- */

/* The eyebrow is the product's page-header signature, inherited here so the
   site and the app open the same way: uppercase label, accent dot, then title. */
.eyebrow {
    display: flex;
    align-items: center;
    gap: var(--s-1);
    font-size: var(--t-label);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent-600);
    margin: 0 0 var(--s-3);
}
.eyebrow::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.14);
    flex: none;
}
/* The eyebrow TEXT takes the lighter step, not --accent-bright: at 0.72rem it is small text, and
   --accent-bright on --field measures 4.07:1, which is below the 4.5:1 floor. --accent-line reads
   at 7.1:1 and is still unmistakably of the accent family. The DOT keeps --accent-bright — it is a
   graphic, where 3:1 applies. */
.sheet--field .eyebrow,
.sheet--deep .eyebrow { color: var(--accent-line); }
.sheet--field .eyebrow::before,
.sheet--deep .eyebrow::before {
    background: var(--accent-bright);
    box-shadow: 0 0 0 4px rgba(96, 165, 250, 0.2);
}

.display {
    font-size: var(--t-display);
    font-weight: 800;
    line-height: 1.03;
    letter-spacing: -0.03em;
    text-wrap: balance;
    color: var(--ink);
    margin: 0;
}
.sheet--field .display,
.sheet--deep .display { color: var(--on-field); }

.h2 {
    font-size: var(--t-h2);
    font-weight: 800;
    line-height: 1.12;
    letter-spacing: -0.02em;
    text-wrap: balance;
    color: var(--ink);
}
.sheet--field .h2,
.sheet--deep .h2 { color: var(--on-field); }

.h3 {
    font-size: var(--t-h3);
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--ink);
}
.sheet--field .h3,
.sheet--deep .h3 { color: var(--on-field); }

.lead {
    font-size: var(--t-lead);
    line-height: 1.5;
    color: var(--strong);
    max-width: 62ch;
}
.sheet--field .lead,
.sheet--deep .lead { color: var(--on-field-soft); }

/* Body copy holds a 65–75ch measure. */
.prose { max-width: 68ch; }
.prose p + p { margin-top: var(--s-3); }
.sheet--field .prose,
.sheet--deep .prose { color: var(--on-field-soft); }

.small {
    font-size: var(--t-small);
    color: var(--strong);
}
.sheet--field .small,
.sheet--deep .small { color: var(--on-field-soft); }

/* A caption that names a demonstration as a demonstration. Every illustrative
   figure on this site carries one — PRODUCT.md's no-fabricated-proof rule means
   example data must never be mistakable for a customer's. */
.synthetic {
    font-size: 0.8125rem;
    letter-spacing: 0.02em;
    color: var(--muted);
}
.sheet--field .synthetic,
.sheet--deep .synthetic { color: var(--on-field-soft); opacity: 0.85; }

/* ---------------------------------------------------------------------------
   5. LEDGER MARKS
   The vocabulary an accountant reads without being taught: column heads ruled
   underneath, figures in tabular lining numerals, a single rule above a total
   and a DOUBLE rule beneath it, red for the credit side.
   --------------------------------------------------------------------------- */
.fig {
    font-variant-numeric: tabular-nums lining-nums;
    font-feature-settings: "tnum" 1, "lnum" 1;
    text-align: right;
    white-space: nowrap;
}
.credit { color: var(--rule-red); }
/* The credit ink lifted for the blue field. --danger-border is the product's own
   light-red step (theme.css); on --field it reads at ~8:1. */
.sheet--field .credit,
.sheet--deep .credit { color: var(--credit-on-field); }

.colhead {
    font-size: var(--t-label);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    padding-bottom: var(--s-1);
    border-bottom: 1px solid var(--line-firm);
}
.sheet--field .colhead,
.sheet--deep .colhead {
    color: var(--on-field-soft);
    border-bottom-color: var(--on-field-rule);
}

.rule {
    border: 0;
    border-top: 1px solid var(--line);
    margin: 0;
}
.rule--firm { border-top-color: var(--line-firm); }
.sheet--field .rule,
.sheet--deep .rule { border-top-color: var(--on-field-rule); }

/* The double rule. A total is closed with it in every set of published accounts,
   and nothing else on this site uses it. */
.rule--double {
    border: 0;
    border-top: 1px solid var(--rule-red);
    border-bottom: 1px solid var(--rule-red);
    height: 3px;
    margin: 0;
}
.sheet--field .rule--double,
.sheet--deep .rule--double {
    border-top-color: var(--accent-bright);
    border-bottom-color: var(--accent-bright);
}

/* ---------------------------------------------------------------------------
   6. THE SCHEDULE
   The site's list form, used wherever a lesser page would reach for a grid of
   identical cards. It is a ruled schedule: label left, definition centre,
   reference right — the shape a statement note actually takes.
   --------------------------------------------------------------------------- */
.schedule { border-top: 1px solid var(--line-firm); }
.sheet--field .schedule,
.sheet--deep .schedule { border-top-color: var(--on-field-rule); }

.schedule__row {
    display: grid;
    grid-template-columns: minmax(0, 15rem) minmax(0, 1fr) auto;
    gap: var(--s-3) var(--s-5);
    align-items: baseline;
    padding: var(--s-4) 0;
    border-bottom: 1px solid var(--line);
}
.sheet--field .schedule__row,
.sheet--deep .schedule__row { border-bottom-color: var(--on-field-rule); }

.schedule__name {
    font-weight: 700;
    color: var(--ink);
    letter-spacing: -0.01em;
    font-size: var(--t-body);
}
.sheet--field .schedule__name,
.sheet--deep .schedule__name { color: var(--on-field); }

.schedule__note { color: var(--text); }
.sheet--field .schedule__note,
.sheet--deep .schedule__note { color: var(--on-field-soft); }

.schedule__ref {
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--muted);
    font-variant-numeric: tabular-nums lining-nums;
}

/* A live row tints rather than growing a coloured bar down its edge — a thick
   accent border on a list item is the decoration this direction refuses.

   ONLY ROWS THAT ACTUALLY GO SOMEWHERE TINT. `:has(a)` is doing real work here:
   a tint on a row whose only link is a few words inside it promises a click
   target across the whole line that is not there, and the pointer lands on dead
   space. Rows with no link stay inert, which is honest.

   `:focus-within` gives the keyboard the same signal the mouse gets — without
   it, tabbing through a schedule highlights nothing but the small link itself.
   It sits outside the hover media query on purpose: keyboard users exist on
   touch devices too. */
/* Square corners on purpose: this is a band across a ruled schedule, and a
   rounded pill sitting on hairline rules reads as a chip that wandered in from
   another design. */
.schedule__row {
    margin-inline: calc(var(--s-3) * -1);
    padding-inline: var(--s-3);
    transition: background-color 180ms var(--ease-out);
}

.schedule__row:has(a):focus-within { background: var(--accent-soft); }

.sheet--field .schedule__row:has(a):focus-within,
.sheet--deep .schedule__row:has(a):focus-within { background: rgba(255, 255, 255, 0.055); }

@media (hover: hover) and (pointer: fine) {
    .schedule__row:has(a):hover { background: var(--accent-soft); }

    .sheet--field .schedule__row:has(a):hover,
    .sheet--deep .schedule__row:has(a):hover { background: rgba(255, 255, 255, 0.055); }
}
/* Same reason as the eyebrow: 0.8125rem is small text, so it takes the 7.1:1 step. */
.sheet--field .schedule__ref,
.sheet--deep .schedule__ref { color: var(--accent-line); }

@media (max-width: 760px) {
    .schedule__row {
        grid-template-columns: 1fr auto;
        gap: var(--s-1) var(--s-3);
    }
    .schedule__note { grid-column: 1 / -1; }
}

/* ---------------------------------------------------------------------------
   6b. PLATES — a framed photograph with its caption
   The site's only framed object. Everything else sits directly on the page; a
   photograph earns a frame because it brings its own edges and needs separating
   from the paper it lands on.

   HISTORY, so nobody rebuilds it: this began as a reserved-space device holding
   room for product screenshots, with crop marks and an "awaiting artwork" state.
   The owner dropped that idea — the site shows no screenshots — so everything
   except the parts a real photograph uses has been removed.
   --------------------------------------------------------------------------- */
.plate { margin: 0; }

.plate__area {
    position: relative;
    aspect-ratio: 16 / 10;
    background: var(--accent-soft);
    border-radius: var(--r-lg);
    overflow: hidden;
}
.sheet--field .plate__area,
.sheet--deep .plate__area { background: rgba(255, 255, 255, 0.06); }

.plate__area > img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }

.plate figcaption {
    margin-top: var(--s-2);
    font-size: 0.8125rem;
    color: var(--muted);
}
.sheet--field .plate figcaption,
.sheet--deep .plate figcaption { color: var(--on-field-soft); }

/* ---------------------------------------------------------------------------
   7. CONTROLS
   Filled controls deepen on hover, never brighten — the product's rule.
   --------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s-1);
    padding: 0.85rem 1.4rem;
    border-radius: 9px;
    border: 1px solid transparent;
    font-size: var(--t-small);
    font-weight: 700;
    letter-spacing: 0.01em;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 160ms var(--ease-out),
                border-color 160ms var(--ease-out),
                color 160ms var(--ease-out),
                transform 160ms var(--ease-out);
}
.btn:active { transform: scale(0.97); }

.btn--primary {
    background: var(--accent-press);
    color: var(--on-accent);
}
.btn--ghost {
    background: var(--paper);
    border-color: var(--line-firm);
    color: var(--strong);
}
/* The light control on the blue field. Uses its own tokens, not --paper: see the
   note beside --cta-bg. It stays light in dark mode so the call to action keeps
   popping off the field instead of sinking into it. */
.btn--paper {
    background: var(--cta-bg);
    color: var(--cta-ink);
}
.btn--outline {
    background: transparent;
    border-color: var(--on-field-rule);
    color: var(--on-field);
}

@media (hover: hover) and (pointer: fine) {
    .btn--primary:hover { background: var(--accent-deep); }
    /* --accent-soft, not a literal near-white: in dark mode a #f8fafc hover would
       flash a near-white slab on a dark button. */
    .btn--ghost:hover { background: var(--accent-soft); color: var(--ink); }
    .btn--paper:hover { background: var(--cta-bg-hover); }
    .btn--outline:hover { border-color: var(--on-field-soft); background: rgba(255, 255, 255, 0.08); }
}

/* A text link that reads as a reference in the document, not a button. */
.link {
    color: var(--accent-press);
    font-weight: 700;
    text-decoration: none;
    border-bottom: 1px solid var(--accent-line);
    padding-bottom: 1px;
    transition: border-color 160ms var(--ease-out), color 160ms var(--ease-out);
}
.sheet--field .link,
.sheet--deep .link {
    color: var(--on-field);
    border-bottom-color: var(--accent-bright);
}
@media (hover: hover) and (pointer: fine) {
    .link:hover { border-bottom-color: currentColor; }
}

/* ---------------------------------------------------------------------------
   8. THE WORDMARK
   --------------------------------------------------------------------------- */
.mark {
    font-family: var(--face-mark);
    font-size: var(--t-mark);
    letter-spacing: 0.01em;
    line-height: 1;
    color: var(--ink);
    text-decoration: none;
    display: inline-flex;
    align-items: baseline;
    gap: 0.28em;
    white-space: nowrap;
}
.mark em {
    font-style: normal;
    color: var(--accent);
}
.on-field .mark,
.sheet--field .mark,
.sheet--deep .mark { color: var(--on-field); }
.on-field .mark em,
.sheet--field .mark em,
.sheet--deep .mark em { color: var(--accent-bright); }

/* ---------------------------------------------------------------------------
   9. MOTION
   The site has ONE authored moment — the posting trace drawing itself — and a
   quiet reveal grammar around it. Everything here is PROGRESSIVE ENHANCEMENT:
   the hidden start states are scoped to `html.js`, a class set by an inline
   script before first paint. If the script never runs, or fails, or the visitor
   blocks it, every word on this site is visible at full opacity. That is not a
   nicety — low bandwidth is a product REQUIREMENT (PRODUCT.md), and content
   that depends on JavaScript to become visible is content that can vanish.
   --------------------------------------------------------------------------- */

/* Cross-document view transitions. Fifteen static pages that share a masthead
   and a footer; without this every navigation is a white flash, with it the
   chrome holds still while the document changes underneath. Browsers that do
   not support it simply navigate as before. */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation-duration: 140ms; }
::view-transition-new(root) { animation-duration: 220ms; }

/* The masthead and footer persist across the transition instead of cross-fading
   with the page body. */
.site-header { view-transition-name: site-header; }
.site-footer { view-transition-name: site-footer; }

@media (prefers-reduced-motion: no-preference) {
    /* Scroll reveal. Enters from an already-settled default — a short rise and
       a fade, never a scale from nothing. */
    html.js .reveal {
        opacity: 0;
        transform: translateY(16px);
    }

    html.js .reveal.is-in {
        opacity: 1;
        transform: none;
        transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out);
        transition-delay: var(--reveal-delay, 0ms);
    }
}

/* Reduced motion means fewer and gentler animations, not none: the opacity
   change still aids comprehension, the movement goes. */
@media (prefers-reduced-motion: reduce) {
    html.js .reveal { opacity: 0; }
    html.js .reveal.is-in {
        opacity: 1;
        transform: none;
        transition: opacity 240ms ease;
    }

    @view-transition { navigation: none; }
}

/* ---------------------------------------------------------------------------
   9b. THE MODE TRANSITION
   Opt-in, and live only for the ~420ms site.js keeps `.theme-anim` on <html>.

   Permanent colour transitions would be wrong twice over: every page load would
   fade its own colours in as the stylesheet lands, which reads as a rendering
   fault rather than a design; and a standing transition on `color` makes every
   hover feel a beat late.

   The broad selector and !important are the point — for the length of the swap
   this must beat each component's own transition, then get out of the way
   completely. site.js does not add the class at all under reduced motion: the
   mode still changes, it simply arrives rather than travels. A theme switch is
   exactly the kind of full-screen colour movement that provokes symptoms in
   someone with a vestibular disorder.
   --------------------------------------------------------------------------- */
html.theme-anim,
html.theme-anim *,
html.theme-anim *::before,
html.theme-anim *::after {
    transition:
        background-color var(--theme-swap) ease,
        border-color var(--theme-swap) ease,
        color var(--theme-swap) ease,
        fill var(--theme-swap) ease,
        stroke var(--theme-swap) ease,
        box-shadow var(--theme-swap) ease !important;
    transition-delay: 0s !important;
}

/* Photographs are exempt: fading a picture's colours during a theme change
   looks like a decoding error, not a transition. */
html.theme-anim img,
html.theme-anim iframe {
    transition: none !important;
}

/* ---------------------------------------------------------------------------
   9c. THE MODE TOGGLE
   Hidden until `html.js` is present, because a control that cannot work without
   JavaScript should not be offered. Two glyphs live inside it and CSS picks
   which to show, so changing mode costs no re-render on a statically rendered
   page: the moon means "go dark", the sun means "go light".
   --------------------------------------------------------------------------- */
.theme-toggle { display: none; }

html.js .theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex: none;
    padding: 0;
    border: 1px solid var(--line-firm);
    border-radius: var(--r-sm);
    background: var(--paper);
    color: var(--strong);
    cursor: pointer;
    transition: background-color 160ms var(--ease-out),
                border-color 160ms var(--ease-out),
                color 160ms var(--ease-out),
                transform 160ms var(--ease-out);
}

.theme-toggle:active { transform: scale(0.94); }

@media (hover: hover) and (pointer: fine) {
    .theme-toggle:hover {
        background: var(--accent-soft);
        border-color: var(--accent-line);
        color: var(--accent-press);
    }
}

.theme-toggle svg { width: 17px; height: 17px; display: block; }

/* Light mode offers the moon; dark mode offers the sun. */
.theme-toggle .tt-sun { display: none; }
.theme-toggle .tt-moon { display: block; }

[data-theme="dark"] .theme-toggle .tt-sun { display: block; }
[data-theme="dark"] .theme-toggle .tt-moon { display: none; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme]) .theme-toggle .tt-sun { display: block; }
    :root:not([data-theme]) .theme-toggle .tt-moon { display: none; }
}

/* ---------------------------------------------------------------------------
   10. PRINT
   The jotter is a printed piece and this site is its companion; a visitor who
   prints a page should get the document, not a screenshot of a website.
   --------------------------------------------------------------------------- */
@media print {
    .sheet--field,
    .sheet--deep {
        background: #fff !important;
        color: #000 !important;
    }
    .sheet--field *,
    .sheet--deep * { color: #000 !important; }
    .site-header,
    .site-footer nav,
    .btn { display: none !important; }
    .sheet { padding: var(--s-4) 0; break-inside: avoid; }
    a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.75em; }
}
