/* ============================================================================
   Maximus the Gladiator — umbrella brand stylesheet
   ============================================================================

   RELATIONSHIP TO THE QUANTDESK SUB-SITE
   The trading desk at /quantdesk keeps its own restrained marble-and-patina
   palette, on purpose. That page asks a visitor to connect a brokerage
   account, and gold-and-crimson conquest styling is what a scam looks like.
   This umbrella site is a personal and venture brand rather than a financial
   product, so it is allowed the drama the sub-site cannot afford. The two
   share a type stack and an ornament sprite, which is what makes them read as
   one family despite the different colour.

   PALETTE SOURCE
   Every colour below is sampled from the logo rather than invented: the
   crimson of the plume, the charcoal of the galea, the weathered gold of the
   Colosseum behind it, and the parchment the mark sits on.

   THEMING
   Three states are supported and they are not the same thing:
     - no attribute        follows the operating system via prefers-color-scheme
     - [data-theme=light]  forced light, set by the toggle
     - [data-theme=dark]   forced dark, set by the toggle
   The hero band is deliberately dark in BOTH themes. It is a stage, and a
   stage is lit from the front against darkness.
   ========================================================================= */

:root {
  /* ---- brand constants: identical in both themes -------------------- */
  --imperial:      #9e1b26;   /* the plume. Reserved for emphasis and alerts. */
  /* Profit and loss, on the operator's instruction: green up, red down.
     Named separately from `--imperial` even though loss borrows its value,
     because they mean different things — one is an alert, the other is a
     direction — and the day a designer lightens the plume, a loss must not
     silently follow it. Both are held above 4.5:1 on the page's surfaces. */
  --gain:          #2f7d5b;
  --loss:          #9e1b26;
  --imperial-lift: #d4515c;
  --gold:          #b8912f;   /* weathered, not polished. Never #ffd700.      */
  --gold-lift:     #d9b65c;
  --gold-pale:     #ead9a8;
  --iron:          #43474d;   /* the helmet.                                  */
  --night:         #121316;
  --night-soft:    #1b1d21;

  /* ---- themed surfaces: overridden below ---------------------------- */
  --bg:        #f4f1e9;       /* parchment */
  --bg-sunk:   #e9e4d7;
  --surface:   #fffdf8;
  --line:      #ded7c6;
  --line-soft: #ece6d8;
  --ink:       #1a1c20;
  --ink-soft:  #4a4f57;
  --ink-faint: #7d8189;

  /* ---- type --------------------------------------------------------- */
  --display: "Trajan Pro", "Iowan Old Style", "Palatino Linotype", Palatino,
             "Book Antiqua", Georgia, serif;
  --body:    ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono:    ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* ---- metrics ------------------------------------------------------ */
  --measure: 64ch;
  --gap: clamp(1rem, 2.5vw, 2rem);
  /* Rounded, on the operator's instruction: "make the corners round in every
     box design". This was 3px with a note that Rome did not do rounded
     corners — true, and it lost the argument to the fact that every box on
     this site sits inside rounded browser chrome, so a hard 90-degree corner
     reads as unfinished rather than as carved. One token, so buttons, cards,
     panels and inputs move together and none is left square. */
  --radius: 10px;
  /* Images keep their own, slightly larger, so a picture inside a card does
     not appear to have a sharper corner than the card holding it. */
  --radius-img: 12px;
  --shadow: 0 1px 2px rgb(18 19 22 / .05), 0 8px 24px -12px rgb(18 19 22 / .18);
  --shadow-lift: 0 2px 4px rgb(18 19 22 / .07), 0 18px 40px -16px rgb(18 19 22 / .3);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --bg:        #121316;
    --bg-sunk:   #0d0e10;
    --surface:   #1b1d21;
    --line:      #2c2f35;
    --line-soft: #232629;
    --ink:       #ece7dc;
    --ink-soft:  #b6b2a8;
    --ink-faint: #85817a;
    --gold:      #d9b65c;
    --gold-lift: #ead9a8;
    --imperial:  #d4515c;
    /* Lifted for a dark ground: the light-mode pair fails contrast on #121316. */
    --gain:      #5fbf8f;
    --loss:      #e5707a;
  }
}
:root[data-theme="dark"] {
  --bg:        #121316;
  --bg-sunk:   #0d0e10;
  --surface:   #1b1d21;
  --line:      #2c2f35;
  --line-soft: #232629;
  --ink:       #ece7dc;
  --ink-soft:  #b6b2a8;
  --ink-faint: #85817a;
  --gold:      #d9b65c;
  --gold-lift: #ead9a8;
  --imperial:  #d4515c;
  --gain:      #5fbf8f;
  --loss:      #e5707a;
  --shadow: 0 1px 2px rgb(0 0 0 / .4), 0 8px 24px -12px rgb(0 0 0 / .7);
  --shadow-lift: 0 2px 4px rgb(0 0 0 / .5), 0 18px 40px -16px rgb(0 0 0 / .8);
}

/* ---------------------------------------------------------------------- */
/* base                                                                    */
/* ---------------------------------------------------------------------- */

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  font-size: clamp(1rem, .97rem + .15vw, 1.0625rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.14;
  text-wrap: balance;
  margin: 0 0 .6rem;
}
h1 { font-size: clamp(2.25rem, 1.6rem + 3.2vw, 4rem); letter-spacing: -.015em; }
h2 { font-size: clamp(1.55rem, 1.25rem + 1.3vw, 2.25rem); }
h3 { font-size: 1.2rem; }
h4 { font-size: 1rem; letter-spacing: .01em; }

p { max-width: var(--measure); margin: 0 0 1rem; }
img, svg, canvas { max-width: 100%; }

a { color: var(--gold); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--ink); }

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

::selection { background: var(--gold); color: var(--night); }

/* ---------------------------------------------------------------------- */
/* layout primitives                                                       */
/* ---------------------------------------------------------------------- */

.wrap   { width: min(100% - 2.5rem, 70rem); margin-inline: auto; }
.narrow { width: min(100% - 2.5rem, 46rem); margin-inline: auto; }

section { padding-block: clamp(3rem, 7vw, 5.5rem); }
/* The section divider, with an interpunct.
   Roman inscriptions separate words with a raised centre dot rather than a
   space, and a diamond is how the same mark is cut in stone. So the rule that
   divides the sections carries one: the line fades out toward the middle, the
   diamond sits in the gap. It costs one pseudo-element and it is the site's
   own alphabet rather than a decoration borrowed from somewhere else. */
.rule {
  border: 0;
  height: 1px;
  margin: 0;
  position: relative;
  /* Stronger than --line: this rule has to read against BOTH the parchment
     above it and the sunk panel below, and the border colour that works
     inside a card disappears when it is the only thing on the page. */
  background: linear-gradient(90deg,
    transparent 0%, color-mix(in srgb, var(--ink-faint) 38%, transparent) 14%,
    color-mix(in srgb, var(--ink-faint) 38%, transparent) 46%, transparent 49%,
    transparent 51%, color-mix(in srgb, var(--ink-faint) 38%, transparent) 54%,
    color-mix(in srgb, var(--ink-faint) 38%, transparent) 86%, transparent 100%);
}
.rule::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 7px; height: 7px;
  translate: -50% -50%;
  rotate: 45deg;
  background: var(--gold);
}
.sunk { background: var(--bg-sunk); }

/* Inscriptional label. Small, tracked-out capitals, the way a Roman tablet
   labels what is beneath it. */
.eyebrow {
  font-family: var(--body);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 .8rem;
}
.eyebrow.gold { color: var(--gold); }

.lede {
  font-size: clamp(1.05rem, 1rem + .35vw, 1.3rem);
  color: var(--ink-soft);
  line-height: 1.55;
}

.mt-lg { margin-top: 1.75rem; }
.quiet { color: var(--ink-faint); font-size: .875rem; }

/* ---------------------------------------------------------------------- */
/* masthead                                                                */
/* ---------------------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 60;
  background: color-mix(in srgb, var(--night) 88%, transparent);
  /* Safari has never shipped this unprefixed, including on every iPhone. The
     masthead is translucent, so without the prefix an iOS visitor gets the
     hero scrolling legibly through the navigation. */
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgb(255 255 255 / .08);
}
.masthead .wrap {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  min-height: 4.25rem;
}

.mark {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-family: var(--display);
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold-pale);
  text-decoration: none;
  white-space: nowrap;
}
.mark img {
  width: 2.1rem;
  height: 2.1rem;
  object-fit: contain;
  border-radius: var(--radius-img);
}
.mark:hover { color: #fff; }
.mark .thin { font-weight: 400; color: rgb(255 255 255 / .55); }

.masthead nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-wrap: wrap;
}
.masthead nav a {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .7);
  text-decoration: none;
  padding: .45rem .7rem;
  border-radius: var(--radius);
}
.masthead nav a:hover,
.masthead nav a[aria-current="page"] { color: var(--gold-lift); background: rgb(255 255 255 / .06); }

/* ---- the ONE call-to-action treatment -------------------------------------
   Solid, dark text, uppercase, letterspaced — the button from the home page.
   Every primary action on the site is now this button, at one of two sizes,
   and nothing else. It used to be an OUTLINED variant up here and a SOLID one
   down the page, which reads as two products rather than as one hierarchy.

   Hierarchy is still kept, but by repetition rather than by inventing shapes:
   one solid button per view, `.btn-ghost` for a secondary beside it, and a
   plain `.more` link for anything a reader may safely ignore. What changed is
   that the primary button looks the same everywhere it appears. */
