/* ==========================================================================
   timefiction.com

   Implements the Claude Design handoff in `project/`. The token block below is
   carried over verbatim from the exported design system
   (`_ds/…/tokens/{colors,typography,spacing}.css` + `base.css`), with two
   deliberate changes, both noted inline: the display size is fluid, and body
   copy hyphenates when justified.
   ========================================================================== */

/* ---------- Tokens: colour ------------------------------------------------ */

:root {
  --black: #000000;
  --amber: #F6A300;
  --near-white: #F2F2F2;
  --ash: #D9D9D9;
  --ink: #262626;
  --line-dim: rgba(217, 217, 217, .5);

  --color-bg: var(--black);
  --color-text: var(--ash);
  --color-text-muted: rgba(217, 217, 217, .7);
  --color-accent: var(--amber);
  --color-heading-start: var(--amber);
  --color-heading-end: var(--near-white);
  --color-connector: var(--line-dim);
  --color-glow: var(--ash);
  --color-selected-glow: var(--amber);

  --button-primary-bg: var(--amber);
  --button-primary-text: var(--ink);
  --button-secondary-border: var(--amber);
  --button-secondary-text: var(--amber);
  --button-secondary-bg: transparent;

  --heading-shadow: 0 2px 10px rgba(0, 0, 0, .55);
}

/* ---------- Tokens: type -------------------------------------------------- */

:root {
  --font-display: "Kaushan Script", cursive;
  --font-serif: "Baskervville", "Baskerville", "Georgia", serif;

  /* The design system pins h1 at a flat 54px and every page then wrapped its
     h1 in `white-space:nowrap` to stop the prototype renderer clipping the
     last glyph. Nowrap overflows real phones, so the size is fluid instead and
     the clipping is fixed properly (see .ds-h1's trailing padding). */
  --text-h1-size: clamp(30px, 6.4vw, 54px);
  --text-h1-line: 1.15;
  --text-h2-size: clamp(20px, 2.4vw, 24px);
  --text-h3-size: 18px;
  --text-h4-size: 16px;
  --text-body-size: 17px;
  --text-body-line: 1.7;
  --text-nav-size: 16px;
  --text-body-max-width: 68ch;
}

/* ---------- Tokens: space ------------------------------------------------- */

:root {
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;
  --radius-pill: 999px;
  --radius-md: 6px;
}

/* ---------- Base ---------------------------------------------------------- */

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

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

body {
  margin: 0;
  /* Column flex so a short page (the 404) can fill the viewport below the nav
     without overflowing it. `dvh` keeps mobile browser chrome out of the sum. */
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-serif);
}

img { max-width: 100%; }

a { color: var(--amber); }
a:hover { color: var(--near-white); }

:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
  border-radius: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Type scale ---------------------------------------------------- */

.ds-h1 {
  display: inline-block;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-h1-size);
  font-weight: 400;
  line-height: var(--text-h1-line);
  background: linear-gradient(180deg, var(--color-heading-start), var(--color-heading-end));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  text-shadow: var(--heading-shadow);
  /* Kaushan Script's italic terminals overshoot the glyph advance; without a
     little trailing room the background-clip box slices the final letter. */
  padding-right: .12em;
}

.ds-h2 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-h2-size);
  font-weight: 400;
  color: var(--color-text);
}

.ds-h3 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-h3-size);
  font-weight: 700;
  color: var(--color-text);
}

.ds-h4 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-h4-size);
  font-weight: 400;
  color: var(--color-text);
}

.ds-body {
  margin: 0;
  max-width: var(--text-body-max-width);
  font-family: var(--font-serif);
  font-size: var(--text-body-size);
  line-height: var(--text-body-line);
  color: var(--color-text);
}

.ds-nav-text {
  font-family: var(--font-serif);
  font-size: var(--text-nav-size);
  color: var(--color-text);
}

/* Long justified measures open rivers in Baskervville without hyphenation. */
.prose {
  text-align: justify;
  hyphens: auto;
}

/* ---------- Nav ----------------------------------------------------------- */

