/* leocelis.com
   Palette: ITV house palette, scored 2026-10-31. Ratios are WCAG
   relative luminance, computed, not eyeballed.
   Motion: the page is still; only controls change state, 150ms.
   Reduced motion cuts it. */

@font-face {
  font-family: "Newsreader";
  src: url("../fonts/Newsreader-Variable.ttf") format("truetype");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("../fonts/Newsreader-Italic-Variable.ttf") format("truetype");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("../fonts/InstrumentSans-Variable.ttf") format("truetype");
  font-weight: 400 700;
  font-stretch: 75% 100%;
  font-style: normal;
  font-display: swap;
}

:root {
  --paper: #f3efe6;
  --paper-deep: #e8e2d4; /* ink 14.16 · stone 5.49 · slate 4.53 */
  --ink: #16150f;        /* 15.94 on paper */
  --stone: #5c584f;      /* 6.17 on paper: secondary text */
  --slate: #4b6880;      /* 5.10 on paper, 3.13 vs ink: the only accent, never a field */
  --rule: #cec7b8;       /* 1.47: hairlines only, never text */
  --brick: #8e3b2c;      /* 6.51 on paper: form errors only */

  --serif: "Newsreader", Georgia, "Times New Roman", serif;
  --sans: "Instrument Sans", "Helvetica Neue", Arial, sans-serif;

  --gutter: 20px;
  --box: 1200px;
  --section: 64px;
  /* Motion, the same tokens as the InTheValley site: controls answer in 120ms,
     panels 240ms, a block rising into view 520ms with a 90ms stagger, ease-out. */
  --fast: 120ms;
  --panel: 240ms;
  --reveal: 520ms;
  --stagger: 90ms;
  /* Easing: ease-out for what enters,
     ease-in-out for a state change inside one element (hover, press, a line). */
  --ease-out: cubic-bezier(0.2, 0, 0, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}

@media (min-width: 768px) { :root { --gutter: 24px; --section: 88px; } }
@media (min-width: 1024px) { :root { --gutter: 32px; --section: 112px; } }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { max-width: 100%; display: block; }
p { margin: 0 0 16px; }
h1, h2, h3 { margin: 0; font-weight: 400; letter-spacing: -0.01em; }

a { color: var(--slate); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
    transition: color var(--fast) var(--ease-in-out), text-decoration-thickness var(--fast) var(--ease-in-out); }
a:hover { text-decoration-thickness: 2px; }
:focus-visible { outline: 2px solid var(--slate); outline-offset: 2px; }

.box { max-width: var(--box); margin: 0 auto; padding: 0 var(--gutter); }
.label { font-family: var(--sans); font-size: 14px; font-weight: 500; letter-spacing: 0.02em; color: var(--stone); margin: 0 0 16px; }

/* Header, the InTheValley website's (inthevalley/website globals.css .site-header):
   rule across the window, a centered row at least 80px tall with 16px above and
   below, the outlined Newsreader SemiBold wordmark at 26px tall (same recipe and
   vertical box as the InTheValley mark, tools/build_assets.py), and the nav link
   in sans 500 at 15px, ink at rest, a 1px underline 3px under on hover and
   keyboard focus. */
.site-head { border-bottom: 1px solid var(--rule); }
.site-head .box { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 24px; min-height: 80px; padding-top: 16px; padding-bottom: 16px; }
.wordmark { display: block; line-height: 0; }
.wordmark img { display: block; height: 22px; width: auto; } /* a step under the ITV wordmark (26px): ITV leads the family */
.nav { display: flex; gap: 24px; align-items: baseline; }
.nav a, .nav button { font-family: var(--sans); font-weight: 500; font-size: 15px; line-height: 1.4; color: var(--ink); text-decoration: none; }
.nav a:hover, .nav a:focus-visible, .nav button:hover, .nav button:focus-visible { color: var(--ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }


button { font: inherit; cursor: pointer; }
.link-button { background: none; border: 0; padding: 0; }

/* Buttons: one solid (ink), one quiet (text link). */
.actions { display: flex; flex-wrap: wrap; gap: 16px 28px; align-items: center; margin-top: 32px; }
/* Solid ink at rest, flips to paper on hover (the InTheValley button). Pressed, it
   settles into a well instead of resizing. */
.btn { display: inline-block; font-family: var(--sans); font-size: 15px; font-weight: 500; line-height: 1.4; padding: 12px 24px;
       background: var(--ink); color: var(--paper); border: 1px solid var(--ink); border-radius: 0; text-decoration: none;
       transition: background-color var(--fast) var(--ease-in-out), color var(--fast) var(--ease-in-out), box-shadow var(--fast) var(--ease-in-out); }
.btn:hover { background: var(--paper); color: var(--ink); }
.btn:active { box-shadow: inset 0 2px 0 var(--rule); }
.btn-quiet { font-family: var(--sans); font-size: 16px; font-weight: 500; color: var(--ink); }
.btn-quiet:hover { color: var(--slate); }

/* 1. First screen: the line, and one picture of real work.
   From 1024px the picture is a paper-deep "desk" that runs from 5/12 of the
   box to the window's right edge, so it holds at least half the first screen
   (measured); the text column still starts
   under the wordmark (one box). */
.hero { display: grid; gap: 40px; }
.hero-text { padding: 48px var(--gutter) 0; max-width: var(--box); width: 100%; margin: 0 auto; }
.hero-art { background: var(--paper-deep); padding: 40px var(--gutter); }
@media (min-width: 1024px) {
  .hero {
    grid-template-columns: minmax(var(--gutter), 1fr) calc((min(100%, var(--box)) - 2 * var(--gutter)) * 5 / 12) calc((min(100%, var(--box)) - 2 * var(--gutter)) * 7 / 12) minmax(var(--gutter), 1fr);
    gap: 0;
  }
  .hero-text { grid-column: 2; padding: 48px 48px 112px 0; align-self: center; margin: 0; }
  /* No minimum height: the hero is as tall as the book shelf, so the quote column has
     no empty band above or below it. */
  .hero-art { grid-column: 3 / 5; padding: 64px var(--gutter) 64px 64px; display: flex; align-items: center; }
}
/* The hero headline is a book quote picked on each load. Its size follows its length so a
   short line reads large and a long one still fits: l up to 70 characters, m up to 120, s
   above. The quote stays hidden only until the pick lands (300ms fade in). */
/* The intro, once per load, one thing at a time (the
   InTheValley entrance): the menu fades in; the quote rises 14px and
   fades in once it is picked; its source follows one stagger later; then the two
   books rise, one after the other. The wordmark, the rules and the desk never
   move. Reduced motion shows the finished page. */
.hero-line { margin: 0; }
.hero-line blockquote, .hero-line-source { transition: opacity var(--reveal) var(--ease-out), transform var(--reveal) var(--ease-out); }
.hero-line blockquote { transition-delay: var(--fast); }
.hero-line-source { transition-delay: calc(var(--fast) + var(--stagger) * 2); }
.js .hero-line:not(.is-ready) blockquote, .js .hero-line:not(.is-ready) .hero-line-source { opacity: 0; transform: translateY(14px); transition: none; }
@keyframes enter-fade { from { opacity: 0; } to { opacity: 1; } }
.js .nav { animation: enter-fade var(--reveal) var(--ease-out) both; }
/* The books wait for the quote, then rise one at a time instead of together. */
.hero-art .shelf .lb-book { animation-delay: calc(var(--i, 0) * var(--panel) + var(--reveal)) !important; }

/* Below the first screen, each block rises 16px into place once as it scrolls
   into view, cards one stagger apart. Hidden only after site.js marks it, so no
   script means nothing hidden; never re-triggered. */
[data-reveal] { transition: opacity var(--reveal) var(--ease-out), transform var(--reveal) var(--ease-out);
                transition-delay: calc(var(--i, 0) * var(--stagger)); }
[data-reveal="pending"] { opacity: 0; transform: translateY(16px); transition: none; }
.hero-line blockquote { margin: 0; }
.hero-line h1 { line-height: 1.12; font-size: 40px; max-width: 14ch; text-wrap: balance; }
.hero-line h1[data-size="m"] { font-size: 34px; max-width: 18ch; }
.hero-line h1[data-size="s"] { font-size: 30px; max-width: 22ch; }
@media (min-width: 768px) {
  .hero-line h1 { font-size: 54px; }
  .hero-line h1[data-size="m"] { font-size: 46px; }
  .hero-line h1[data-size="s"] { font-size: 38px; }
}
@media (min-width: 1280px) {
  .hero-line h1 { font-size: 60px; }
  .hero-line h1[data-size="m"] { font-size: 50px; }
  .hero-line h1[data-size="s"] { font-size: 42px; }
}
.hero-line-source { font-family: var(--sans); font-size: 15px; color: var(--stone); margin-top: 24px; }
.hero-line-source a { color: var(--stone); }
.hero-line-source a:hover { color: var(--ink); }

/* Section statement, shared by the sections below the hero. */
.statement { font-size: 38px; line-height: 1.15; }
@media (min-width: 1024px) { .statement { font-size: 46px; } }
/* 4. What I do now: a framed panel, a new shape. */
/* The two books on the first screen: each cover is the link to its book. */
.shelf-figure { margin: 0; width: 100%; max-width: 640px; }
/* The shelf itself is the Living Books embed (books.leocelis.com/embed/): it brings
   its own look and motion. Here only its width, gap and fonts are set, and the
   plain-link fallback is styled. */
.shelf { --lb-cover-w: 300px; --lb-gap: 24px; --lb-justify: start;
         --lb-serif: var(--serif); --lb-sans: var(--sans); --lb-ink: var(--ink); --lb-stone: var(--stone); --lb-accent: var(--slate); }
@media (min-width: 768px) { .shelf { --lb-gap: 40px; } }
.shelf-fallback { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; font-family: var(--serif); font-size: 21px; line-height: 1.3; }
.shelf-fallback a { color: var(--ink); }

.now { padding: var(--section) 0; }
/* Two company cards side by side from 1024px; each card stacks label, line, text and
   button, and the button sits at the card's foot so both buttons share one baseline. */
.cards { display: grid; gap: 32px; }
@media (min-width: 1024px) { .cards { grid-template-columns: 1fr 1fr; } }
.now { background: var(--ink); }
/* Each card is one target: the button's link covers the card. On hover a slate
   hairline draws across the top, left to right, the label darkens and the
   button flips, together. */
.panel { position: relative; background: var(--paper); color: var(--ink); padding: 32px 24px; display: flex; flex-direction: column; }
.panel::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--slate);
                 transform: scaleX(0); transform-origin: left; transition: transform var(--panel) var(--ease-in-out); }