.masthead nav a.nav-cta,
.masthead nav .nav-cta {
  border: 1px solid var(--gold);
  background: var(--gold);
  color: var(--night);
  margin-left: .4rem;
  border-radius: var(--radius);
  padding: .45rem .9rem;
  font: inherit;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
}
.masthead nav a.nav-cta:hover,
.masthead nav .nav-cta:hover { background: var(--gold-lift); border-color: var(--gold-lift); color: var(--night); }

/* Signed in, the action is to leave. The SAME shape as the sign-in button —
   same weight, same tracking, same padding — in crimson rather than gold, so
   it is recognisably the same kind of control while never being mistaken for
   the button it replaces. Same type, different pigment. */
.masthead nav .nav-cta-out {
  background: var(--imperial);
  border-color: var(--imperial);
  color: #fff;
}
.masthead nav .nav-cta-out:hover {
  background: var(--imperial-lift);
  border-color: var(--imperial-lift);
  color: var(--night);
}
.nav-logout-form { margin: 0; display: inline-flex; }

/* The theme control, in the bar. Icon only here — the glyph is unambiguous
   and the bar has no room for the word. */
.masthead nav .nav-theme {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  margin-left: .5rem;
  background: rgb(255 255 255 / .06);
  border: 1px solid rgb(255 255 255 / .14);
  border-radius: var(--radius);
  color: var(--gold-pale);
  cursor: pointer;
  flex: none;
}
.masthead nav .nav-theme:hover { border-color: var(--gold); color: var(--gold-lift); }
.masthead nav .nav-theme svg { width: 1.05rem; height: 1.05rem; }
.masthead nav .nav-theme .theme-label { display: none; }

.nav-toggle {
  display: none;
  margin-left: auto;
  background: none;
  border: 1px solid rgb(255 255 255 / .25);
  color: var(--gold-pale);
  padding: .45rem .7rem;
  border-radius: var(--radius);
  font: inherit;
  font-size: .8rem;
  cursor: pointer;
}

@media (max-width: 62rem) {
  .nav-toggle { display: block; }
  .masthead nav {
    display: none;
    order: 3;
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-bottom: .75rem;
  }
  .masthead nav.open { display: flex; }
  /* .85rem of padding, not .7rem: with the line box this clears the ~44px
     minimum touch target. At the old size adjacent items were close enough
     that a thumb landing between two of them was a coin toss, and the cost of
     guessing wrong in a navigation menu is a whole page load. */
  .masthead nav a { padding: .85rem .25rem; border-bottom: 1px solid rgb(255 255 255 / .07); }
  .masthead nav a.nav-cta { margin: .6rem 0 0; text-align: center; padding: .7rem; }
}

/* ---------------------------------------------------------------------- */
/* hero                                                                    */
/* ---------------------------------------------------------------------- */
/* The hero is a dark sepia stage in both themes. Layer order, back to
   front: base gradient, arcade silhouette, converging data streams on
   canvas, flanking columns, then the inscription. Every decorative layer is
   aria-hidden; a screen reader hears only the words. */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(4.5rem, 12vw, 9rem) clamp(3rem, 7vw, 5rem);
  background:
    radial-gradient(120% 90% at 50% 8%, #4a3f2c 0%, #2a2419 42%, var(--night) 100%);
  color: #f0e9d8;
  text-align: center;
}
.hero::after {
  /* A film grain, so the flat gradient reads as aged plaster rather than
     as a CSS gradient. Cheap: one repeating SVG turbulence, no image. */
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: .16;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

/* ---- the rotating stage ------------------------------------------------
   Real captures of the real ventures, cycling behind the inscription.

   They are treated hard on purpose — desaturated, pushed warm, darkened,
   slowly scaled — because an untreated screenshot behind a headline reads as
   a screenshot and fights the words for attention. Treated this way it reads
   as what it is: the work, out of focus, behind the name.

   Three properties this must keep:
     - the inscription stays legible over EVERY plate, which is what the
       scrim below guarantees rather than hopes for;
     - nothing here is content, so the whole stage is aria-hidden and a
       screen reader never meets it;
     - with reduced motion it holds one plate and stops. A slow cross-fade is
       still motion, and "subtle" is not an exemption.

   Drop different files in and it keeps working: the plate list lives in the
   HTML, not here. */

.hero-stage {
  position: absolute;
  inset: 0;
  z-index: -2;               /* above the element's own gradient, below the
                                grain, arcade, columns and streams */
  overflow: hidden;
  pointer-events: none;
}

/* A real <img> rather than a background-image, and not for tidiness.
   A relative `url()` written into a CUSTOM PROPERTY is resolved against the
   stylesheet that substitutes it, not against the document — so
   `--img:url('assets/img/x.jpg')` consumed by a rule in assets/mtg.css asks
   for assets/assets/img/x.jpg and silently renders nothing. An `src` has no
   such ambiguity, is rewritten by the same pass that rewrites every other
   link, and shares its cache entry with the identical tile image below. */
.hero-plate {
  position: absolute;
  inset: 0;
  margin: 0;
  overflow: hidden;
  /* Warm, but no longer monochrome. It was `grayscale(1) sepia(.5)` at 72%
     opacity under a scrim reaching 80% black, and the operator's verdict was
     that the plates were simply hidden. Holding grayscale back to .45 lets
     each venture keep a trace of its own colour while the sepia still stops
     six unrelated palettes from making the hero change hue every six
     seconds. Brightness up, because everything above it darkens. */
  filter: grayscale(.45) sepia(.32) contrast(1.05) brightness(1.02) saturate(1.05);
  opacity: 0;
  transform: scale(1.06);
  transition: opacity 1.6s ease;
  will-change: opacity, transform;
}
.hero-plate img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: center top;
  display: block;
  /* Blurred hard, and this is the load-bearing line in the whole stage.
     These captures are of pages that have their OWN headlines, and an
     unblurred one puts a second headline directly behind "Strength and
     Honour" — two sets of words competing at the same size, which is worse
     than no picture at all. Blurred, a screenshot stops being readable and
     becomes what it is wanted for: colour, movement and depth.
     Scaled slightly larger than the frame so the blur's soft edge is
     cropped away rather than showing as a pale border. */
  /* Blur, then the water. `url(#ripple)` is the SVG displacement filter in
     the hero markup; browsers that cannot resolve it drop that one function
     and keep the blur, which is the correct degradation. */
  /* 7px hid the picture along with the headline behind it. 3px still stops a
     screenshot's own headline from being READ — which is the whole job — but
     leaves a recognisable shape, so the stage looks like the work rather
     than like coloured fog. */
  filter: blur(3px) url(#ripple);
  transform: scale(1.1);
}
.hero-plate.is-on {
  opacity: .95;
  animation: kenburns 14s ease-out forwards;
}

@keyframes kenburns {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to   { transform: scale(1.17) translate3d(0, -1.5%, 0); }
}

/* The scrim. Two jobs: hold contrast under the gold inscription no matter
   what is behind it, and keep the bottom edge dark enough for the band of
   buttons. Sits inside the stage so it is always above every plate. */
.hero-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Lightened with the plates, but NOT uniformly. The dark is concentrated
     where the words are and released towards the edges, so contrast under
     the quotation is unchanged while the picture is visible around it.
     Reversing that — an even, weaker scrim — would show more of the plate
     and make the type harder to read, which is the wrong trade. */
  background:
    radial-gradient(58% 46% at 50% 40%, rgb(18 19 22 / .60) 0%, rgb(18 19 22 / .34) 62%, transparent 100%),
    linear-gradient(180deg, rgb(18 19 22 / .48) 0%, rgb(18 19 22 / .10) 42%, rgb(18 19 22 / .62) 100%);
}

/* Which venture is behind the words right now. Small, factual, and the only
   part of the stage a person can click. */
.hero-now {
  position: absolute;
  left: 50%;
  bottom: clamp(.9rem, 2.5vw, 1.6rem);
  translate: -50% 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: .7rem;
}
.hero-now .dots { display: flex; gap: .38rem; }
.hero-now .dot {
  width: .42rem;
  height: .42rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgb(234 217 168 / .3);
  cursor: pointer;
  transition: background .2s, transform .2s;
}
.hero-now .dot[aria-current="true"] { background: var(--gold-lift); transform: scale(1.35); }
.hero-now .dot:hover { background: var(--gold-pale); }
.hero-now .label {
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgb(240 233 216 / .5);
  min-width: 9rem;          /* reserved, so a longer name cannot shift the dots */
  text-align: left;
}
@media (max-width: 40rem) { .hero-now .label { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .hero-plate { transition: none; }
  .hero-plate.is-on { animation: none; transform: scale(1.06); }
}

.hero-arcade {
  position: absolute;
  left: 50%; bottom: 0;
  translate: -50% 0;
  width: 130%;
  max-width: none;
  height: 62%;
  z-index: -1;
  color: var(--gold-pale);
  opacity: .09;
  pointer-events: none;
}

#streams {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
}

.hero-cols {
  position: absolute;
  inset: 12% 0 8%;
  z-index: -1;
  display: flex;
  justify-content: space-between;
  padding-inline: clamp(.5rem, 5vw, 5rem);
  color: var(--gold-pale);
  opacity: .17;
  pointer-events: none;
}
.hero-cols svg { width: clamp(2rem, 5vw, 3.4rem); height: 100%; }
@media (max-width: 48rem) { .hero-cols { display: none; } }

/* ---- water ------------------------------------------------------------
   Two layers, and neither is the picture itself.

   The FILTER bends the plate a few pixels along a slowly drifting noise
   field. That is what reads as looking through water rather than at a
   photograph — the movement is in the surface, not in the subject, so it
   never competes with the words.

   The RINGS are three expanding circles on very long, offset cycles. They
   are what makes it read as water specifically rather than as generic
   drift: a ripple has an origin and a direction.

   Both cost real GPU time on a large area, so both stop when the tab is
   hidden (the filter via the browser, the rings via animation-play-state)
   and both are removed outright under prefers-reduced-motion. */