/* The wordmark was removed during design review, so the bar is links only. */
.nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: clamp(16px, 4vw, 32px);
  padding: 20px clamp(16px, 4vw, 40px);
  background: var(--color-bg);
}

.nav__link {
  color: var(--color-text);
  text-decoration: none;
}

.nav__link:hover,
.nav__link[aria-current="page"] { color: var(--color-accent); }

/* ---------- Buttons ------------------------------------------------------- */

.btn {
  display: inline-block;
  padding: 12px 28px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-family: var(--font-serif);
  font-size: 16px;
  letter-spacing: .02em;
  text-decoration: none;
  cursor: pointer;
  transition: opacity .15s ease, transform .1s ease;
}

.btn:hover { opacity: .82; }
.btn:active { transform: scale(.97); }

.btn--primary {
  background: var(--button-primary-bg);
  color: var(--button-primary-text);
}

.btn--primary:hover { color: var(--button-primary-text); }

.btn--secondary {
  background: var(--button-secondary-bg);
  color: var(--button-secondary-text);
  border-color: var(--button-secondary-border);
}

.btn--secondary:hover { color: var(--button-secondary-text); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

/* ---------- Divider ------------------------------------------------------- */

/* The ◆◇◆ glyph run is the site's recurring signature mark: it separates
   scenes inside a story and the essay from the contact block on About. */
.divider {
  margin: 56px 0;
  color: var(--color-text-muted);
  font-size: 14px;
  letter-spacing: .5em;
  text-align: center;
}

/* ---------- Cookie consent ------------------------------------------------ */

/* Sits on --ink rather than the page black so it reads as a layer over the
   site, not part of it. First in the DOM, pinned to the bottom visually. */
.consent {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 100;
  padding: 18px clamp(16px, 4vw, 40px);
  background: var(--ink);
  border-top: 1px solid var(--line-dim);
}

.consent__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 28px;
  max-width: 1080px;
  margin: 0 auto;
}

.consent__text { flex: 1 1 320px; }

.consent__title {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 700;
  color: var(--near-white);
}

.consent__body {
  margin: 0;
  max-width: 68ch;
  font-size: 15px;
  line-height: 1.5;
  color: var(--color-text-muted);
}

.consent__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* Accept and Decline are the same size on purpose — a decline that is harder
   to find than an accept is not a free choice. */
.consent .btn {
  padding: 10px 26px;
  font-size: 15px;
}

/* A button that reads as a link: it opens the prompt, so it is not navigation. */
.linkish {
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-serif);
  font-size: 15px;
  color: var(--amber);
  text-decoration: underline;
  cursor: pointer;
}

.linkish:hover { color: var(--near-white); }

/* ==========================================================================
   Home — the Map of Time
   ========================================================================== */

:root { --capsule-fade: 3000ms; }

.timeline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  /* The rows must be *explicit* for the hero's `grid-row: 1 / -1` to span them:
     a negative line number counts back from the end of the explicit grid, so
     with implicit rows -1 resolves to line 1 and the hero collapses into row 1,
     inflating it to its own height. --rows is written into the markup by
     tools/build-pages.py, from the number of events in the longer column. */
  grid-template-rows: repeat(var(--rows, 12), auto);
  column-gap: clamp(10px, 2vw, 28px);
  row-gap: 44px;
  align-items: start;
  padding: 24px clamp(12px, 3vw, 32px) 120px;
}

.timeline__hero {
  grid-column: 2;
  grid-row: 1 / -1;
  position: sticky;
  top: 6vh;
  align-self: start;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  max-width: 480px;
  text-align: center;
}

.timeline__hourglass {
  display: block;
  width: min(340px, 32vw);
  min-width: 180px;
  height: auto;
  border-radius: 4px;
}

.event {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  /* Every event is pinned to this height so the two columns stay in step,
     exactly as the independent flex columns did in the prototype. */
  min-height: 88px;
  max-width: 340px;
  grid-column: var(--col);
  grid-row: var(--row);
}