.panel:hover::before, .panel:focus-within::before { transform: scaleX(1); }
.panel .label { transition: color var(--fast) var(--ease-in-out); }
.panel:hover .label { color: var(--ink); }
.panel .btn::after { content: ""; position: absolute; inset: 0; }
.panel:hover .btn { background: var(--paper); color: var(--ink); }
@media (min-width: 768px) { .panel { padding: 40px 48px; } }
@media (min-width: 1280px) { .panel { padding: 44px 56px; } }
.panel .statement { font-size: 32px; margin-top: 12px; }
@media (min-width: 1024px) { .panel .statement { font-size: 36px; } }
.panel .actions { margin-top: auto; padding-top: 28px; }
.panel p:not(.label) { font-size: 20px; max-width: 46ch; margin-top: 20px; }

/* 5. Background: statement beside text. No portrait. */
.about { padding: var(--section) 0; }
.about .box { display: grid; gap: 16px; }
@media (min-width: 1024px) { .about .box { grid-template-columns: 5fr 7fr; gap: 64px; align-items: baseline; } .about .box > div { display: contents; } }
.about .statement { font-size: 32px; }
@media (min-width: 1024px) { .about .statement { font-size: 38px; } }
.about p { font-size: 20px; max-width: 60ch; margin-top: 16px; }