.hero-fx { position: absolute; width: 0; height: 0; overflow: hidden; }

/* The hero's timed rings are gone with the splash's, and for the same reason.
   What replaces them is `.water-hero` — the same pointer-driven component,
   declared with the splash's. */

.hero .kicker {
  display: inline-block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .38em;
  text-transform: uppercase;
  color: var(--gold-lift);
  margin-bottom: 1.4rem;
  padding-left: .38em;   /* optical: tracking adds space only on the right */
}

/* The inscription. Wide tracking and a warm gold gradient across the
   letterforms, which is what makes carved stone read as carved stone. */
.hero h1 {
  font-size: clamp(2.1rem, 1rem + 6.4vw, 5.5rem);
  letter-spacing: clamp(.04em, .6vw, .13em);
  line-height: 1.06;
  text-transform: uppercase;
  margin: 0;
  background: linear-gradient(180deg, var(--gold-pale) 0%, var(--gold-lift) 48%, #9a7a24 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  padding-left: .1em;
  /* The letterforms are a gradient clipped to text, so they cannot carry a
     text-shadow (the shadow would be clipped away with everything else).
     A drop-shadow filter applies to the rendered result instead, and it is
     what keeps the inscription readable over a photographic plate rather
     than only over the flat gradient this was designed against. */
  filter: drop-shadow(0 2px 10px rgb(0 0 0 / .55));
}
@supports not (background-clip: text) { .hero h1 { color: var(--gold-lift); } }

.hero .sub {
  margin: 1.6rem auto 0;
  max-width: 40rem;
  color: rgb(240 233 216 / .82);
  font-size: clamp(1rem, .95rem + .3vw, 1.2rem);
}

/* ---- the rotating quotation -------------------------------------------
   One at a time, cross-faded with the picture behind it.

   The stack is absolutely positioned inside a fixed-height box rather than
   flowing: quotes vary from eight words to thirty, and letting them flow
   would move the buttons under them up and down every fifteen seconds,
   which is the single most irritating thing a rotating hero can do. The box
   is tall enough for the longest one at every width. */

.hero-quotes {
  position: relative;
  min-height: 11rem;
  display: grid;
  place-items: center;
  margin-inline: auto;
  max-width: 46rem;
}
@media (max-width: 40rem) { .hero-quotes { min-height: 15rem; } }

.hero-q {
  grid-area: 1 / 1;
  margin: 0;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .9s ease, transform .9s ease;
  pointer-events: none;
}
.hero-q.is-on { opacity: 1; transform: none; pointer-events: auto; }

.hero-q blockquote {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(1.35rem, 1rem + 1.9vw, 2.5rem);
  line-height: 1.28;
  letter-spacing: .005em;
  text-wrap: balance;
  color: #f2ecdd;
  text-shadow: 0 2px 14px rgb(0 0 0 / .55);
}
.hero-q blockquote::before { content: "\201C"; }
.hero-q blockquote::after  { content: "\201D"; }

.hero-q figcaption {
  margin-top: 1rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gold-lift);
}
/* A short rule above the attribution — the mark that separates a saying from
   the person who said it, without an em-dash doing the work. */
.hero-q figcaption::before {
  content: "";
  display: block;
  width: 2.2rem;
  height: 1px;
  background: var(--gold);
  opacity: .7;
  margin: 0 auto .7rem;
}

.hero-cta { margin-top: clamp(1.75rem, 4vw, 2.75rem); }

@media (prefers-reduced-motion: reduce) {
  .hero-q { transition: none; }
  /* The displacement filter is animated by SMIL, which this query cannot
     reach — so the filter is dropped entirely rather than left frozen. */
  .hero-plate img { filter: blur(3px) !important; }
}

/* Quotation, set left as in the reference, italic serif. */
.hero-quote {
  font-family: var(--display);
  font-style: italic;
  font-size: clamp(.95rem, .9rem + .3vw, 1.15rem);
  line-height: 1.5;
  color: rgb(240 233 216 / .72);
  border-left: 2px solid var(--imperial-lift);
  padding-left: 1rem;
  margin: 0;
  text-align: left;
  max-width: 22rem;
}
.hero-quote cite { display: block; font-style: normal; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; color: var(--gold); margin-top: .5rem; }

/* The three-column band under the title: quote, buttons, scroll cue. */
.hero-band {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 2rem;
  margin-top: clamp(2rem, 5vw, 3.5rem);
}
.hero-band > :last-child { justify-self: end; }
@media (max-width: 60rem) {
  .hero-band { grid-template-columns: 1fr; justify-items: center; }
  .hero-band > :last-child { justify-self: center; }
  .hero-quote { text-align: center; border-left: 0; border-top: 2px solid var(--imperial-lift); padding: .9rem 0 0; }
}

.scroll-cue {
  border: 1px solid rgb(234 217 168 / .35);
  background: rgb(234 217 168 / .07);
  padding: .9rem 1.1rem;
  text-align: left;
  text-decoration: none;
  display: block;
  min-width: 11rem;
}
.scroll-cue small {
  display: block;
  font-size: .62rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: rgb(240 233 216 / .55);
}
.scroll-cue b {
  display: block;
  font-family: var(--display);
  font-size: 1rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--gold-pale);
  margin-top: .35rem;
}
.scroll-cue svg { width: 1rem; height: 1rem; color: var(--gold); margin-top: .3rem; animation: nudge 2.4s ease-in-out infinite; }
.scroll-cue:hover { background: rgb(234 217 168 / .14); border-color: var(--gold); }
@keyframes nudge { 0%,100% { transform: translateY(0); } 50% { transform: translateY(4px); } }
@media (prefers-reduced-motion: reduce) { .scroll-cue svg { animation: none; } }

/* ---------------------------------------------------------------------- */
/* splash — the door                                                       */
/* ---------------------------------------------------------------------- */
/* HIDDEN IS THE DEFAULT, AND THAT IS THE IMPORTANT PART.
   The markup for the splash is in index.html unconditionally, but nothing
   here shows it until the inline script in <head> puts `data-splash` on the
   root element. No script, no attribute, no curtain: a crawler, a reader
   mode, a text browser and anyone with JavaScript off all get the site
   itself. A welcome screen is a nice thing to have and a terrible thing to
   require.

   The splash is dark in both themes for the same reason the hero band is —
   it is a lit stage. Nothing in this block reads a themed surface token. */

.splash { display: none; }

:root[data-splash] {
  /* The page underneath is fully rendered; it just must not scroll behind
     the curtain, and must not be reachable by tab. */
  overflow: hidden;
}
:root[data-splash] body { overflow: hidden; }

:root[data-splash] .splash {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  /* `minmax(0, 1fr)` rather than leaving the track implicit. An `auto` track
     is allowed to size to its content, and the minimum of an auto track is
     min-content — so a long unbreakable string could widen it past the
     viewport, where `overflow: hidden` below would silently trim the ends
     off a sentence. Pinning the track to the container removes that whole
     class of failure rather than relying on the copy staying short. */
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  overflow: hidden;
  background: var(--night);
  isolation: isolate;
  animation: splash-in .6s ease both;
}

/* Dismissal. The curtain lifts and fades at once; `visibility` is in the
   transition so the finished state is genuinely out of the way rather than a
   transparent sheet still swallowing clicks. */
.splash.is-out {
  opacity: 0;
  visibility: hidden;
  transform: scale(1.04);
  transition: opacity .5s ease, transform .5s ease, visibility 0s linear .5s;
  pointer-events: none;
}

@keyframes splash-in { from { opacity: 0; } to { opacity: 1; } }

.splash-plate { position: absolute; inset: 0; }
.splash-plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The plate carries a Sanskrit invocation across its lower left. Holding
     the crop to the right of centre keeps that text, and the figure it sits
     under, on screen when a phone crops a 16:9 plate to a tall window. */
  object-position: center;
  animation: splash-drift 26s ease-out both;
}
/* Taller than wide, the plate cannot be shown at all — a 16:9 painting in a
   phone window loses two thirds of its width. Given the choice of which
   third to keep, keep the left: the invocation is written there, and losing
   the end of a Sanskrit verse is worse than losing the right-hand figure. */
@media (max-aspect-ratio: 1/1) {
  .splash-plate img { object-position: 34% 50%; }
}
@keyframes splash-drift { from { transform: scale(1.06); } to { transform: scale(1); } }

/* THE WATER.
   Transparent, and with NO standing rings. It used to draw concentric
   hairlines from the centre plus three circles expanding on a timer, and the
   operator's note on it was exact: that reads as a printed target laid over
   the painting. Real water is flat until something touches it.

   So what is left is only what glass genuinely does — a faint refraction of
   what is behind it, one wide sweep of light so it reads as a surface rather
   than a filter, and a vignette that buys the type its contrast. Everything
   under 8% alpha. The ripples now come from the pointer; see `.water`. */
.splash-glass {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-backdrop-filter: blur(2px) saturate(1.06);
  backdrop-filter: blur(2px) saturate(1.06);
  background:
    linear-gradient(118deg, transparent 34%, rgb(255 255 255 / .05) 50%, transparent 66%),
    radial-gradient(52% 40% at 50% 42%, rgb(8 9 11 / .52) 0%, rgb(8 9 11 / .26) 58%, transparent 80%),
    radial-gradient(125% 95% at 50% 44%, transparent 26%, rgb(8 9 11 / .58) 100%);
}