.event--left {
  flex-direction: row-reverse;
  justify-self: end;
  margin-inline-end: clamp(8px, 2vw, 18px);
}

.event--right {
  justify-self: start;
  margin-inline-start: clamp(8px, 2vw, 18px);
}

.event__capsule {
  position: relative;
  flex-shrink: 0;
  width: 56px;
  height: 72px;
}

.capsule {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: default;
}

.capsule__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: opacity var(--capsule-fade) ease;
}

/* Default (and no-JS) state: every capsule is already open and every event is
   readable, so the page is complete for crawlers and without scripting. The
   sequential reveal below is layered on top only once JS is confirmed. */
.capsule__img--closed { opacity: 0; }
.capsule__img--open { opacity: 1; }

.event__year {
  position: absolute;
  top: 78px;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  white-space: nowrap;
  transition: opacity var(--capsule-fade) ease;
}

.event__desc {
  margin: 0;
  color: var(--color-text-muted);
  transition: opacity var(--capsule-fade) ease;
}

.event--left .event__desc { text-align: right; }

/* --- Progressive enhancement: the one-at-a-time reveal -------------------- */

.js .capsule__img--open,
.js .event__year,
.js .event__desc { opacity: 0; }

.js .event[data-state="pending"] .capsule__img--closed { opacity: 1; }

.js .event[data-state="open"] .capsule__img--open,
.js .event[data-state="open"] .event__year,
.js .event[data-state="open"] .event__desc { opacity: 1; }

.js .event[data-state="pending"] .capsule { cursor: pointer; }

@media (prefers-reduced-motion: reduce) {
  :root { --capsule-fade: 200ms; }
  .btn:active { transform: none; }
}

/* ==========================================================================
   Encyclopedia of Time
   ========================================================================== */

.enc-header {
  max-width: 640px;
  margin: 0 auto;
  padding: 48px 24px 8px;
  text-align: center;
}

.enc-header__sub { margin-top: 14px; }

.enc {
  position: relative;
  width: min(94vw, 780px);
  aspect-ratio: 1 / 1;
  margin: 56px auto 96px;
}