/* 6. Closing band. */

/* Footer: one legal row, same tone, space between; room above. */
.site-foot { padding: 32px 0 40px; border-top: 1px solid var(--rule); }
/* Type and seal as the InTheValley footer (globals.css .site-footer__facts .ui and
   .site-footer__seal): sans 500 at 15px / 1.4, 8px either side of the dot, seal 26px.
   Colors stay this site's own (stone on paper). */
.site-foot .box { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 16px; font-family: var(--sans); font-size: 15px; font-weight: 500; line-height: 1.4; color: var(--stone); }
/* Legal row, as on the ITV site: "(c) 2000-year Leo Celis . Privacy", one face,
   size and tone, a middle dot between; no underline at rest, never the accent.
   The ComplyEdge seal sits at the right end. */
.site-foot .box { align-items: center; }
.site-foot .legal { margin: 0; }
.site-foot .sep { margin: 0 8px; }
.site-foot .foot-end { display: flex; align-items: center; gap: 24px; }
/* Seal ring: stone on paper clears WCAG 1.4.11 (3:1), so the seal's light half
   does not melt into the page. */
.site-foot .seal { display: inline-flex; }
.site-foot .seal img { display: block; height: 26px; width: auto; border-radius: 4px; outline: 1px solid var(--stone); }
.site-foot a { color: var(--stone); text-decoration: none; }
.site-foot a:hover, .site-foot a:focus-visible { color: var(--ink); text-decoration: underline; }