/* ---- pointer ripples ---------------------------------------------------
   One component, used by the splash and by the hero. `mtg.js` inserts an
   <i> at the pointer and removes it when its animation ends; nothing here
   runs on a timer, so an idle page costs nothing and there is no ambient
   motion to exempt under prefers-reduced-motion — the script simply declines
   to spawn.

   `pointer-events: none` on the layer matters twice: the ripple must not
   swallow the click on the button underneath it, and the pointermove that
   creates it is listened for on the CONTAINER, not on this. */
.water {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.water-hero { z-index: -2; }

.water i {
  position: absolute;
  /* Sized and positioned by the script in px; the element is centred on the
     pointer by its own translate rather than by margins, so one rule works
     at every size the script picks. */
  border-radius: 50%;
  border: 1px solid rgb(234 217 168 / .34);
  /* A touch of light inside the ring, so it reads as a depression in a
     surface rather than as a drawn circle. */
  background: radial-gradient(circle, rgb(255 255 255 / .07) 0%, transparent 62%);
  translate: -50% -50%;
  scale: 0;
  opacity: 0;
  animation: water-ring 1.15s cubic-bezier(.16, .72, .28, 1) forwards;
}
@keyframes water-ring {
  0%   { scale: .08; opacity: 0; }
  14%  { opacity: .8; }
  100% { scale: 1; opacity: 0; }
}

.splash-inner {
  position: relative;
  z-index: 1;
  text-align: center;
  padding: var(--gap);
  /* Sits above the true centre. The lower third of the plate carries the
     invocation; the type belongs in the sky, not on top of the writing. */
  padding-bottom: clamp(4rem, 20vh, 12rem);
  /* `width` as well as `max-width`, so `justify-items: center` above centres
     a block that already fills the track instead of one shrink-wrapped to
     its longest line. Without it the padding below would hug the copy rather
     than the edge of the screen. */
  width: 100%;
  max-width: 46rem;
  animation: splash-rise .8s .15s cubic-bezier(.2, .7, .3, 1) both;
}
@keyframes splash-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

.splash-eyebrow {
  margin: .9rem 0 0;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .42em;
  text-transform: uppercase;
  color: var(--gold-lift);
}
.splash-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2rem, 6vw, 3.6rem);
  line-height: 1.08;
  letter-spacing: .01em;
  text-wrap: balance;
  margin: .7rem 0 0;
  color: #f6efdf;
  text-shadow: 0 2px 30px rgb(0 0 0 / .6);
}
.splash-sub {
  margin: 1rem auto 0;
  max-width: 34rem;
  color: rgb(240 233 216 / .82);
  font-size: clamp(.95rem, 1.6vw, 1.05rem);
  text-shadow: 0 1px 14px rgb(0 0 0 / .6);
}
.splash-cta { margin-top: clamp(1.6rem, 4vw, 2.4rem); }

/* The music control. Lives outside the splash because it outlives it: hidden
   until either the curtain is up or something is genuinely playing. */
.sound-dock {
  position: fixed;
  right: clamp(.75rem, 2.5vw, 1.5rem);
  bottom: clamp(.75rem, 2.5vw, 1.5rem);
  z-index: 210;
  display: none;
}
:root[data-splash] .sound-dock,
.sound-dock.is-live { display: block; }

/* No music on a phone. Last, so it beats both rules above.

   The dock was already honest — nothing autoplays, the file is `preload="none"`
   and is not fetched until the button is pressed, and the preference is
   deliberately not remembered. That is the right behaviour on a desktop, where
   a soundtrack is a choice someone makes in their own room.

   A phone is not that room. It is carried into offices, trains and waiting
   rooms, it is where a mis-tap costs the most, and it is where the 700KB the
   track would cost is least affordable. So on small screens the control is
   simply not offered. `display: none` also removes it from the tab order and
   from a screen reader, which a visibility trick would not. */
@media (max-width: 46rem) {
  :root[data-splash] .sound-dock,
  .sound-dock,
  .sound-dock.is-live { display: none; }
}

.sound-btn {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--body);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .5rem .85rem;
  border-radius: var(--radius);
  border: 1px solid rgb(234 217 168 / .38);
  background: rgb(10 11 13 / .55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--gold-pale);
  cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.sound-btn:hover { border-color: var(--gold); color: var(--gold-lift); }

/* Three bars. Flat while silent, moving while playing — the state is in the
   shape as well as the label, so it survives being read at a glance. */
.sound-icon { display: inline-flex; align-items: center; gap: 2px; height: 12px; }
/* Full height with a scale on top of it, rather than an animated `height`:
   the bars are decoration, and decoration has no business asking for layout
   twice a second. */
.sound-icon i {
  width: 2px;
  height: 12px;
  background: currentColor;
  border-radius: 1px;
  transform: scaleY(.34);
  transition: transform .2s;
}
.sound-btn[aria-pressed="true"] .sound-icon i { animation: sound-bar .9s ease-in-out infinite; }
.sound-btn[aria-pressed="true"] .sound-icon i:nth-child(2) { animation-delay: .18s; }
.sound-btn[aria-pressed="true"] .sound-icon i:nth-child(3) { animation-delay: .36s; }
@keyframes sound-bar { 0%, 100% { transform: scaleY(.34); } 50% { transform: scaleY(1); } }

@media (prefers-reduced-motion: reduce) {
  :root[data-splash] .splash { animation: none; }
  .splash-plate img,
  .splash-inner { animation: none; }
  /* The script does not spawn ripples under reduced motion, so there is
     nothing here to hide. This stays as the belt to that braces. */
  .water { display: none; }
  .splash-glass { -webkit-backdrop-filter: none; backdrop-filter: none; }
  .sound-btn[aria-pressed="true"] .sound-icon i { animation: none; transform: scaleY(1); }
}

/* ---------------------------------------------------------------------- */
/* buttons                                                                 */
/* ---------------------------------------------------------------------- */

.cta-row { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  font-family: var(--body);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: .85rem 1.5rem;
  border-radius: var(--radius);
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s, transform .15s;
}
.btn:active { transform: translateY(1px); }

.btn-solid  {
  position: relative;
  overflow: hidden;
  background: var(--gold);
  color: var(--night);
  border-color: var(--gold);
}
.btn-solid:hover { background: var(--gold-lift); color: var(--night); }
/* A light sweeping across the face on hover — the way a raised gold surface
   catches a lamp when you move past it. Transform only, so it composites on
   the GPU and never triggers layout; and it is on the PRIMARY action alone,
   because an effect every button has is an effect nobody notices. */
.btn-solid::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgb(255 255 255 / .5), transparent);
  transform: translateX(0);
  transition: transform .55s ease;
  pointer-events: none;
}
.btn-solid:hover::after { transform: translateX(360%); }
@media (prefers-reduced-motion: reduce) {
  .btn-solid::after { display: none; }
}

.btn-ghost  { background: transparent; color: var(--gold-pale); border-color: rgb(234 217 168 / .45); }
.btn-ghost:hover { border-color: var(--gold); color: var(--gold-lift); background: rgb(234 217 168 / .08); }

/* On light page surfaces the ghost button needs ink, not parchment. */
.on-page .btn-ghost { color: var(--ink); border-color: var(--line); }
.on-page .btn-ghost:hover { border-color: var(--gold); color: var(--gold); background: transparent; }

.btn-block { width: 100%; }
.btn-sm { padding: .55rem 1rem; font-size: .7rem; }

/* ---------------------------------------------------------------------- */
/* hero image strip — four framed portraits                                */
/* ---------------------------------------------------------------------- */
/* The four empty portrait frames that used to live here are GONE, on the
   operator's instruction. They were placeholders for gladiator imagery, and
   that imagery now belongs to the rotating hero stage above (`.hero-stage`)
   rather than to four boxes below the fold saying "img/family.jpg".

   Nothing references `.portrait` any more. If a picture wall comes back it
   should come back as a deliberate design decision, not as the residue of
   this one. */

/* ---------------------------------------------------------------------- */
/* venture tiles with preview                                              */
/* ---------------------------------------------------------------------- */
/* Each tile carries a real capture of the destination, taken at 1440x900 and
   stored at 640x400 (~30 KB each, six of them under 170 KB in total).
   They WILL go stale when one of those sites is redesigned; `scripts/
   capture-site-previews.ps1` retakes the set in one command, and the tile
   degrades to its colourway rather than to a broken image if a file is
   missing. */

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1.1rem;
  margin-top: 1.75rem;
}

.tile {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius-img);
  text-decoration: none;
  color: inherit;
  overflow: hidden;
  transition: border-color .18s, transform .18s, box-shadow .18s;
}
.tile:hover { border-color: var(--gold); transform: translateY(-3px); box-shadow: var(--shadow-lift); color: inherit; }

/* The preview panel. --a and --b are still set per tile: they are what shows
   through before the capture has loaded, and what remains if the file is
   ever missing, so the tile never collapses to a white rectangle. */
.tile-preview {
  position: relative;
  aspect-ratio: 16 / 10;      /* the capture's own ratio — 640x400 */
  background: linear-gradient(135deg, var(--a, #33383f), var(--b, #1c1f24));
  display: grid;
  place-items: center;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
}
.tile-shot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
  /* Slightly cooled and dimmed at rest so six unrelated brand palettes do not
     turn the section into a swatch book; full colour on hover, which also
     gives the tile something to DO when you point at it. */
  filter: saturate(.82) brightness(.94);
  transform: scale(1.01);
  transition: filter .25s ease, transform .35s ease;
}
.tile:hover .tile-shot { filter: none; transform: scale(1.045); }
@media (prefers-reduced-motion: reduce) {
  .tile-shot, .tile:hover .tile-shot { transition: none; transform: none; }
}

/* The one tile with no site to capture yet (the Creator Toolkit) keeps the
   drawn treatment. Deleting this rule would leave it a blank gradient. */
.tile-preview .glyph {
  font-family: var(--display);
  font-size: clamp(1.6rem, 4vw, 2.4rem);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .92);
  text-align: center;
  padding: 0 .75rem 1.2rem;
  line-height: 1.1;
}