.enc-ring {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Thumbs sit on a rectangle: 4 across the top, 3 down the right, 4 along the
   bottom, 3 up the left. Each carries its own --x/--y in the markup. */
.enc-item {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: 92px;
  height: 100px;
  transform: translate(-50%, -50%);
  z-index: 1;
  transition: left .4s ease, top .4s ease, width .4s ease, height .4s ease;
}

.enc-item.is-selected {
  left: 50%;
  top: 40%;
  width: 270px;
  height: 293px;
  z-index: 5;
}

.enc-thumb {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 1.5px solid var(--near-white);
  border-radius: 12px;
  overflow: hidden;
  background: none;
  cursor: pointer;
}

.enc-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.enc-panel {
  position: absolute;
  left: 50%;
  top: 64%;
  width: min(60%, 360px);
  transform: translate(-50%, 0);
  text-align: center;
}

.enc-panel--empty {
  top: 50%;
  width: min(46%, 300px);
  transform: translate(-50%, -50%);
}

.enc-prompt {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 15px;
}

.enc-name {
  font-size: 22px;
}

.enc-effect {
  margin-top: 10px;
  max-width: none;
  color: var(--color-text-muted);
  font-size: 15px;
  line-height: 1.5;
}

.enc-count {
  margin-top: 14px;
  max-width: none;
  color: var(--amber);
  font-size: 14px;
}

/* The enlarged image only exists in the mobile layout; on desktop the thumb
   itself travels to the centre, so showing a second copy would duplicate it. */
.enc-detail__img { display: none; }

/* ==========================================================================
   Book
   ========================================================================== */

.book {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 56px;
  max-width: 1080px;
  margin: 0 auto;
  padding: 64px 24px 96px;
}

.book__cover {
  flex: 1 1 260px;
  max-width: 400px;
}

.book__cover img {
  display: block;
  width: 100%;
  height: auto;
  border: 2px solid var(--near-white);
  border-radius: 4px;
  box-shadow: 0 0 40px rgba(0, 0, 0, .6);
}

.book__body {
  flex: 2 1 420px;
  min-width: 0;
}

.book__blurb { max-width: none; }

.book__blurb p { margin: 0 0 18px; }
.book__blurb p:last-child { margin-bottom: 0; }
.book__blurb strong { font-weight: 700; }

.book .btn-row { margin-top: 36px; }

/* ==========================================================================
   About
   ========================================================================== */

.about {
  max-width: clamp(65ch, 70vw, 1100px);
  margin: 0 auto;
  padding: 48px 24px 96px;
}

/* Understated page label rather than a display headline — About is meant to
   open quietly, unlike Home. */
.about__label {
  margin: 0 0 28px;
  color: var(--color-text-muted);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
}

.about__byline {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 28px;
}

.about__portrait {
  flex-shrink: 0;
  width: 140px;
  height: 170px;
  object-fit: cover;
  border-radius: 12px;
  filter: grayscale(1);
}

/* The design system caps body copy at 68ch; the essay was widened past that
   during review, so every paragraph here runs the full column — including the
   opening one, which would otherwise sit visibly narrower than the rest. */
.about__opening,
.about__beat,
.about__essay,
.about__closing { max-width: none; }

.about__opening {
  flex: 1;
  min-width: 220px;
}

.about__essay { margin: 0 0 22px; }

/* "However…" gets its own beat: italic, larger, breathing room either side. */
.about__beat {
  margin: 44px 0;
  font-size: 22px;
  font-style: italic;
  text-align: left;
}

/* The closing line is given the same light emphasis as the story's last line
   and Home's sub-heading — a recurring motif for meaningful last lines. */
.about__closing {
  margin: 36px 0 0;
  font-style: italic;
}

/* --- Mailing list signup ------------------------------------------------- */

/* The one boxed element on the site. A thin light rule is already part of the
   vocabulary — the book cover's frame, the encyclopedia thumbs — so the card
   reads as belonging here rather than as a widget dropped in. */
.signup {
  max-width: 560px;
  margin: 0 0 56px;
  padding: 28px clamp(20px, 4vw, 32px) 30px;
  border: 1px solid var(--line-dim);
  border-radius: var(--radius-md);
}

.signup__title {
  margin-bottom: 14px;
  text-align: center;
}

.signup__lede { max-width: none; }

.signup__list {
  max-width: none;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}

.signup__list li {
  padding-left: 1.5em;
  text-indent: -1.5em;
}

/* The ◆ that divides the stories and closes the essay, reused as a bullet. */
.signup__list li::before {
  content: "\25C6";
  display: inline-block;
  width: 1.5em;
  text-indent: 0;
  color: var(--amber);
  font-size: .7em;
}

.signup__form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 26px;
}

.signup__email {
  flex: 1 1 220px;
  min-width: 0;
  padding: 12px 22px;
  border: 1px solid var(--line-dim);
  border-radius: var(--radius-pill);
  background: var(--black);
  color: var(--color-text);
  font-family: var(--font-serif);
  font-size: 16px;
}

.signup__email::placeholder { color: var(--color-text-muted); }
.signup__email:focus { border-color: var(--color-accent); }

.signup__form .btn { flex: 0 0 auto; }

.signup__submit[disabled] {
  opacity: .6;
  cursor: default;
}

.signup__smallprint {
  margin: 16px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-text-muted);
}

.signup__done {
  padding: 8px 0;
  text-align: center;
}

.signup__done:focus { outline: none; }

.signup__done p {
  max-width: none;
  margin-top: 10px;
}

.social {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 20px;
  margin-top: 20px;
}

.social a {
  display: block;
  line-height: 0;
  border-radius: var(--radius-pill);
}

.social img {
  display: block;
  width: 44px;
  height: 44px;
}

/* ==========================================================================
   Story
   ========================================================================== */

/* Immersive reading chrome: no site nav, just two quiet corner links. */
.story-nav {
  display: flex;
  justify-content: space-between;
  padding: 28px clamp(16px, 5vw, 56px);
}

