@font-face{font-family:'Abril Fatface';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/abril-fatface-400.woff2') format('woff2')}
@font-face{font-family:'Merriweather';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/merriweather-400.woff2') format('woff2')}
@font-face{font-family:'Merriweather';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/merriweather-700.woff2') format('woff2')}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/jetbrains-mono-500.woff2') format('woff2')}

:root{
  /* Warm paper, not white. Every ink on it is measured AAA (7:1+). */
  --paper:#FBF6EA;
  --paper-2:#F2ECDE;
  --card:#FFFCF4;       /* a leaf laid on the paper — lifts, never glares */
  --ink:#1A1712;
  --muted:#5A5243;      /* 7.15:1 */
  --rule:#DCD2BC;
  --red:#8F2D07;        /* 7.65:1 — small text, labels, keywords */
  --red-big:#C1440E;    /* 4.75:1 — display sizes only, where 3:1 applies */
  --lagoon:#1F4B47;     /* 9.03:1 */

  --display:'Abril Fatface',Georgia,serif;
  --body:'Merriweather',Georgia,serif;
  --mono:'JetBrains Mono',ui-monospace,monospace;

  --bar-h:7.8rem;
  --pad:clamp(1.25rem,5vw,4.5rem);
}

*,*::before,*::after{box-sizing:border-box}

html,body{height:100%}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--body);
  /* 16-18px. An earlier scale ran clamp(1.16rem,...,1.3rem) — 18.5-20.8px —
     which on a freelancer's laptop reads as a large-print edition. Stripe,
     Linear and Vercel all sit at 16px; editorial sites run 18px for article
     body and 15-16px for everything that is not prose. */
  font-size:clamp(1rem,0.98rem + 0.2vw,1.125rem);
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  overflow:hidden;               /* the page itself never scrolls */
}

/* ---- The deck: one screen per section, snapping ---- */
.deck{
  height:100dvh;
  overflow-y:scroll;
  /* proximity, not mandatory. Mandatory fights trackpad momentum and forces a
     full-viewport jump on every flick, which punishes the scan-and-compare
     reading that anyone evaluating a paid tool actually does. */
  scroll-snap-type:y proximity;
  scroll-behavior:smooth;
  scrollbar-width:none;
}
.deck::-webkit-scrollbar{display:none}

.panel{
  min-height:100dvh;
  /*
   * min-height only. NOT max-height, and NOT overflow-y.
   *
   * The pair used to be `max-height:100dvh; overflow-y:auto`, on the reasoning
   * that a panel outgrowing a phone should scroll itself rather than the page.
   * What that actually built was seven nested scroll containers inside a
   * scroll-snap deck, every one with its scrollbar hidden.
   *
   * Scrolling slowly over such a panel sends the wheel to the INNER scroller
   * first. It creeps through its own overflow with no scrollbar to explain
   * why, and only then does the deck move and snap. That reads as lag, and as
   * text that will not advance to the next section — because it is not
   * advancing, it is scrolling inside the section you are already on.
   *
   * Measured at 1920×975 only `#s-how` overflowed, by 15px. At 800px high that
   * became 102px, and at 640px — an ordinary laptop once browser chrome is
   * subtracted — FOUR panels overflowed, `#s-how` by 182px.
   *
   * Growing is the honest behaviour: a panel that needs more room takes it,
   * the deck scrolls continuously through it, and proximity snapping picks up
   * again at the next boundary. Panels that fit are unchanged, because
   * min-height still makes them exactly one screen.
   */
  scroll-snap-align:start;
  display:grid;
  align-content:center;
  gap:1.5rem;
  padding:calc(var(--bar-h) + 1.5rem) var(--pad) 2.5rem;
}

/* ---- Top bar: the section index, and the 47 years ---- */
.topbar{
  position:fixed;
  inset:0 0 auto 0;
  z-index:20;
  /*
   * OPAQUE behind the bar's own content. The fade lives below it, in ::after.
   *
   * This was `linear-gradient(var(--paper) 64%, transparent)` — opaque for the
   * first 64% of the bar and fading out over the rest. The bar is 96px tall, so
   * that put the transparent zone at roughly 61–96px, and the bar's SECOND ROW
   * — the timeline rule with "Four platforms" and "One number" — sits at about
   * 75–96px. Inside its own transparency.
   *
   * Page text scrolling past therefore passed BEHIND the bar's own labels and
   * collided with them: "ANNUAL" from the pricing panel printed on top of
   * "Four platforms". The fade was meant to dissolve content below the bar and
   * was instead dissolving it behind the bar's writing.
   *
   * Worst at a dark-to-light boundary, which is where the contrast makes the
   * collision unmissable — but it happened at every boundary.
   */
  background:var(--paper);
  padding:0.75rem var(--pad) 0;
}

/*
 * The dissolve, moved to where it was always meant to be: BELOW the bar.
 *
 * Same effect — content does not end at a hard line — with nothing of the bar's
 * own on top of it, so there is nothing for passing text to collide with.
 */
.topbar::after{
  content:'';
  position:absolute;
  left:0;
  right:0;
  top:100%;
  height:2.25rem;
  background:linear-gradient(var(--paper),rgba(251,246,234,0));
  pointer-events:none;
}
/* At 16px the keywords no longer fit beside the wordmark on a phone, so they
   take their own row there. Squeezing them back onto one line is what
   produced 11px labels in the first place. */