/* The host name, over a gradient so it stays readable against whatever the
   top-left of that site happens to be. */
.tile-preview .host {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 2;
  padding: 1.6rem .7rem .45rem;
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .04em;
  text-align: center;
  color: rgb(255 255 255 / .82);
  background: linear-gradient(180deg, transparent, rgb(0 0 0 / .72));
}

.tile-body { padding: 1rem 1.1rem 1.2rem; display: flex; flex-direction: column; gap: .3rem; flex: 1; }
.tile-body b { font-family: var(--display); font-size: 1.05rem; letter-spacing: .02em; }
.tile-body span { color: var(--ink-soft); font-size: .875rem; }
.tile-body .kind {
  margin-top: auto;
  padding-top: .65rem;
  font-size: .65rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold);
}

.tile .boss {
  position: absolute;
  top: .55rem; right: .55rem;
  width: 1.4rem; height: 1.4rem;
  color: rgb(255 255 255 / .55);
  z-index: 2;
  /* It now sits over a photograph rather than a flat gradient, and a pale
     line over a pale screenshot is an invisible line. The shadow is what
     keeps it readable on every one of the six without knowing any of them. */
  filter: drop-shadow(0 1px 2px rgb(0 0 0 / .75));
  transition: color .2s ease, rotate .5s ease;
}
/* The shield boss turns gold and rotates a quarter turn as you point at the
   tile — the one flourish on this section, on the ornament rather than on the
   photograph, so the picture is never the thing that moves. */
.tile:hover .boss { color: var(--gold-lift); rotate: 90deg; }
@media (prefers-reduced-motion: reduce) { .tile:hover .boss { rotate: none; } }

/* ---------------------------------------------------------------------- */
/* generic cards, claims, panels                                           */
/* ---------------------------------------------------------------------- */

.cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--gap);
}

.card, .panel {
  position: relative;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius);
  padding: 1.25rem 1.35rem;
}
/* A single gold hairline along the top edge, fading out to both sides. It is
   what stops a page of cards reading as a page of boxes: the eye gets a lit
   edge to find the top of each one by, and it costs nothing. */
.card::before, .panel::before {
  content: "";
  position: absolute;
  inset-inline: -1px;
  top: -1px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold) 50%, transparent);
  opacity: .8;
  pointer-events: none;
}
.card h3 { margin-top: 0; }
.card p:last-child, .panel p:last-child { margin-bottom: 0; }

.claim { display: flex; gap: .9rem; align-items: flex-start; }
.claim svg { flex: none; width: 1.6rem; height: 1.6rem; color: var(--gold); margin-top: .15rem; }
.claim p { margin: 0; }

.note {
  border-left: 3px solid var(--gold);
  background: var(--bg-sunk);
  padding: .9rem 1.1rem;
  border-radius: 0 var(--radius) var(--radius) 0;
}
.note.warn { border-left-color: var(--imperial); }
.note p:last-child { margin-bottom: 0; }

.badge {
  display: inline-block;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: .2rem .5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink-faint);
}
.badge.gold { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 45%, transparent); }
.badge.live { color: #2f7d5b; border-color: #2f7d5b55; }
.badge.warn { color: var(--imperial); border-color: color-mix(in srgb, var(--imperial) 45%, transparent); }

/* Apps, listed as intentions. A fake app-store badge for something that does
   not exist would be the first lie on the page. */
.apps { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1rem; margin-top: 1.5rem; }
.app {
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: .35rem;
  background: var(--bg-sunk);
}
.app b { font-family: var(--display); font-size: 1.05rem; }
.app span:last-child { color: var(--ink-soft); font-size: .875rem; }

/* ---------------------------------------------------------------------- */
/* API                                                                     */
/* ---------------------------------------------------------------------- */

.endpoint {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--mono);
  font-size: .82rem;
}
.endpoint:last-child { border-bottom: 0; }
.endpoint .verb {
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .1em;
  padding: .12rem .4rem;
  border-radius: 2px;
  background: color-mix(in srgb, var(--gold) 20%, transparent);
  color: var(--gold);
  min-width: 3.1rem;
  text-align: center;
}
.endpoint .verb.post { background: color-mix(in srgb, var(--imperial) 18%, transparent); color: var(--imperial); }

pre.code {
  font-family: var(--mono);
  font-size: .8rem;
  line-height: 1.6;
  background: var(--night);
  color: #d6d0c2;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  overflow-x: auto;
}
pre.code .c { color: #8a8578; }
pre.code .s { color: var(--gold-lift); }

/* Pricing, for the creator tool. */
.plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1rem; margin-top: 1.5rem; }
.plan { border: 1px solid var(--line); border-radius: var(--radius); padding: 1.3rem; background: var(--surface); display: flex; flex-direction: column; }
.plan.featured { border-color: var(--gold); box-shadow: var(--shadow); }
.plan h3 { font-size: 1.1rem; margin-bottom: .2rem; }
.plan .price { font-family: var(--display); font-size: 2rem; line-height: 1.2; margin: .4rem 0 .1rem; }
.plan .price small { font-family: var(--body); font-size: .75rem; color: var(--ink-faint); letter-spacing: .06em; }
.plan ul { list-style: none; margin: 1rem 0 1.25rem; padding: 0; display: grid; gap: .45rem; font-size: .88rem; color: var(--ink-soft); }
.plan ul li { padding-left: 1.2rem; position: relative; }
.plan ul li::before { content: "\2022"; position: absolute; left: .25rem; color: var(--gold); }
.plan .btn { margin-top: auto; }

/* ---------------------------------------------------------------------- */
/* tabs — inspiration panel                                                */
/* ---------------------------------------------------------------------- */

.tabs { display: flex; flex-wrap: wrap; gap: .3rem; border-bottom: 1px solid var(--line); margin-bottom: 1.4rem; }
.tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: .6rem .9rem;
  font: inherit;
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  cursor: pointer;
}
.tab:hover { color: var(--ink); }
.tab[aria-selected="true"] { color: var(--gold); border-bottom-color: var(--gold); }

/* ---------------------------------------------------------------------- */
/* knowledge bank                                                          */
/* ---------------------------------------------------------------------- */
/* A sources rail and a question box. The rail is narrow and stays put; the
   answers are the page. On a phone the rail goes UNDER the results rather
   than above them — you came here to ask something, and a list of two book
   titles is not what should meet you at the top of the screen. */

.kb { display: grid; grid-template-columns: 15rem 1fr; gap: 2rem; align-items: start; }
@media (max-width: 54rem) {
  .kb { grid-template-columns: 1fr; gap: 2.5rem; }
  .kb-side { order: 2; }
  .kb-main { order: 1; }
}

.kb-sources { list-style: none; margin: 0 0 1.5rem; padding: 0; display: grid; gap: .1rem; }
.kb-sources a {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding: .4rem .55rem;
  border-radius: var(--radius);
  font-size: .84rem;
  text-decoration: none;
  color: var(--ink-soft);
  border-left: 2px solid transparent;
}
.kb-sources a:hover { background: var(--bg-sunk); color: var(--ink); }
.kb-sources a.is-on { border-left-color: var(--gold); color: var(--gold); background: var(--bg-sunk); }
.kb-sources em,
.kb-branches em { margin-left: auto; font-style: normal; font-family: var(--mono); font-size: .68rem; color: var(--ink-faint); }

.kb-branches ul { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: .1rem; }
.kb-branches a {
  display: flex;
  gap: .5rem;
  padding: .3rem .55rem;
  font-size: .78rem;
  text-decoration: none;
  color: var(--ink-soft);
  border-left: 1px solid var(--line);
}
.kb-branches a:hover { color: var(--gold); border-left-color: var(--gold); }

.kb-ask { display: flex; gap: .5rem; margin-bottom: 1.5rem; }
.kb-ask input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 1rem;
  padding: .8rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}
.kb-ask input:focus-visible { border-color: var(--gold); }
.kb-ask .btn { flex: none; }

/* Visually hidden but read aloud. The question box has a placeholder, and a
   placeholder is not a label. */
.sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.kb-empty { border: 1px dashed var(--line); border-radius: var(--radius); padding: 1.5rem; }
.kb-examples { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1rem; }
.kb-examples a {
  font-size: .8rem;
  text-decoration: none;
  color: var(--ink-soft);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .3rem .8rem;
}
.kb-examples a:hover { border-color: var(--gold); color: var(--gold); }

/* ---- the AI answer ----
   Visually SEPARATE from the passages, and deliberately not dressed as one.
   A generated paragraph styled like a quotation from a book is a generated
   paragraph that will be read as a quotation from a book. Gold rule above,
   its own label, and the passages it drew on sitting underneath it. */

.kb-answer {
  border: 1px solid var(--line);
  border-top: 3px solid var(--gold);
  border-radius: var(--radius);
  background: var(--bg-sunk);
  padding: 1.1rem 1.2rem;
  margin-bottom: 1.5rem;
}
.kb-answer.is-note { border-top-color: var(--line); background: none; border-style: dashed; }
.kb-answer-tag {
  margin: 0 0 .6rem;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold);
}
.kb-answer-body { font-size: 1rem; line-height: 1.6; margin-bottom: .8rem; white-space: pre-wrap; }