/* Legal page (privacy.html), laid out as the InTheValley privacy page: below
   1024 one column, the contents list hidden, the headings carry the page. From
   1024 a contents rail as wide as its longest entry on a 1px left rule, then
   the policy filling the rest of the box at 20px / 1.6. No facts box. */
.legal-page { padding: 48px 0 var(--section); }
.legal-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 48px; }
.legal-toc { display: none; }
.legal-toc ol { list-style: none; margin: 16px 0 0; padding: 0; font-family: var(--sans); font-size: 15px; line-height: 1.45; }
.legal-toc li + li { margin-top: 12px; }
.legal-toc a { color: var(--stone); text-decoration: none; }
.legal-toc a:hover, .legal-toc a:focus-visible { color: var(--ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.legal-text h1 { font-size: 46px; line-height: 1.1; margin-top: 16px; }
.legal-text .intro { font-size: 19px; line-height: 1.6; color: var(--stone); margin-top: 24px; }
.legal-text h2 { font-size: 24px; line-height: 1.25; margin-top: 48px; scroll-margin-top: 24px; }
.legal-text p, .legal-text li, .legal-text address { font-size: 19px; line-height: 1.6; }
.legal-text p, .legal-text address { margin-top: 16px; }
.legal-text address { font-style: normal; }
.legal-text ul { margin: 16px 0 0; padding-left: 20px; }
.legal-text li { margin-bottom: 12px; }
.legal-text a { color: var(--ink); }
.legal-text a[target="_blank"] { white-space: nowrap; }
.legal-text a:hover { color: var(--slate); }
.legal-text .label { font-size: 14px; line-height: 1.4; margin: 0; }
@media (min-width: 1024px) {
  .legal-page { padding-top: 64px; }
  /* Rail under the logo, text out to the last menu button: no blank
     in the middle, none on the right. */
  .legal-grid { grid-template-columns: max-content minmax(0, 1fr); column-gap: 72px; align-items: start; }
  .legal-toc { display: block; position: sticky; top: 24px; border-left: 1px solid var(--rule); padding-left: 24px; }
  .legal-text .intro, .legal-text p, .legal-text li, .legal-text address { font-size: 20px; }
  .legal-text h2 { font-size: 26px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