.topbar-row{
  display:flex;
  align-items:center;
  gap:0.2rem 1.5rem;
  flex-wrap:wrap;
}
.mark{
  font-family:var(--display);
  font-size:1.5rem;
  letter-spacing:0.02em;
  color:var(--ink);
  text-decoration:none;
  flex:none;
}
.mark span{color:var(--red-big)}

/* The one filled control in the navbar, so signing in is the obvious action. */
.signin{
  flex:none;
  display:inline-flex;
  align-items:center;
  min-height:44px;
  padding:0.5rem 1.15rem;
  background:var(--red);
  border:2px solid var(--red);
  color:var(--paper);            /* 7.4:1 */
  font-family:var(--mono);
  font-size:0.85rem;
  font-weight:500;
  letter-spacing:0.08em;
  text-transform:uppercase;
  text-decoration:none;
  transition:background .2s ease,border-color .2s ease;
}
.signin:hover{background:var(--ink);border-color:var(--ink)}
.signin:focus-visible{outline:2px solid var(--lagoon);outline-offset:3px}

/* The keywords. On a narrow phone this strip scrolls sideways — nav, never page. */
.keys{
  display:flex;
  flex:0 1 auto;
  gap:1.7rem;
  overflow-x:auto;
  scrollbar-width:none;
  /* The auto left margin is what pushes the keywords across to sit beside
     Sign in. It has to be in the shorthand: a separate margin-left:auto above
     this line was silently cancelled by the `margin:0` that followed it. */
  margin:0 0 0 auto;
  padding:0;
  list-style:none;
  -webkit-overflow-scrolling:touch;
}
.keys::-webkit-scrollbar{display:none}
.keys a{
  font-family:var(--mono);
  font-size:0.84rem;
  font-weight:500;
  letter-spacing:0.09em;
  text-transform:uppercase;
  color:var(--muted);
  text-decoration:none;
  white-space:nowrap;
  display:flex;
  align-items:center;
  min-height:44px;               /* real touch target */
  transition:color .2s ease;
}
.keys a:hover{color:var(--ink)}
.keys a[aria-current="true"]{color:var(--red)}
.keys a:focus-visible,.mark:focus-visible,.btn:focus-visible{
  outline:2px solid var(--lagoon);
  outline-offset:3px;
}

/* The timeline. The marker is the active section — the nav IS the 45 years. */
.timeline{position:relative;height:2.2rem}
.timeline-rule{position:absolute;top:0.42rem;left:0;right:0;height:1px;background:var(--rule)}
.bead{
  position:absolute;top:0;
  width:0.64rem;height:0.64rem;
  border-radius:50%;
  background:var(--red-big);
  transform:translateX(-50%);
  transition:left .45s cubic-bezier(.6,.05,.2,1);
  box-shadow:0 0 0 4px var(--paper);
}
.years{
  position:absolute;top:0.85rem;left:0;right:0;
  display:flex;justify-content:space-between;
  font-family:var(--mono);
  font-size:0.8rem;
  letter-spacing:0.1em;
  color:var(--muted);
  font-variant-numeric:tabular-nums;
}

/* ---- Type ---- */
.eyebrow{
  font-family:var(--mono);
  font-size:0.82rem;font-weight:500;
  letter-spacing:0.14em;text-transform:uppercase;
  color:var(--red);margin:0;
}
.display{
  font-family:var(--display);font-weight:400;
  font-size:clamp(3.1rem,15vw,8.5rem);
  line-height:0.86;letter-spacing:-0.02em;
  margin:0;text-wrap:balance;
}
.display .quiet{color:var(--muted);display:block}
h2.title{
  font-family:var(--display);font-weight:400;
  font-size:clamp(2.1rem,8vw,4rem);
  line-height:0.98;margin:0;text-wrap:balance;
}
.lede{margin:0;max-width:34ch;color:#3B342A}
.fine{
  font-family:var(--mono);font-size:0.82rem;
  letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);margin:0;
}

/* ---- Actions: underlined, not boxed. No rounded pills anywhere. ---- */
.actions{display:flex;flex-wrap:wrap;gap:1.7rem;margin-top:0.4rem}
.btn{
  font-family:var(--mono);font-size:0.9rem;font-weight:500;
  letter-spacing:0.08em;text-transform:uppercase;
  color:var(--ink);text-decoration:none;
  border-bottom:2px solid var(--red-big);
  min-height:44px;display:inline-flex;align-items:flex-end;
  padding-bottom:0.35rem;
  transition:color .2s ease,border-color .2s ease;
}
.btn:hover{color:var(--red)}
.btn.quiet{border-bottom-color:var(--rule);color:var(--muted)}
.btn.quiet:hover{color:var(--ink);border-bottom-color:var(--muted)}

/* ---- Ruled list: the contents page of a printed souvenir ---- */
.ruled{list-style:none;margin:0.5rem 0 0;padding:0;max-width:48ch}
/* A fixed key column, not `auto`. With `auto` each row sized its own first
   column, so PASSPHRASE and INVITED pushed their text to different left edges
   and the list read as unrelated rows rather than one index. */