.kb-meta { margin: -.8rem 0 1.2rem; }
.kb-ration {
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.kb-ration.is-spent { color: var(--imperial); }

.kb-count { margin-bottom: .8rem; }
.kb-hits { display: grid; gap: .9rem; }
.kb-hit {
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 1rem 1.1rem;
}
.kb-src { font-size: .66rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--gold); margin: 0; }

/* The mind-map path. This is the thing that makes the bank a map rather than
   a pile: every passage says which branch it came from. */
.kb-trail { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; margin: .35rem 0 .6rem; font-size: .72rem; color: var(--ink-faint); }
.kb-trail i { font-style: normal; color: var(--line); }
.kb-text { margin: 0; font-size: .9rem; line-height: 1.6; color: var(--ink-soft); max-width: none; }

/* ---- the reading list ---- */
/* Forty-four titles in seventeen sections. Columns rather than one long list,
   because the value of this panel is being able to find your own subject in
   it, and a 44-item column means scrolling past fifteen books about worms to
   reach the one about risk.

   A GRID, not CSS `columns`. Columns was the first attempt and looked wrong:
   the sections are wildly uneven — one has eight entries, four have one — and
   balancing them across columns while keeping each heading with its own list
   left half-screen gaps between sections. A grid gives ragged bottoms instead
   of ragged middles, which reads as a list of sections rather than as a
   broken layout. */

.readlist {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  align-content: start;
  gap: 1.6rem 2rem;
  margin-top: 1.5rem;
}
.readlist section { margin: 0; }
.readlist h4 {
  font-family: var(--body);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 .5rem;
}
.readlist ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.readlist li {
  font-size: .84rem;
  line-height: 1.4;
  padding-left: .9rem;
  border-left: 1px solid var(--line);
}
.readlist em { color: var(--ink-faint); font-style: normal; font-size: .78rem; }

/* Marks a title whose text is actually parsed into the Knowledge Bank, as
   opposed to one that is merely named. The distinction is the entire honesty
   of the panel: two of forty-four are searchable, and a reader should be able
   to see which two without reading a paragraph about licensing. */
.in-bank {
  display: inline-block;
  margin-top: .25rem;
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #2f7d5b;
  border: 1px solid #2f7d5b55;
  border-radius: 999px;
  padding: .05rem .5rem;
  white-space: nowrap;
}

.res { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: .9rem; }
.res a {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
  padding: .9rem 1rem;
  text-decoration: none;
  color: inherit;
  background: var(--surface);
  transition: border-color .15s, transform .15s;
}
.res a:hover { transform: translateX(3px); border-color: var(--gold); }
.res b { font-size: .95rem; }
.res span { color: var(--ink-soft); font-size: .84rem; }
.res .kind {
  margin-top: .3rem;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--gold);
}

/* ---------------------------------------------------------------------- */
/* forms                                                                   */
/* ---------------------------------------------------------------------- */

.field { display: grid; gap: .35rem; margin-bottom: 1rem; }
.field label { font-size: .72rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
.field input, .field select, .field textarea {
  font: inherit;
  font-size: .95rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: .65rem .8rem;
  width: 100%;
}
.field textarea { min-height: 7rem; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--gold); }
.field .hint { font-size: .78rem; color: var(--ink-faint); }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 34rem) { .field-row { grid-template-columns: 1fr; } }

.check { display: flex; gap: .6rem; align-items: flex-start; font-size: .85rem; color: var(--ink-soft); margin-bottom: 1rem; }
.check input { margin-top: .25rem; flex: none; }

.form-status { font-size: .85rem; color: var(--gold); min-height: 1.3rem; }

/* ---------------------------------------------------------------------- */
/* auth pages                                                              */
/* ---------------------------------------------------------------------- */

.auth {
  min-height: calc(100dvh - 4.25rem);
  display: grid;
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 56rem) { .auth { grid-template-columns: 1fr; } .auth-aside { display: none; } }

.auth-aside {
  position: relative;
  overflow: hidden;
  background: radial-gradient(120% 90% at 30% 10%, #4a3f2c, #22201a 55%, var(--night));
  color: #f0e9d8;
  display: grid;
  align-content: center;
  padding: clamp(2rem, 5vw, 4rem);
}
.auth-aside .hero-arcade { opacity: .1; height: 50%; }
.auth-aside h2 { font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem); letter-spacing: .08em; text-transform: uppercase;
  background: linear-gradient(180deg, var(--gold-pale), #9a7a24); -webkit-background-clip: text; background-clip: text; color: transparent; }
.auth-aside p { color: rgb(240 233 216 / .75); }
.auth-aside ul { list-style: none; padding: 0; margin: 1.5rem 0 0; display: grid; gap: .7rem; }
.auth-aside li { display: flex; gap: .7rem; align-items: flex-start; font-size: .9rem; color: rgb(240 233 216 / .82); }
.auth-aside li svg { flex: none; width: 1.1rem; height: 1.3rem; color: var(--gold); }

.auth-form { display: grid; align-content: center; padding: clamp(2rem, 5vw, 4rem); }
.auth-form .inner { width: min(100%, 25rem); margin-inline: auto; }
.auth-alt { font-size: .875rem; color: var(--ink-faint); margin-top: 1.25rem; }

/* ---------------------------------------------------------------------- */
/* dashboard shell                                                         */
/* ---------------------------------------------------------------------- */
/* A TOP BAR, not a side rail, on the operator's instruction — and the change
   is not only cosmetic. The side rail was a 15rem column that never
   collapsed, so the content beside it ran the full remaining width of a
   27-inch monitor: tables stretched to 1,900px, a two-column row put its two
   cards a hand's width apart, and every line of prose broke at 160
   characters. That is what "too wide and out of proportion" was.
   The bar hands the whole viewport back to `.wrap`, which is the same
   70rem measure every other page on the site is set to, so the dashboard now
   lines up with the marketing pages instead of being a different shape.

   The bar reuses `.masthead` for the shell — same height, same sticky
   behaviour, same blur — and only adds what a nav of BUTTONS needs that a nav
   of links does not. */

.app-bar nav { margin-left: auto; }

.app-nav {
  display: flex;
  align-items: center;
  gap: .15rem;
  flex-wrap: wrap;
}
/* The member dashboard switches panels in the browser, so its nav is BUTTONS.
   The admin panel has one route per section, so its nav is LINKS. They must
   look identical — a person moving between the two should not be able to tell
   that one of them reloads — so both selectors carry the same rules rather
   than the link inheriting an approximation. */
.app-nav button,
.app-nav a.app-link {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  background: none;
  border: 0;
  border-radius: var(--radius);
  padding: .45rem .7rem;
  font: inherit;
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .7);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
}
/* Home leaves the page; the buttons beside it switch panels within it. Same
   size and rhythm so the row reads as one navigation, one hairline between
   them so the difference is visible before you click. */
.app-nav .app-home {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .45rem .7rem;
  margin-right: .45rem;
  border-right: 1px solid rgb(255 255 255 / .14);
  border-radius: var(--radius) 0 0 var(--radius);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: rgb(255 255 255 / .7);
  text-decoration: none;
  white-space: nowrap;
}
.app-nav .app-home svg { width: 1rem; height: 1rem; flex: none; }
.app-nav .app-home:hover { color: var(--gold-lift); }

.app-nav button svg,
.app-nav a.app-link svg { width: 1rem; height: 1rem; flex: none; }
.app-nav button:hover,
.app-nav a.app-link:hover { color: var(--gold-lift); background: rgb(255 255 255 / .06); }
.app-nav button[aria-current="true"],
.app-nav a.app-link[aria-current="page"] {
  color: var(--gold-lift);
  background: rgb(255 255 255 / .06);
  /* An underline as well as a colour: on the one screen where a person needs
     to know exactly where they are, colour alone is not enough for anyone who
     cannot distinguish it. */
  box-shadow: inset 0 -2px 0 var(--gold);
}

/* Theme toggle and sign-out, at the far right of the bar. Compact: they are
   used rarely and must not compete with the section names. */
.app-tools {
  display: flex;
  align-items: center;
  gap: .4rem;
  margin-left: .6rem;
  padding-left: .8rem;
  border-left: 1px solid rgb(255 255 255 / .12);
}
.app-tools .theme-toggle { width: auto; padding: .42rem .6rem; font-size: .66rem; }
.app-tools .theme-label { display: none; }   /* the icon carries it up here */
.app-tools .logout-form { display: inline-flex; }

/* Log out is a CTA, and it is the SAME CTA as the public masthead's Log in —
   gold, on the operator's instruction. It was crimson, which made the two
   read as opposites: crimson on this site means alert, and leaving is not an
   alarm. They occupy the same slot in the bar, so signed out you see one call
   to action there and signed in the other, now in one colour. */
.app-tools .logout {
  width: auto;
  padding: .45rem .85rem;
  font-size: .68rem;
  gap: .4rem;
  background: var(--gold);
  border-color: var(--gold);
  color: var(--night);
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  border-radius: var(--radius);
  white-space: nowrap;
}
.app-tools .logout svg { width: .95rem; height: .95rem; flex: none; }
.app-tools .logout:hover { background: var(--gold-lift); color: var(--night); border-color: var(--gold-lift); }

/* The same breathing room the public masthead got. */
.app-bar .wrap { padding-block: .5rem; min-height: 4.6rem; }
.app-tools .nav-font { padding: .42rem .55rem; }

/* ---- the stacked mark, and why the bar needs one --------------------------
   The app bar carries six sections and three tools; the public masthead
   carries five links and one button. Same shell, nearly twice the contents,
   so the piece that has to give is the one that is fixed-width and says the
   least: the name, which the person reading it has already seen on every page
   that got them here.

   Two lines at .82rem instead of one at 1.02rem is roughly a third of the
   width back, spent on height the bar already had (min-height 4.6rem against
   a 2.1rem logo). Scoped to `.app-bar` — the marketing masthead has room and
   is where the name is doing real work. */
.app-bar .mark-stack {
  gap: .55rem;
  align-items: center;
  line-height: 1.05;
}
.app-bar .mark-stack .mark-words {
  display: flex;
  flex-direction: column;
  font-size: .82rem;
  letter-spacing: .13em;
}
.app-bar .mark-stack img { width: 2.3rem; height: 2.3rem; }

/* The nav takes the width the mark gave up, and keeps it on ONE line.
   `flex-wrap: wrap` let it drop QuantDesk — the last item, and the only one on
   this bar anybody signs in for — onto a second row, where it read as a
   different kind of thing from the five above it. It now shrinks and, at the
   point where shrinking is not enough, scrolls: the same behaviour the phone
   layout has always had, rather than a second row that changes what the
   navigation appears to mean. */
.app-bar .app-nav {
  flex-wrap: nowrap;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.app-bar .app-nav::-webkit-scrollbar { display: none; }
/* Tightened just enough to make six fit at a laptop width. Below this the
   labels start to run together, so the scroll above is what takes over. */
.app-bar .app-nav button,
.app-bar .app-nav a.app-link,
.app-bar .app-nav .app-home { padding-inline: .55rem; letter-spacing: .1em; }
.app-bar .app-nav .app-home { margin-right: .3rem; }

@media (max-width: 62rem) {
  /* mtg.css hides `.masthead nav` below this width and waits for the hamburger
     to add `.open`. The dashboard has no hamburger — its nav is four buttons
     that scroll — so without this the whole navigation simply vanished on a
     phone. Specificity, not !important: `.masthead.app-bar nav.app-nav` beats
     `.masthead nav` on its own terms. */
  .masthead.app-bar nav.app-nav { display: flex; }
  /* The bar's own flex row does not wrap, so `width:100%` on the nav merely
     squeezes it in beside the logo. Allowing a wrap is what actually gives the
     nav its own line under the mark. */
  .masthead.app-bar .wrap { flex-wrap: wrap; row-gap: 0; }

  .app-bar .app-nav {
    order: 3;
    width: 100%;
    overflow-x: auto;
    /* Explicitly row: the marketing masthead's mobile rule stacks its nav into
       a column, and inheriting that turns four sections into four full-width
       rows above the fold. */
    flex-direction: row;
    align-items: center;
    flex-wrap: nowrap;
    gap: .1rem;
    padding-bottom: .5rem;
    /* Scrolls rather than stacking. A stacked nav of five sections pushes the
       first figure off a phone screen entirely, and the whole point of this
       page is the figure at the top. */
    scrollbar-width: none;
  }
  .app-bar .app-nav::-webkit-scrollbar { display: none; }
  .app-tools { margin-left: auto; }
}

.theme-toggle {
  appearance: none;
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  background: rgb(255 255 255 / .06);
  border: 1px solid rgb(255 255 255 / .12);
  border-radius: var(--radius);
  color: rgb(230 224 210 / .85);
  padding: .5rem .7rem;
  font: inherit;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
}
.theme-toggle:hover { border-color: var(--gold); color: var(--gold-lift); }
.theme-toggle svg { width: 1rem; height: 1rem; }

.logout {
  display: flex; align-items: center; justify-content: center; gap: .5rem;
  border: 1px solid color-mix(in srgb, var(--imperial-lift) 55%, transparent);
  color: var(--imperial-lift);
  background: none;
  border-radius: var(--radius);
  padding: .5rem .7rem;
  font: inherit;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}
.logout:hover { background: color-mix(in srgb, var(--imperial) 16%, transparent); color: var(--imperial-lift); }

/* `section` in mtg.css carries 3-5.5rem of block padding, which is right for
   a marketing page you scroll and wrong for a panel you scan: it pushed the
   first figure most of a screen down. An application view starts near the
   top. */
.app-main { padding-block: 1.5rem 2.5rem; background: var(--bg); min-height: 70dvh; }

.main-head { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.who-block { min-width: 0; }
.who-name {
  font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.1rem);
  margin: 0;
  letter-spacing: .01em;
  overflow-wrap: anywhere;   /* an email address can be long and has no spaces */
}
.who-sub {
  margin: .15rem 0 0;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.panel-view[hidden] { display: none; }

/* Denser than the marketing pages. Six figures that fit on one screen tell
   you more than four that do not. */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); gap: .75rem; margin-bottom: 1.25rem; }
.stat { border: 1px solid var(--line); border-radius: var(--radius); padding: .8rem .9rem; background: var(--surface); }
.stat .k { font-size: .64rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-faint); }
.stat .v {
  font-family: var(--display);
  font-size: 1.45rem;
  line-height: 1.15;
  margin-top: .25rem;
  /* Figures in adjacent tiles have to line up optically, and proportional
     digits in a serif face do not. */
  font-variant-numeric: tabular-nums;
}
.stat .d { font-size: .74rem; color: var(--ink-faint); line-height: 1.4; }
.stat .d.up { color: var(--gain); }
.stat .d.down { color: var(--loss); }