.story-nav a { text-decoration: none; }

.story {
  max-width: clamp(60ch, 60vw, 960px);
  margin: 0 auto;
  padding: 0 24px 96px;
}

.story__body { margin-top: 40px; }

.story__body p {
  max-width: none;
  margin: 0;
  /* Paragraphs run on with a first-line indent rather than being separated by
     space — the convention the story was typeset in. */
  text-indent: 2em;
}

/* No indent for the first paragraph, nor for one that opens a new scene. */
.story__body > p:first-child,
.story__body > .divider + p { text-indent: 0; }

/* House convention across all 18 stories: the opening and closing sections are
   italic (the inner-monologue frame), the body between them is regular. */
.story__body p.is-italic { font-style: italic; }

.story__body .divider { margin: 40px 0; }

.story .btn-row { margin-top: 48px; }

.story__footer {
  display: flex;
  justify-content: space-between;
  margin-top: 56px;
}

.story__footer a { text-decoration: none; }

/* ==========================================================================
   404
   ========================================================================== */

.notfound {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 24px;
  text-align: center;
}

.notfound__capsule {
  width: 72px;
  height: 92px;
  object-fit: contain;
}

.notfound__body {
  max-width: 52ch;
  color: var(--color-text-muted);
}

.notfound__back {
  margin-top: 12px;
  font-family: var(--font-serif);
  font-size: 16px;
}

/* ==========================================================================
   Narrow viewports

   680px is the breakpoint the Home page's mobile layout was designed against.
   ========================================================================== */

@media (max-width: 679px) {

  /* --- Home: the two columns collapse into one chronological run ---------- */
  .timeline {
    display: flex;
    flex-direction: column;
    gap: 36px;
    max-width: 460px;
    margin: 0 auto;
    padding: 24px 20px 80px;
  }

  .timeline__hero {
    position: static;
    max-width: none;
    gap: 14px;
    margin-bottom: 4px;
  }

  .timeline__hourglass {
    width: min(240px, 60vw);
    min-width: 0;
  }

  .event,
  .event--left,
  .event--right {
    flex-direction: row;
    justify-self: auto;
    max-width: none;
    margin-inline: 0;
  }

  .event--left .event__desc { text-align: left; }

  /* --- Encyclopedia: rectangle becomes a grid, detail moves below --------- */
  .enc {
    position: static;
    width: auto;
    max-width: 520px;
    aspect-ratio: auto;
    margin: 32px auto 72px;
    padding: 0 20px;
  }

  .enc-ring {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
  }

  .enc-item {
    position: static;
    width: auto;
    height: auto;
    aspect-ratio: 92 / 100;
    transform: none;
    transition: none;
  }

  .enc-item.is-selected {
    width: auto;
    height: auto;
  }

  .enc-item.is-selected .enc-thumb {
    border-color: var(--color-selected-glow);
    box-shadow: 0 0 0 2px var(--color-selected-glow);
  }

  .enc-panel,
  .enc-panel--empty {
    position: static;
    width: auto;
    margin-top: 32px;
    transform: none;
  }

  .enc-detail__img {
    display: block;
    width: min(240px, 70%);
    height: auto;
    margin: 0 auto 20px;
    border: 1.5px solid var(--near-white);
    border-radius: 12px;
  }

  /* --- About: portrait sits above the opening paragraph ------------------- */
  .about { padding: 32px 20px 72px; }

  /* Once the field takes a row to itself, a natural-width button beneath it
     reads as orphaned — let it span instead. */
  .signup__form .btn { flex: 1 1 auto; }

  .about__byline { gap: 20px; }

  .about__portrait {
    width: 120px;
    height: 146px;
  }

  /* --- Book: cover on top, then blurb, then the buying links -------------- */
  .book {
    gap: 32px;
    padding: 40px 20px 72px;
  }

  .book__cover {
    max-width: 280px;
    margin: 0 auto;
  }

  /* --- Story ------------------------------------------------------------- */
  .story { padding: 0 20px 72px; }
  .story-nav { padding: 20px; }
}