.ruled li{
  display:grid;grid-template-columns:8.5rem 1fr;
  gap:0.35rem 1.5rem;padding:1.1rem 0;
  border-top:1px solid var(--rule);
}
@media (max-width:34rem){
  .ruled li{grid-template-columns:1fr}
}
.ruled li:last-child{border-bottom:1px solid var(--rule)}
.ruled .k{
  font-family:var(--mono);font-size:0.82rem;
  letter-spacing:0.1em;text-transform:uppercase;
  color:var(--lagoon);padding-top:0.4rem;
}
.ruled .v{font-size:1.15rem;color:#3B342A;margin:0}
.ruled .v strong{color:var(--ink);font-weight:700;display:block}

/* ---- The date, set like a title page ---- */
.datestack{display:grid;gap:0.25rem}
.datestack .big{
  font-family:var(--display);
  font-size:clamp(3.4rem,17vw,9rem);
  line-height:0.82;font-variant-numeric:tabular-nums;margin:0;
}
.datestack .big em{font-style:normal;color:var(--red-big)}
.count{
  font-family:var(--mono);font-size:1.05rem;
  letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);font-variant-numeric:tabular-nums;
}

/* ---- One inverted panel, so the deck has a change of air ---- */
.panel.ink{background:var(--ink);color:var(--paper)}
.panel.ink .lede,.panel.ink .ruled .v{color:#D8CFBC}
.panel.ink .eyebrow{color:#E4762F}
.panel.ink .fine,.panel.ink .count{color:#A99C84}
.panel.ink .ruled li{border-color:#3A342A}
.panel.ink .ruled .k{color:#7FB3AD}
.panel.ink .ruled .v strong,.panel.ink .btn{color:var(--paper)}
.panel.ink .datestack .big em{color:#E4762F}
.panel.ink .btn.quiet{color:#A99C84;border-bottom-color:#3A342A}

@media (min-width:52rem){
  :root{--bar-h:5.8rem}
  .keys{flex:0 1 auto}
  .panel{gap:1.9rem}
  .split{
    display:grid;grid-template-columns:1.15fr 1fr;
    gap:clamp(2rem,6vw,6rem);align-items:center;
  }
}

@media (prefers-reduced-motion:reduce){
  .deck{scroll-behavior:auto}
  .bead{transition:none}
}

/* ---- Forms ---------------------------------------------------------------
   Labels are mono and lagoon, exactly like the keys in a ruled list, because
   they do the same job: naming the thing beside them. */
.field{display:grid;gap:0.45rem;margin:0 0 1.7rem}
.field label{
  font-family:var(--mono);
  font-size:0.82rem;font-weight:500;
  letter-spacing:0.1em;text-transform:uppercase;
  color:var(--lagoon);
}
.field .hint{margin:0;font-size:0.95rem;color:var(--muted)}
.field input{
  width:100%;
  min-height:56px;                 /* well over the 44px floor */
  padding:0.7rem 0.9rem;
  border:2px solid var(--ink);
  border-radius:0;                 /* print has no rounded corners */
  background:var(--paper);
  color:var(--ink);
  font-family:var(--body);
  font-size:1.1rem;
}
.field input:focus-visible{outline:2px solid var(--lagoon);outline-offset:2px}

/* Held to the same measure as the lede above it. Left to fill the panel, a
   single email box would stretch most of a desktop screen. */
.signin-form{max-width:30rem;margin:0.4rem 0 0}

/* The submit. Same filled block as the navbar's Sign in, so the page's one
   action looks like the action that brought you here. */
.btn-solid{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:56px;padding:0.6rem 1.6rem;
  background:var(--red);border:2px solid var(--red);
  color:var(--paper);
  font-family:var(--mono);font-size:0.9rem;font-weight:500;
  letter-spacing:0.08em;text-transform:uppercase;
  text-decoration:none;cursor:pointer;
  transition:background .2s ease,border-color .2s ease;
}
.btn-solid:hover{background:var(--ink);border-color:var(--ink)}
.btn-solid:focus-visible{outline:2px solid var(--lagoon);outline-offset:3px}

/* The back link in the bar, where Sign in sits on the other pages.
   It carries the same padding and an invisible border so its box is exactly
   as tall as that button: without them the bar was 3px shorter here and the
   whole page sat 3px higher than the homepage. */
.barlink{
  flex:none;
  margin-left:auto;                /* far right, where Sign in is on index */
  display:inline-flex;align-items:center;min-height:44px;
  padding:0.5rem 0;
  border:2px solid transparent;
  font-family:var(--mono);font-size:0.82rem;font-weight:500;
  letter-spacing:0.09em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;
  transition:color .2s ease;
}
.barlink:hover{color:var(--ink)}
.barlink:focus-visible{outline:2px solid var(--lagoon);outline-offset:3px}

/* ---- Sign in: one centred column, and nothing else ------------------------
   The page has one job. Everything sits in the middle of the screen: the
   column is centred horizontally, the panel centres it vertically, and the
   text is centred within it. */
.auth .panel{padding-left:1.5rem;padding-right:1.5rem}

.auth-box{
  width:100%;
  max-width:27rem;
  margin:0 auto;
  text-align:center;
  display:grid;
  gap:1.1rem;
  justify-items:center;
}

.auth-box .display{font-size:clamp(3rem,7vw,4.4rem)}
.auth-box .lede{max-width:30ch;margin:0 auto}

.auth-box .signin-form{width:100%;max-width:none;margin:0.6rem 0 0}
.auth-box .field{text-align:left;margin-bottom:1.3rem}
.auth-box .btn-solid{width:100%}

/* The other ways in. Quiet text links, not a ruled list - a list of rows
   would weigh as much as the form it sits under. */
.auth-alt{
  display:grid;gap:0.7rem;
  margin:0.6rem 0 0;padding:1.4rem 0 0;
  border-top:1px solid var(--rule);
  width:100%;
}
.auth-alt a{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;
  font-family:var(--mono);font-size:0.82rem;font-weight:500;
  letter-spacing:0.06em;
  color:var(--muted);text-decoration:underline;text-underline-offset:4px;
  transition:color .2s ease;
}
.auth-alt a:hover{color:var(--red)}
.auth-alt a:focus-visible{outline:2px solid var(--lagoon);outline-offset:3px}

/* ---- Signed in: page links on row one, this page's sections on row two ----
   Signed out, the first row carries the keywords for the one public page.
   Signed in there are five pages to move between, so the pages take that row
   and the page's own sections drop underneath. Same mono index either way. */
body.member{--bar-h:7.2rem}

.pages{
  display:flex;
  gap:1.4rem;
  margin-left:auto;
  min-width:0;
  overflow-x:auto;
  scrollbar-width:none;
}
.pages::-webkit-scrollbar{display:none}

.pages a{
  flex:none;
  display:flex;align-items:center;
  min-height:44px;
  font-family:var(--mono);
  font-size:0.82rem;font-weight:500;
  letter-spacing:0.09em;text-transform:uppercase;
  white-space:nowrap;
  color:var(--muted);text-decoration:none;
  transition:color .2s ease;
}
.pages a:hover{color:var(--ink)}

/* Current page by colour AND an underline — never colour alone. */
.pages a[aria-current="page"]{
  color:var(--red);
  box-shadow:inset 0 -3px 0 var(--red);
}

/* Beats the auto margin on .barlink so the name sits right after the pages
   rather than both of them splitting the free space. */
.pages + .barlink{margin-left:1.5rem}

.topbar-sections{
  margin-top:0.2rem;
  padding-top:0.1rem;
  border-top:1px solid var(--rule);
}
.topbar-sections .keys{margin:0}

/* ---- Small pieces the member pages need ---------------------------------- */

/* A row's own action, e.g. "Change who can see this". */
.linklike{
  font-family:var(--mono);
  font-size:0.95rem;letter-spacing:0.04em;
  color:var(--muted);
  text-decoration:underline;text-underline-offset:3px;
}
.linklike:hover{color:var(--red)}

/* A ruled row whose whole width is a link. */
.ruled a.row{
  display:grid;grid-template-columns:subgrid;grid-column:1 / -1;
  gap:inherit;min-height:44px;
  color:inherit;text-decoration:none;
}
.ruled a.row:hover .v strong{color:var(--red)}
@supports not (grid-template-columns:subgrid){.ruled a.row{display:block}}

/* Nothing here yet — an invitation, never a dead end. */
.empty{
  border:1px dashed var(--rule);
  padding:2.4rem 1.6rem;
  text-align:center;
  display:grid;gap:0.9rem;justify-items:center;
}
.empty h2{font-family:var(--display);font-weight:400;font-size:2rem;margin:0}
.empty p{margin:0;max-width:38ch;color:var(--muted)}

/* State of a memory: who can see it. Text, never colour alone. */
.chip{
  display:inline-block;
  font-family:var(--mono);
  font-size:0.95rem;font-weight:500;
  letter-spacing:0.06em;text-transform:uppercase;
  color:var(--lagoon);
}
.chip-public{color:var(--red)}

/* The member's name in the bar, when it is the page you are on. */
.barlink[aria-current="page"]{
  color:var(--red);
  box-shadow:inset 0 -3px 0 var(--red);
}

/* ---- A centred column, for any page you type into -------------------------
   Same treatment as the sign-in page. A form pinned to the left edge of a
   1500px screen with nothing beside it reads as broken; centred, the page has
   a middle and the eye knows where to start.

   Kept separate from .auth-box rather than merged with it: sign-in is a single
   short form and holds a narrower measure, this has to fit ruled rows too. */
.centred{
  width:100%;
  max-width:32rem;
  margin:0 auto;
  text-align:center;
  display:grid;
  gap:1.1rem;
  justify-items:center;
}

.centred .display{font-size:clamp(3rem,7vw,4.4rem)}
.centred .title{font-size:clamp(2rem,4vw,2.8rem)}
.centred .lede{max-width:34ch;margin:0 auto}
.centred .signin-form{width:100%;max-width:none;margin:0.4rem 0 0}
.centred .field{text-align:left;margin-bottom:1.3rem}
.centred .btn-solid{width:100%}
.centred .actions{justify-content:center}

/* Rows stay left-aligned inside the centred column — centred list text is
   unreadable once a row runs to two lines. */
.centred .ruled{width:100%;max-width:none;text-align:left}

/* ---- Centred column, corrected ---------------------------------------------
   32rem was a measure for prose, and the ruled rows were living in it too: the
   value column came out about 280px and "Show it to the batch" wrapped into
   the line above. The column is now sized for the widest thing it holds, and
   the narrow things are held narrow individually. */
.centred{max-width:44rem}
.centred .signin-form{max-width:30rem;margin-inline:auto}
.centred .lede{max-width:36ch}

/* A row's action belongs on its own line. Inline, it read as the tail of the
   sentence before it and broke across two lines mid-phrase. */
.ruled .v .linklike{display:inline-block;margin-top:0.45rem}

/* ---- The right-hand pane ---------------------------------------------------
   What the section means, and where it stands. It is a margin note, not a
   panel: a hairline rule and space, no fill and no border box, so it reads as
   part of the printed page rather than as a widget stuck beside it.

   Below 64rem it drops under the content instead of squeezing both. */
.with-pane{display:grid;gap:clamp(2rem,5vw,4rem);align-items:start;width:100%}

@media (min-width:64rem){
  .with-pane{grid-template-columns:1fr 21rem}
  .pane{
    border-left:1px solid var(--rule);
    padding-left:clamp(1.5rem,2.5vw,2.5rem);
  }
}

.pane{display:grid;gap:1.2rem;align-content:start}

.pane h3{
  margin:0;
  font-family:var(--mono);
  font-size:0.82rem;font-weight:500;
  letter-spacing:0.12em;text-transform:uppercase;
  color:var(--lagoon);
}

.pane p{margin:0;font-size:0.95rem;color:var(--muted)}

/* The numbers. Tabular so the column of figures lines up. */
.figures{list-style:none;margin:0;padding:0;display:grid;gap:0}
.figures li{
  display:flex;justify-content:space-between;align-items:baseline;gap:1rem;
  border-top:1px solid var(--rule);
  padding:0.6rem 0;
  font-family:var(--mono);font-size:0.82rem;
  color:var(--muted);
}
.figures li:last-child{border-bottom:1px solid var(--rule)}
.figures b{font-weight:500;color:var(--ink);font-variant-numeric:tabular-nums}

/* ---- The flipbook preview, on the souvenir page ---------------------------
   Two facing pages, drawn rather than photographed: the book is not printed
   yet and a fake photograph would be a lie about what is in it. */
.book{
  width:100%;
  border:1px solid var(--rule);
  background:var(--card);
  display:grid;grid-template-columns:1fr 1fr;
}
.book-page{padding:0.9rem;display:grid;gap:0.6rem;align-content:start}
.book-page + .book-page{border-left:1px solid var(--rule)}
.book-slot{
  aspect-ratio:3/4;
  background:var(--paper-2);
  border:1px solid var(--rule);
  display:grid;place-items:center;
  font-family:var(--mono);font-size:0.82rem;
  letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);
}
.book-caption{
  font-family:var(--mono);font-size:0.82rem;
  letter-spacing:0.06em;
  color:var(--ink);
}
.book-caption span{display:block;color:var(--muted)}
.book-foot{
  display:flex;justify-content:space-between;gap:1rem;
  font-family:var(--mono);font-size:0.82rem;color:var(--muted);
  font-variant-numeric:tabular-nums;
}

/* The content column inside .with-pane needs its own vertical rhythm.
   As children of .panel these elements got its 1.5rem grid gap; wrapped in a
   plain div they got nothing, and since .display and .lede both carry
   margin:0 the descender of a 136px Didone landed on the line beneath it. */
.with-pane > :not(.pane){
  display:grid;
  gap:1.5rem;
  align-content:start;
  min-width:0;
}

/* ---- The pane, made readable ----------------------------------------------
   It was set at 1rem beside 20.8px body text, so it read as fine print rather
   than as part of the page. Contrast was never the problem — the muted ink is
   7.15:1 on paper — the size was. */
@media (min-width:64rem){
  .with-pane{grid-template-columns:1fr 24rem}
}

.pane{gap:1.4rem}
.pane h3{font-size:1.05rem;letter-spacing:0.1em}
.pane p{font-size:1.15rem;line-height:1.6}

.figures li{font-size:1.08rem;padding:0.7rem 0}

.book-caption,.book-foot,.book-slot{font-size:1.05rem}

/* ---- The souvenir spread, given room --------------------------------------
   The book was living in the same 24rem pane as a paragraph of text, which
   left each page about 170px wide — a thumbnail of a thing whose whole point
   is that you can see it. The souvenir page gets a wider second column, and
   the spread is drawn as a printed object: an outer frame, a margin inside it,
   and a spine down the middle. */
@media (min-width:64rem){
  .with-pane-wide{grid-template-columns:1fr 32rem}
}

.book{
  padding:0.55rem;                 /* the frame around the spread */
  background:var(--card);
  border:1px solid var(--rule);
  align-items:stretch;
}

.book-page{
  padding:1.2rem 1.1rem;
  gap:0.85rem;
}

/* The spine. Doubled deliberately — one rule reads as a table border, two
   close together read as the fold between two facing pages. */
.book-page + .book-page{
  border-left:1px solid var(--rule);
  box-shadow:inset 3px 0 0 -2px var(--rule);
}

.book-slot{
  aspect-ratio:4/5;
  background:var(--paper);
  border:1px solid var(--rule);
}

.book-caption{line-height:1.45}
.book-foot{padding-top:0.2rem}

/* ===========================================================================
   THE APP
   ---------------------------------------------------------------------------
   Everything above this line was built for a landing deck: four panels, one
   screen each, snapped. That is right for a page you read once and wrong for
   a page you work in. A transactions list is a document — it wants to scroll
   continuously, be searched with the browser's own find, and show a scrollbar
   so you know there is more.

   So the app keeps the paper, the type, the rules and the mono index, and
   drops the deck. `body.app` unpicks the snapping without touching the markup:
   the pages still declare `.deck` and `.panel`, so the keyword navbar built by
   app.js keeps working unchanged.
   ========================================================================== */

/* The viewport scrolls, not the body. `overflow:auto` on a height:100% body
   makes body its own scroll container, which leaves window.scrollY pinned at 0
   — and with it browser find-on-page, scroll restoration, :target anchors and
   the wheel over anything that isn't the body box. Release the height instead. */
body.app{height:auto;min-height:100%;overflow:visible}

body.app .deck{
  height:auto;
  overflow-y:visible;
  scroll-snap-type:none;
}

body.app .panel{
  min-height:0;
  max-height:none;
  overflow-y:visible;
  scroll-snap-align:none;
  align-content:start;
  padding-top:2.6rem;
  padding-bottom:2.6rem;
}

/* The bar is fixed, so the first section has to clear it itself. */
body.app .panel:first-child{padding-top:calc(var(--bar-h) + 1.6rem)}

/* A hairline between sections, the way a printed report separates its parts.
   Not a card, not a shadow — this system has no boxes. */
body.app .panel + .panel{border-top:1px solid var(--rule)}

/* ---- The tally: gross, fees, net -------------------------------------------
   The one thing the whole product exists to answer. Set like the date on a
   title page — figure large in the display face, its name small in mono
   beneath — and ruled into columns so the three read as one statement rather
   than three unrelated numbers.

   Abril Fatface has no tabular figures, so it is used only where numbers sit
   alone. Anything that has to line up vertically is mono. */
.tally{
  display:grid;
  grid-template-columns:1fr;
  border-top:1px solid var(--rule);
  border-bottom:1px solid var(--rule);
}
@media (min-width:44rem){
  .tally{grid-template-columns:repeat(3,1fr)}
  .tally-cell + .tally-cell{border-left:1px solid var(--rule);padding-left:clamp(1rem,2.5vw,2rem)}
}
.tally-cell{padding:1.4rem 0;display:grid;gap:0.3rem;align-content:start}
.tally-cell + .tally-cell{border-top:1px solid var(--rule)}
@media (min-width:44rem){
  .tally-cell + .tally-cell{border-top:0}
}
.tally-cell .k{
  font-family:var(--mono);font-size:0.82rem;font-weight:500;
  letter-spacing:0.12em;text-transform:uppercase;
  color:var(--lagoon);
}
.tally-cell .n{
  font-family:var(--display);font-weight:400;
  font-size:clamp(2.6rem,7vw,4.2rem);
  line-height:0.9;letter-spacing:-0.01em;
  color:var(--ink);
}
/* Money leaving is set in the same red the rest of the system uses for
   emphasis — ledgers have always written what is owed in red ink. */
.tally-cell .n.out{color:var(--red-big)}
.tally-cell .sub{
  font-family:var(--mono);font-size:0.82rem;
  letter-spacing:0.06em;color:var(--muted);
  font-variant-numeric:tabular-nums;
}

/* ---- The bar chart ---------------------------------------------------------
   Drawn, not plotted. No library, no SVG, no fills that would put a block of
   colour on the paper: each month is a hairline-ruled column of paper-2, and
   the figure sits under it in mono. Every bar carries its value as text, so
   the chart is readable with the stylesheet off and by a screen reader —
   the height is decoration, the number is the data. */
.chart{
  display:grid;
  grid-auto-flow:column;
  grid-auto-columns:1fr;
  align-items:end;
  gap:clamp(0.3rem,1.2vw,0.8rem);
  height:clamp(9rem,22vh,14rem);
  margin:0;padding:0;list-style:none;
  border-bottom:1px solid var(--ink);
}
/* `1fr auto`, not `align-content:end`. With content-sized rows the bar's
   percentage height had no definite track to resolve against and collapsed to
   its 2px minimum — the chart drew as twelve hairlines. The 1fr row gives the
   percentage something real to measure, and align-items:end stands the bar on
   the axis. */
.chart li{
  display:grid;grid-template-rows:1fr auto;align-items:end;
  gap:0.5rem;height:100%;text-align:center;
}
.chart .bar{
  background:var(--paper-2);
  border:1px solid var(--rule);
  border-bottom:0;
  min-height:2px;
}
.chart li[aria-current="true"] .bar{background:var(--red-big);border-color:var(--red-big)}
.chart .m{
  font-family:var(--mono);font-size:0.95rem;
  letter-spacing:0.06em;text-transform:uppercase;
  color:var(--muted);
}
.chart-figures{
  display:flex;justify-content:space-between;
  font-family:var(--mono);font-size:0.82rem;
  color:var(--muted);font-variant-numeric:tabular-nums;
  margin:0.7rem 0 0;
}

/* ---- Sync state ------------------------------------------------------------
   Named, never coloured alone — the same rule the navbar follows. The word is
   the state; the colour only agrees with it. */
.state{
  font-family:var(--mono);font-size:0.95rem;font-weight:500;
  letter-spacing:0.06em;text-transform:uppercase;
  color:var(--lagoon);
  display:inline-flex;align-items:center;gap:0.5rem;
}
.state::before{content:'';width:0.5rem;height:0.5rem;border-radius:50%;background:currentColor;flex:none}
.state-stale{color:var(--red)}
.state-off{color:var(--muted)}

/* ---- A figure worth calling out --------------------------------------------
   The cost-of-conversion number is the one thing no other tool shows, so it
   gets the weight of a pull quote rather than a row in a table. */
.callout{
  border-left:3px solid var(--red-big);
  padding:0.2rem 0 0.2rem 1.3rem;
  display:grid;gap:0.5rem;max-width:44ch;
}
.callout .n{
  font-family:var(--display);font-size:clamp(2rem,5vw,3rem);
  line-height:1;color:var(--ink);
}
.callout p{margin:0;color:#3B342A}

/* Present to a screen reader and to a browser with no stylesheet, absent to
   the eye. The chart uses it to carry each bar's value as real text. */
.vh{
  position:absolute;width:1px;height:1px;
  margin:-1px;padding:0;border:0;
  clip-path:inset(50%);overflow:hidden;white-space:nowrap;
}

/* A row's sync state belongs under the row, not trailing the sentence above
   it — same correction the row action needed. `inline-flex` was not enough:
   an inline box with a top margin still sits on the line it was born on. It
   has to be block-level to claim its own. */
.ruled .v .state{display:flex;margin-top:0.5rem}

/* The bar, on a page that scrolls under it.
   The landing deck fades the bar out at 64% because a snapped panel centres
   its content and nothing ever passes beneath. A document scrolls continuously,
   so that fade let live rows show through the navbar. Solid paper and a
   hairline instead — the bar is a rule across the top of the page, like a
   running head. */
body.app .topbar{
  background:var(--paper);
  border-bottom:1px solid var(--rule);
  padding-bottom:0.3rem;
}
body.app .topbar-sections{border-top:0;margin-top:0}

/* The keyword index scrolls sections into view, so every section has to stop
   clear of the bar rather than under it. */
body.app .panel{scroll-margin-top:calc(var(--bar-h) + 0.5rem)}

/* ---- Consent ---------------------------------------------------------------
   Unticked by default and never a condition of the request: consent to be
   marketed to is a separate thing from asking for a place, and bundling the
   two is precisely what the law forbids. Set at body size rather than as fine
   print — text nobody can read is not consent. */
.consent{
  display:grid;grid-template-columns:auto 1fr;
  gap:0.85rem;align-items:start;
  margin:0 0 1.5rem;cursor:pointer;
  max-width:36rem;
}
.consent input{
  width:1.15rem;height:1.15rem;margin:0.32rem 0 0;
  accent-color:var(--red);flex:none;cursor:pointer;
}
.consent input:focus-visible{outline:2px solid var(--lagoon);outline-offset:3px}
.consent span{font-size:1.05rem;line-height:1.5;color:#3B342A}

/* ---- The bar over an inverted panel ---------------------------------------
   The bar fades to transparent at 64% so content passing beneath it dissolves
   rather than being cut off. Over the ink panel that fade handed the rail and
   its labels a near-black backdrop and they went dark-on-dark — present in the
   original template too, wherever an inverted panel sat under the bar.

   app.js already knows which panel is active, so the bar simply changes ink
   with it. Colours are the ones .panel.ink already establishes, so the bar
   agrees with the panel rather than inventing a second dark palette. */
.topbar{transition:background .35s ease}
.topbar::after{transition:background .35s ease}
.topbar.on-ink{background:var(--ink)}
/* The dissolve takes the panel's colour with the bar, or it fades cream into a
   near-black panel and draws a bright band across the top of it. */
.topbar.on-ink::after{background:linear-gradient(var(--ink),rgba(26,23,18,0))}
.topbar.on-ink .mark{color:var(--paper)}
.topbar.on-ink .keys a{color:#A99C84}
.topbar.on-ink .keys a:hover{color:var(--paper)}
.topbar.on-ink .keys a[aria-current="true"]{color:#E4762F}
.topbar.on-ink .years{color:#A99C84}
.topbar.on-ink .timeline-rule{background:#3A342A}
.topbar.on-ink .bead{box-shadow:0 0 0 4px var(--ink)}

@media (prefers-reduced-motion:reduce){
  .topbar{transition:none}
}

/* ---- The wordmark ----------------------------------------------------------
   A three-letter wordmark reads as a mark at 1.5rem; nine letters does not.
   "Tallyduck" is nine lowercase letters, and at that size a Didone's whole
   character (the thick-to-hairline contrast) falls below the threshold where
   you can see it: it stopped looking like an identity and started looking like
   a bold serif word.

   Two corrections, no illustration required. Size, because Didones need it.
   And the join shown, because a compound name that reads as one word reads as
   a typo — Tally + duck, with the second half stepped back. */
.mark{font-size:1.85rem;letter-spacing:-0.005em}
.mark span.duck{color:var(--muted)}      /* beats `.mark span` on specificity */

@media (max-width:34rem){
  .mark{font-size:1.6rem}
}

/* ---- Auth ------------------------------------------------------------------
   No section index and no rail on a page with one form and one job, so the bar
   is a single row and gives its height back to the page. */
body.auth{--bar-h:4.2rem}

/* The honeypot. Not `display:none`: taken out of the layout, out of the tab
   order and out of the accessibility tree, but still a real field in the DOM
   for anything that fills forms by parsing them. */
.honeypot{
  position:absolute;left:-9999px;
  width:1px;height:1px;overflow:hidden;
}

/* The chart, shown on the landing page beside a tally and a heading rather
   than alone on a dashboard section. It has to give up some height so the
   whole panel still fits one screen without the panel scrolling inside itself. */
.chart-sm{height:clamp(6rem,14vh,9rem)}

/* `hidden` must actually hide. The attribute only carries `display:none` from
   the UA stylesheet, so any author rule that sets display — .auth-box is
   display:grid, .ruled is display:grid, .tally too — silently outranks it and
   the element stays on screen. This is the one place !important is the correct
   tool: hidden is not a suggestion. */
[hidden]{display:none !important}

/* ---- Long-form documents (privacy, terms) --------------------------------
   These are read, not scanned, so they get a measure and a rhythm rather than
   the deck's one-idea-per-screen pacing. body.app already turns off scroll
   snapping and lets the page scroll normally; .doc only sets the type. */
.doc .panel{max-width:44rem}
.doc h2{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.5rem,3.4vw,2.1rem);line-height:1.15;
  margin:2.6rem 0 0.9rem;
}
.doc h2:first-of-type{margin-top:1.6rem}
.doc h3{
  font-family:var(--mono);font-size:0.95rem;font-weight:500;
  letter-spacing:0.02em;color:var(--muted);
  margin:1.6rem 0 0.5rem;
}
.doc p,.doc li{font-size:1.06rem;line-height:1.65;color:#3B342A}
.doc p{margin:0 0 0.9rem}
.doc ul{margin:0 0 1.1rem;padding-left:1.1rem}
.doc li{margin:0 0 0.4rem}
.doc a{color:var(--red);text-underline-offset:0.18em}
.doc .updated{
  font-family:var(--mono);font-size:0.9rem;color:var(--muted);
  border-top:1px solid var(--rule);padding-top:0.8rem;margin-top:2.6rem;
}
/* A visible marker for the things still to be decided. Better on the page in
   plain sight than quietly missing — and it will not survive to launch. */
.doc .todo{
  border-left:3px solid var(--red-big);padding:0.1rem 0 0.1rem 1rem;
  margin:0 0 1.1rem;color:#3B342A;
}

/* ---- The rate stack ------------------------------------------------------
   Three rates stacked, so the cost reads as ACCUMULATION — a spread inside the
   rate, then a fee on top of it — rather than as one number to be taken on
   trust. No statement anywhere puts those two beside each other.

   Everything here starts VISIBLE. GSAP hides these rows at init and only if it
   is actually going to animate them, so a blocked script leaves the figures
   readable instead of leaving an empty column. */
.rates{display:grid;gap:1.1rem;align-content:start}
.rate-list{list-style:none;margin:0;padding:0;display:grid}
.rate{
  display:grid;grid-template-columns:1fr auto auto;
  align-items:baseline;gap:0.5rem 1.1rem;
  padding:0.75rem 0;border-top:1px solid #3A342A;
}
.rate:last-child{border-bottom:1px solid #3A342A}
.rate-k{
  font-family:var(--mono);font-size:0.86rem;font-weight:500;
  letter-spacing:0.1em;text-transform:uppercase;color:#7FB3AD;
}
.rate-n{
  font-family:var(--mono);font-size:1.25rem;color:var(--paper);
  font-variant-numeric:tabular-nums;
}
/* Reserved width even when empty (the mid-market row has no delta), so the
   three numbers stay in one column instead of shifting as rows appear.
   6ch, not less: the widest delta is "+0.33%" at six characters, and reserving
   4.6ch pushed the mid-market figure ~10px right of the two below it. */
.rate-d{
  font-family:var(--mono);font-size:0.9rem;font-weight:500;color:#E4762F;
  font-variant-numeric:tabular-nums;min-width:6ch;text-align:right;
}
.rate-out{
  font-family:var(--display);font-size:clamp(2.6rem,9vw,4.6rem);
  line-height:0.9;color:var(--paper);margin:0.4rem 0 0;
  font-variant-numeric:tabular-nums;
}
.rate-out em{font-style:normal;color:#E4762F}
.rate-out span{
  display:block;font-family:var(--mono);font-size:0.86rem;font-weight:500;
  letter-spacing:0.1em;text-transform:uppercase;color:#A99C84;margin-top:0.6rem;
}

/* The deck is a custom scroll container and now takes focus, so it needs to be
   able to say so. --red-big rather than --lagoon: this outline has to be
   visible on the ink panel as well as on paper. */
.deck:focus-visible{outline:2px solid var(--red-big);outline-offset:-4px}

/* ---- Content links -------------------------------------------------------
   Without these, links inside body copy fall back to the UA stylesheet and
   render default blue/purple, which on warm paper is the loudest thing on the
   page. The navbar, buttons and .doc pages already had their own treatment;
   these are the ones that were missed. Author rules beat the UA stylesheet
   regardless of specificity, so :visited needs no separate declaration. */
.lede a,.fine a,.hint a,.ruled .v a,.consent a,.auth-alt a{
  color:var(--red);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:0.18em;
  transition:color .2s ease;
}
.lede a:hover,.fine a:hover,.hint a:hover,.ruled .v a:hover,
.consent a:hover,.auth-alt a:hover{color:var(--ink)}

/* --red is 7.65:1 on paper but far too dark on the ink panel. */
.panel.ink .lede a,.panel.ink .fine a,.panel.ink .ruled .v a{color:#E4762F}
.panel.ink .lede a:hover,.panel.ink .fine a:hover,
.panel.ink .ruled .v a:hover{color:var(--paper)}