table.data { width: 100%; border-collapse: collapse; font-size: .875rem; }
table.data th, table.data td { text-align: left; padding: .6rem .7rem; border-bottom: 1px solid var(--line-soft); }
table.data th { font-size: .66rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
table.data tbody tr:hover { background: var(--bg-sunk); }
table.data td.num { font-family: var(--mono); text-align: right; }
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }

/* ---------------------------------------------------------------------- */
/* footer                                                                  */
/* ---------------------------------------------------------------------- */

footer {
  background: var(--night);
  color: rgb(230 224 210 / .72);
  padding-block: clamp(2.5rem, 5vw, 3.5rem);
  border-top: 3px solid var(--gold);
}
footer .cols { gap: 2rem; }

/* Five columns that stay on one level, and wrap onto a matching one.
   The generic `.cols` is sized for three, so the fourth and fifth columns
   dropped to a second row that began under the middle of the first — the
   misalignment the operator asked to be tidied. `auto-fit` with a floor
   wide enough for "Refunds & cancellation" keeps every column the same
   width at every breakpoint, so a wrapped row lines up with the one above
   it instead of straddling it. The mark's column is allowed to be wider
   because it holds a logo and a sentence, not a list of links. */
.foot-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 2rem 1.75rem;
  align-items: start;
}
.foot-cols > :first-child { grid-column: span 2; min-width: 0; }
@media (max-width: 40rem) {
  .foot-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot-cols > :first-child { grid-column: 1 / -1; }
}

/* The bottom row. Both explanatory notes live here rather than hanging off
   the end of a column, which used to make that one column taller than its
   neighbours and break the line the row is read along. */
.foot-note {
  margin-top: 2.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid rgb(230 224 210 / .12);
  display: grid;
  gap: .6rem;
}

footer a { color: rgb(230 224 210 / .72); text-decoration: none; display: block; font-size: .875rem; padding: .18rem 0; }
footer a:hover { color: var(--gold-lift); }
footer small { display: block; font-size: .78rem; color: rgb(230 224 210 / .45); }
footer .head { font-size: .68rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--gold); margin-bottom: .5rem; }
footer .mark { margin-bottom: .6rem; }

.meander-band { height: 14px; color: var(--gold); opacity: .5; width: 100%; }

/* ---------------------------------------------------------------------- */
/* scroll reveal                                                           */
/* ---------------------------------------------------------------------- */
/* Opacity and a small lift only. Nothing slides in from off-screen, which
   on a long page is motion sickness rather than delight. */

.reveal { opacity: 0; transform: translateY(12px); transition: opacity .6s ease, transform .6s ease; }
.reveal.in { opacity: 1; transform: none; }

/* Stagger, for the grids only.
   The section as a whole fades in; inside it the tiles arrive one after
   another, 70ms apart. Seven venture tiles appearing simultaneously reads as
   a page finishing loading; the same seven arriving in sequence reads as
   something being laid out for you, and it is the difference between the
   section feeling built and feeling delivered.

   Capped at eight steps. An unbounded `nth-child` delay means a long grid's
   last item waits a second and a half, which stops being a flourish and
   starts being a page that is slow. */
.reveal .tiles > *,
.reveal .apps > *,
.reveal .res > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .5s ease, transform .5s ease;
}
.reveal.in .tiles > *,
.reveal.in .apps > *,
.reveal.in .res > * { opacity: 1; transform: none; }
.reveal.in .tiles > :nth-child(1),
.reveal.in .apps > :nth-child(1),
.reveal.in .res > :nth-child(1) { transition-delay: .05s; }
.reveal.in .tiles > :nth-child(2),
.reveal.in .apps > :nth-child(2),
.reveal.in .res > :nth-child(2) { transition-delay: .12s; }
.reveal.in .tiles > :nth-child(3),
.reveal.in .apps > :nth-child(3),
.reveal.in .res > :nth-child(3) { transition-delay: .19s; }
.reveal.in .tiles > :nth-child(4),
.reveal.in .apps > :nth-child(4),
.reveal.in .res > :nth-child(4) { transition-delay: .26s; }
.reveal.in .tiles > :nth-child(5),
.reveal.in .apps > :nth-child(5),
.reveal.in .res > :nth-child(5) { transition-delay: .33s; }
.reveal.in .tiles > :nth-child(6),
.reveal.in .apps > :nth-child(6),
.reveal.in .res > :nth-child(6) { transition-delay: .4s; }
.reveal.in .tiles > :nth-child(n+7),
.reveal.in .apps > :nth-child(n+7),
.reveal.in .res > :nth-child(n+7) { transition-delay: .47s; }

/* The failure mode of a reveal must never be invisible content: with motion
   reduced, or if the observer never fires, everything is simply shown. */
@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal .tiles > *, .reveal .apps > *, .reveal .res > * {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------------------------------------------------------------------- */
/* reading progress                                                        */
/* ---------------------------------------------------------------------- */
/* A gold hairline across the very top, filling as you read. Two pixels, one
   element, `scaleX` on a transform — no scroll handler, no layout, no cost.
   It is the one piece of chrome that makes a long page feel like it has a
   length, and on a site whose whole argument is "read the uncomfortable part
   before you decide" that is worth having.

   Driven by `animation-timeline: scroll()` where it exists and simply absent
   where it does not, rather than falling back to a JavaScript scroll listener:
   a decorative bar is not worth a handler firing on every frame of every
   scroll. */

.progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  z-index: 90;
  background: linear-gradient(90deg, var(--gold), var(--gold-lift));
  transform-origin: 0 50%;
  transform: scaleX(0);
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  .progress {
    animation: progress-grow linear;
    animation-timeline: scroll(root block);
  }
}
@keyframes progress-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { .progress { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* Print: drop the stage lighting, keep the words. */
/* ---------------------------------------------------------------------- */
/* about, learn and shell additions                                        */
/* ---------------------------------------------------------------------- */

/* ---- the masthead's breathing room -------------------------------------
   The bar is sticky at top:0, so there is no gap to add ABOVE it — what the
   operator was reading as "too close to the top" is the row's contents
   pressed against the viewport edge. So the space goes inside the bar. */
.masthead .wrap { padding-block: .55rem; min-height: 4.9rem; }

/* ---- reader font size --------------------------------------------------
   Three steps, stamped on the root as `data-font`. Everything on this site
   is sized in rem from the root, so one property moves the whole page
   together rather than growing the body copy out of its own headings.

   Not a replacement for the browser's own zoom, which is always available
   and which nobody should be discouraged from using — it is here because a
   control on the page is the one people actually find. */
:root[data-font="lg"] { font-size: 112.5%; }
:root[data-font="xl"] { font-size: 125%; }

.nav-font {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  background: none;
  border: 1px solid rgb(234 217 168 / .28);
  border-radius: var(--radius);
  color: var(--gold-pale);
  cursor: pointer;
  font-family: var(--body);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  padding: .4rem .6rem;
  line-height: 1;
  transition: border-color .15s, color .15s;
}
.nav-font:hover { border-color: var(--gold); color: var(--gold-lift); }
.nav-font .a-sm { font-size: .72em; }
.nav-font .a-lg { font-size: 1.05em; }

/* ---- callout: a heading, a sentence, and one action --------------------- */
.callout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1.25rem 1.4rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
  background: var(--surface);
}
.callout > div { flex: 1 1 22rem; min-width: 0; }
.callout p:last-of-type { margin-bottom: 0; }
.callout-title { font-size: 1.35rem; margin: .1rem 0 .5rem; }

/* ---- video tiles, four across ------------------------------------------ */
.vid-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
}
.vid-tiles > a {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  text-decoration: none;
  color: inherit;
  transition: border-color .15s, transform .15s, box-shadow .15s;
}
.vid-tiles > a:hover { border-color: var(--gold); transform: translateY(-2px); box-shadow: var(--shadow-lift); }

.vid-plate {
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  background: linear-gradient(140deg, var(--a), var(--b));
}
/* The play mark: a triangle from borders inside a rounded rectangle. No
   image, no icon font, and it scales with the tile. */
.vid-plate i {
  display: block;
  width: 3.4rem;
  height: 2.4rem;
  border-radius: .6rem;
  background: rgb(0 0 0 / .55);
  border: 1px solid rgb(255 255 255 / .22);
  position: relative;
}
.vid-plate i::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: .42rem 0 .42rem .68rem;
  border-color: transparent transparent transparent rgb(255 255 255 / .9);
}
.vid-tiles > a:hover .vid-plate i { background: rgb(0 0 0 / .7); }

.vid-body { display: grid; gap: .3rem; padding: .85rem .95rem 1rem; }
.vid-body b { font-size: .95rem; }
.vid-body > span { color: var(--ink-soft); font-size: .84rem; line-height: 1.45; }
.vid-body .kind {
  font-size: .62rem; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-faint);
}

/* ---- the reading list, as covers ---------------------------------------
   Forty-three titles. Thirty-three have a cover from Open Library, saved
   into assets/books/ rather than hotlinked, so the page has no runtime
   dependency on anybody else's image host. The other ten get a typographic
   plate: same size, legible, and it does not read as a broken image the way
   a grey placeholder does. */
.book-tiles { display: grid; gap: 2rem; }
.book-tiles h4 {
  font-size: .68rem; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--gold); margin-bottom: .8rem;
}
.books {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 1.1rem;
}
.books > a {
  display: grid;
  gap: .5rem;
  align-content: start;
  text-decoration: none;
  color: inherit;
}
.book-cover {
  display: block;
  aspect-ratio: 2 / 3;
  border-radius: var(--radius-img);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: var(--shadow);
  transition: transform .15s, box-shadow .15s, border-color .15s;
}
.book-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.books > a:hover .book-cover { transform: translateY(-3px); box-shadow: var(--shadow-lift); border-color: var(--gold); }

/* No cover on Open Library. Set the title on a plate instead. */
.book-plate {
  display: grid;
  align-items: center;
  padding: .8rem .7rem;
  background: linear-gradient(160deg, #33302a, #1b1a17);
}
.book-plate > span {
  font-family: var(--display);
  font-size: .82rem;
  line-height: 1.3;
  color: rgb(240 233 216 / .88);
  text-wrap: balance;
}

.book-meta { display: grid; gap: .1rem; }
.book-meta b { font-size: .8rem; line-height: 1.3; }
.book-meta .by { font-size: .72rem; color: var(--ink-faint); }

/* ---- the founder ------------------------------------------------------- */
.founder {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
}
@media (max-width: 46rem) { .founder { grid-template-columns: minmax(0, 1fr); } }

/* Headings on a narrow phone.

   The global `h1` floor is 2.25rem — 36px — which is set for a tablet and is
   too big for a 360px viewport: a title like "Maximus's Arthashastra" breaks
   into three lines, the negative letter-spacing tightens it further, and the
   result reads as cramped rather than grand. Lowering the FLOOR only leaves
   every larger screen exactly as it was, because above ~380px the middle term
   of the clamp is what applies anyway.

   `text-wrap: balance` so a two-line heading splits evenly instead of leaving
   one orphaned word on the second line; browsers without it simply wrap as
   before. */
@media (max-width: 26rem) {
  h1 { font-size: clamp(1.9rem, 1.4rem + 3.2vw, 4rem); letter-spacing: -.01em; }
  h2 { font-size: clamp(1.35rem, 1.1rem + 1.3vw, 2.25rem); }
  h1, h2 { text-wrap: balance; }
}
.founder-plate { margin: 0; }
/* Grown to 240px now that there is a real photograph behind it.
   It used to be held to 176px because the only source was a 150x159 thumbnail
   embedded in a Word document — enough pixels at 400 dpi to fill the column and
   nowhere near enough sharpness, so it read as a blurred enlargement rather
   than a portrait. The file is now a 480x480 square crop of a 4623x3460
   original, which is exactly 2x this plate: retina-sharp, and no larger than
   that.

   `aspect-ratio: 1` and `object-fit: cover` are explicit here rather than
   left to the img's own width/height attributes, which is what this rule
   used to rely on. That inference is real (browsers have supported it since
   ~2021) but it is inference, not a guarantee — it depends on the UA
   stylesheet applying attr(width)/attr(height) and nothing since overriding
   it, and at least one real report of this photo still rendering elongated
   came in after the file itself was already a verified 480x480 square. An
   explicit ratio does not depend on that chain holding; object-fit: cover
   means a future non-square source gets cropped to fit instead of stretched
   to fit, which is the failure mode worth having if this photo is ever
   swapped for one that isn't square again. */
.founder-plate img {
  width: 100%;
  max-width: 15rem;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-img);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  display: block;
}
.founder-plate figcaption {
  margin-top: .55rem;
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ---- the six tenets ----------------------------------------------------
   Numbered because the source is a numbered list of duties, not because a
   number makes a paragraph look designed. */
.tenets {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0 0;
  display: grid;
  gap: 1rem;
  counter-reset: tenet;
}
.tenets li {
  counter-increment: tenet;
  padding-left: 2.6rem;
  position: relative;
  color: var(--ink-soft);
}
.tenets li::before {
  content: counter(tenet);
  position: absolute;
  left: 0;
  top: .05rem;
  width: 1.8rem;
  height: 1.8rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--gold);
  color: var(--gold);
  font-family: var(--mono);
  font-size: .78rem;
}
.tenets b { display: block; color: var(--ink); }

/* ---- the story's dialogue ---------------------------------------------- */
.on-page blockquote {
  margin: 1.5rem 0;
  padding: .2rem 0 .2rem 1.25rem;
  border-left: 3px solid var(--gold);
  color: var(--ink-soft);
  font-style: italic;
}
.on-page blockquote p:last-child { margin-bottom: 0; }

@media print {
  .masthead, .side, footer, #streams, .hero-cols, .hero-arcade, .scroll-cue { display: none !important; }
  .hero { background: none; color: #000; }
  .hero h1 { color: #000; -webkit-text-fill-color: #000; }
  body { background: #fff; color: #000; }
}
