@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/instrument-serif-normal-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/instrument-serif-italic-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Karla';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/karla-variable.woff2') format('woff2-variations');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-normal-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-normal-500.woff2') format('woff2');
}

/* orchestra.org.uk
 *
 * The home page is the design the user made in Claude Design, rebuilt as plain static files.
 * Two things changed on the way in. The prototype's runtime is gone, because every hover it
 * described is a CSS transition and the site should not ship React to draw a light. And the
 * webfonts are served from here rather than from Google, because a project whose whole argument
 * is that nothing leaves your machine should not call a third party to draw its own name.
 *
 * The pool of light is a solid white ellipse under a blur, not a radial gradient. A gradient is
 * geometry with no relation to the photograph under it and reads as paint. A blurred solid has an
 * edge that falls off the way light does. Inside the pool the page inverts to black on white,
 * because a photograph is bright in some places and black in others and one colour of type cannot
 * survive both.
 *
 * This file is the home page and the 404, and nothing else. Each library draws itself: Harmonica
 * on the light palette its own site was written in, and Accordion on the brass the application's
 * front panel is made of. They were both themed from here at one point, in this ground with this
 * type, and the result was three pages of one design wearing three accents. A library that has a
 * material of its own is worth more than a house style.
 */

:root {
  --ground: #08080a;
  --ink: #f3f2ef;
  --ink-2: rgba(243, 242, 239, .72);
  --ink-3: rgba(243, 242, 239, .5);
  --accent: #cdb894;
  --rule: rgba(255, 255, 255, .12);
  --pool: #ffffff;
  --pool-ink: #0a0a0b;
  --pool-ink-2: rgba(10, 10, 11, .76);

  --display: 'Instrument Serif', Georgia, 'Times New Roman', serif;
  --body: Karla, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace;

  --shell: 1180px;
}

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 400 16px/1.6 var(--body);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent); }
img { max-width: 100%; display: block; }

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 20;
  background: var(--ink); color: var(--ground);
  padding: 12px 18px; font: 600 13px/1 var(--body);
}
.skip:focus { left: 12px; top: 12px; }

.shell { max-width: var(--shell); margin: 0 auto; padding: 0 40px; }

.eyebrow {
  font: 500 11px/1 var(--mono);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow.quiet { color: var(--ink-3); }

h1, h2, h3 { margin: 0; font-family: var(--display); font-weight: 400; text-wrap: balance; }
h1 { font-size: clamp(48px, 5.5vw, 76px); line-height: 1.05; letter-spacing: -.01em; }
h2 { font-size: clamp(30px, 3.4vw, 38px); line-height: 1.12; }
h3 { font-size: 24px; line-height: 1.2; }
em { font-style: italic; color: var(--accent); }

@keyframes bubIn { from { opacity: 0; transform: translateY(16px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes fadeUp { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes slowIn { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: none; } }

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

.masthead {
  position: absolute; left: 0; right: 0; top: 0; z-index: 5;
  display: flex; justify-content: space-between; align-items: center;
  padding: 28px 44px; gap: 24px; flex-wrap: wrap;
  animation: fadeUp 2.2s cubic-bezier(.16,.84,.24,1) .1s both;
}
.masthead.solid { position: static; border-bottom: 1px solid var(--rule); animation: none; }
.wordmark { font: 400 22px/1 var(--display); letter-spacing: .03em; }
.masthead nav {
  display: flex; gap: 34px; align-items: center; flex-wrap: wrap;
  font: 500 12px/1 var(--body); letter-spacing: .08em; text-transform: uppercase;
}
.pill { padding: 10px 18px; border: 1px solid rgba(243,242,239,.35); border-radius: 999px; }
.pill:hover { border-color: var(--accent); }

/* ---- hero ------------------------------------------------------------ */

.hero {
  position: relative; width: 100%; min-height: 660px; height: 100vh;
  overflow: hidden; background: var(--ground);
}
.hero-photo { position: absolute; inset: 0; animation: slowIn 2.8s cubic-bezier(.16,.84,.24,1) both; }
.hero-photo img {
  width: 100%; height: 100%; object-fit: cover; object-position: center 62%;
  filter: brightness(.6) contrast(1.06) saturate(.88);
}
.hero-vignette, .hero-top, .hero-foot { position: absolute; pointer-events: none; }
.hero-vignette {
  inset: 0;
  background: radial-gradient(105% 82% at 50% 52%,
    rgba(8,8,10,0) 26%, rgba(8,8,10,.34) 58%, rgba(8,8,10,.78) 84%, rgba(8,8,10,.97) 100%);
}
.hero-top { left: 0; right: 0; top: 0; height: 360px;
  background: linear-gradient(180deg, rgba(8,8,10,.9), rgba(8,8,10,.6) 46%, rgba(8,8,10,.28) 74%, rgba(8,8,10,0)); }
.hero-foot { left: 0; right: 0; bottom: 0; height: 140px;
  background: linear-gradient(0deg, #08080a, rgba(8,8,10,0)); }

.hero-words {
  position: absolute; left: 0; right: 0; top: 17%; z-index: 5;
  text-align: center; pointer-events: none; padding: 0 24px;
  animation: fadeUp 2.6s cubic-bezier(.16,.84,.24,1) .5s both;
}
/* The scrim over the top of the picture stops before the standfirst, which then sits on lit wood
   and goes grey. This darkens only the oval the words occupy, rather than the whole top. */
.hero-words::before {
  content: ""; position: absolute; left: 50%; top: -40px;
  width: 860px; height: 400px; margin-left: -430px; z-index: -1;
  background: radial-gradient(52% 50% at 50% 56%,
    rgba(8,8,10,.62), rgba(8,8,10,.34) 54%, rgba(8,8,10,0) 78%);
}
.hero-words h1 { margin: 18px 0 0; }
.hero-words p { margin: 18px auto 0; max-width: 460px; font-size: 15px; line-height: 1.65; color: rgba(243,242,239,.86); }

/* Centred by the box, not by a transform. fadeUp ends on transform:none and fills forwards, so
   a translateX(-50%) here is wiped the moment the animation lands and the cue sits half its own
   width to the right for good. The text-indent gives back half the trailing
   letter-space, which is what centring a box that carries a full one on the right leaves over. */
.scroll-cue {
  position: absolute; left: 0; right: 0; bottom: 26px; z-index: 5; text-align: center;
  font: 500 10.5px/1 var(--mono); letter-spacing: .2em; text-indent: .1em;
  text-transform: uppercase; color: rgba(243,242,239,.45);
  animation: fadeUp 2.6s cubic-bezier(.16,.84,.24,1) 3.2s both;
}

/* ---- the pools ------------------------------------------------------- */

.part {
  position: absolute; left: var(--x); top: var(--y);
  width: 0; height: 0; z-index: 6; color: var(--pool-ink);
  animation: bubIn 2.6s cubic-bezier(.16,.84,.24,1) var(--in, 1.6s) both;
}
.part:hover { color: var(--pool-ink); }
.part .pool {
  position: absolute; left: -101px; top: -50px; width: 202px; height: 100px;
  border-radius: 50%; background: var(--pool); filter: blur(14px); opacity: .86;
  transition: transform 1.6s cubic-bezier(.25,.8,.25,1), opacity 1.6s cubic-bezier(.25,.8,.25,1);
}
.part .plate { position: absolute; left: -124px; top: -13px; width: 248px; text-align: center; }
.part .name { display: block; font: 400 21px/1.2 var(--display); }
.part .say {
  display: block; margin: 10px 8px 0; font: 400 11.5px/1.6 var(--body); color: var(--pool-ink-2);
  opacity: 0; transition: opacity 1.4s cubic-bezier(.4,0,.2,1) .35s;
}
/* The pool has to finish wider and deeper than the words it lights, or the last line of the
   description lands on the blurred edge and reads grey on wood. */
/* Split by pointer. On a touch screen the first tap resolves as a hover and is swallowed, so a
   name that grows on hover takes two taps to follow, and there is nothing to see for the tap
   that was spent. Keyboard focus keeps the reveal on every device. */
@media (hover: hover) {
  .part:hover .pool { transform: translateY(48px) scale(2.05, 2.6); opacity: 1; }
  .part:hover .say { opacity: 1; }
}
.part:focus-visible .pool { transform: translateY(48px) scale(2.05, 2.6); opacity: 1; }
.part:focus-visible .say { opacity: 1; }

.close .rel {
  margin: 26px auto 0; max-width: 520px;
  font: 400 13px/1.7 var(--body); color: var(--ink-2);
}
.close .rel a {
  font-family: var(--mono); font-size: 12px; letter-spacing: .04em;
  color: var(--accent); border-bottom: 1px solid rgba(205,184,148,.35);
}
.close .rel a:hover { border-bottom-color: var(--accent); }

/* ---- arriving on scroll ---------------------------------------------- */

/* Driven by the scroll position itself, so the site still ships no JavaScript. Browsers without
   a view timeline never hide the content in the first place, and neither does reduced motion,
   so the failure in both cases is that everything is simply already there. */
@keyframes rise {
  from { opacity: 0; transform: translateY(26px); }
  to { opacity: 1; transform: none; }
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .rise {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 8% cover 30%;
    }
  }
}

/* ---- sections -------------------------------------------------------- */

.statement { padding: 150px 40px 130px; text-align: center; }
.statement p {
  margin: 26px auto 0; max-width: 820px;
  font: 400 clamp(26px, 3vw, 38px)/1.35 var(--display); text-wrap: pretty;
}

.section { padding: 0 40px 96px; }
.section-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 24px; flex-wrap: wrap;
  border-bottom: 1px solid var(--rule); padding-bottom: 18px;
}
.section-head .eyebrow { letter-spacing: .16em; }

.pair { display: grid; grid-template-columns: repeat(2, 1fr); gap: 60px; margin-top: 54px; }
/* Three libraries read as three columns. Below the width where a column of prose stops being a
   column of prose, they stack, which the narrow rule at the foot of this file already does. */
.pair.trio { grid-template-columns: repeat(3, 1fr); gap: 44px; }
.pair.trio p { font-size: 13.5px; }
/* The three descriptions are not the same length, so the link that follows each one is held to the
   foot of its column rather than to the end of its paragraph. Three of them on one line reads as a
   row of doors. Three of them at three heights reads as an accident. */
.pair.trio > div .more { margin-top: auto; }

/* Conductor is not a library and is not drawn as one. It sits under the three, ruled off, at the
   width of one of them, which is the whole of what is being said about it here. */
.aside {
  display: flex; flex-direction: column; gap: 14px; align-items: flex-start;
  max-width: 420px; margin-top: 56px; padding-top: 22px; border-top: 1px solid var(--rule);
}
.aside p { margin: 0; font-size: 13.5px; line-height: 1.75; color: var(--ink-2); }
.pair > div { display: flex; flex-direction: column; gap: 16px; align-items: flex-start; }
.pair p { margin: 0; font-size: 14px; line-height: 1.75; color: var(--ink-2); }
.more { font: 500 11.5px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--accent); }

.close { padding: 116px 40px 130px; text-align: center; }
.close h2 { font-size: clamp(34px, 4vw, 52px); line-height: 1.1; }
.close > p { margin: 18px auto 0; max-width: 460px; font-size: 15px; line-height: 1.7; color: var(--ink-2); }
.buttons { display: flex; gap: 16px; justify-content: center; margin-top: 36px; flex-wrap: wrap; }
.btn { padding: 14px 28px; border-radius: 999px; font: 600 13px/1 var(--body); letter-spacing: .04em; }
.btn.filled { background: var(--ink); color: var(--ground); }
.btn.filled:hover { background: var(--accent); color: var(--ground); }
.btn.hollow { border: 1px solid rgba(243,242,239,.3); }
.btn.hollow:hover { border-color: var(--accent); }

.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 28px;
  max-width: 900px; margin: 72px auto 0; text-align: left;
}
.facts div { border-top: 1px solid var(--rule); padding-top: 16px; }
.facts dt { font: 500 11px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--accent); }
.facts dd { margin: 12px 0 0; font-size: 13.5px; line-height: 1.7; color: var(--ink-2); }
.facts code { font-family: var(--mono); font-size: .92em; color: var(--ink); }

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

footer.site { border-top: 1px solid var(--rule); }
footer.site .shell {
  padding: 44px 40px; display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 20px;
}
footer.site .wordmark { font-size: 19px; }
footer.site nav {
  display: flex; gap: 28px; flex-wrap: wrap;
  font: 500 11px/1 var(--body); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
footer.site .small { font: 400 11px/1.6 var(--mono); color: var(--ink-3); }

/* ---- narrow ---------------------------------------------------------- */

@media (max-width: 900px) {
  .shell, .section, .statement, .close { padding-left: 24px; padding-right: 24px; }
  .masthead { padding: 20px 24px; }
  .pair, .pair.trio { grid-template-columns: 1fr; gap: 44px; }
  .statement { padding-top: 110px; padding-bottom: 96px; }
  .close { padding-top: 110px; padding-bottom: 110px; }
}

/* Three columns of prose need the width for three columns of prose. Below this each one is a
   measure nobody would set by choice, so they stack while the page is still a wide one. */
@media (max-width: 1040px) {
  .pair.trio { grid-template-columns: 1fr; gap: 44px; }
}

/* The photograph is a wide one, and a window held upright is not. Covering a portrait window
   with it crops away most of its width, and on a phone that leaves a handful of players where
   the whole point of the picture is that there are eighty of them.

   The pool of light does not survive the move either, and for a plainer reason than the crop. It
   is a hover, and a phone has none: the sentence inside it cannot be reached, because the tap
   that would open it leaves for the library page first. Drawn open it costs the picture, since
   two blocks of text at this width need enough light to put the stage out behind them. Drawn on
   a phone at all it is a large blurred layer inside a clipped one, which some mobile browsers
   composite as a hard rectangle with the blur cut off at its edges.

   So a portrait window stops trying. The masthead and the words go on the ground, the photograph
   is a band at its own proportions, and each library is a plain card underneath it carrying the
   name and the sentence with nothing hidden. Ordinary furniture, which is what a screen with one
   pointer and no hover is owed. The wide layout above keeps the pools and is untouched. */
@media (max-width: 720px), (orientation: portrait) {
  .hero { display: flex; flex-direction: column; height: auto; min-height: 0; }

  /* Ranged left, not centred. Centred display type over a photograph is the composition the wide
     layout is built on and it earns it there. In a 342px column with no picture behind it, it is
     just the centred hero every template ships, and the ragged right of a proper measure is both
     easier to read and more like the thing itself. */
  .masthead { order: 1; position: static; padding: 22px 24px; }
  .hero-words { order: 2; position: static; text-align: left; padding: 2vw 24px 7vw; animation-delay: .3s; }
  .hero-words::before { display: none; }
  .hero-words p { margin-left: 0; margin-right: 0; }

  /* Nothing is set over the picture here, so it does not need holding down to two thirds
     brightness, and the scrims that were doing the holding go. It meets the sheet below it on a
     hard edge rather than fading into it, because the two are different materials and a fade
     would pretend otherwise. */
  .hero-photo { order: 3; position: relative; aspect-ratio: 16 / 9; }
  .hero-photo img { filter: brightness(.86) contrast(1.04) saturate(.94); }
  .hero-vignette, .hero-top, .hero-foot, .scroll-cue { display: none; }

  /* One sheet of paper laid across the page, ruled between each pair, carrying all three
     libraries.

     Inside a pool the wide layout inverts to black on white, because a photograph is bright in
     some places and black in others and one colour of type cannot survive both. A phone has no
     hover to open a pool with and some mobile browsers will not composite the blur, so the pool
     becomes a slab: the same inversion with a hard edge instead of a soft one. Full bleed and
     square, so that it reads as paper set into the page rather than as two rounded cards, which
     is the one shape every other site on a phone is already wearing.

     The padding centres the measure inside the full width slab, so a tablet held upright gets a
     sheet edge to edge and a column of text that is still readable across. */
  .part {
    order: 4; position: static; width: auto; height: auto; margin: 0;
    padding: 26px max(24px, calc((100% - 548px) / 2)) 30px;
    background: var(--pool); color: var(--pool-ink); animation-delay: .5s;
  }
  .part.one, .part.two { border-bottom: 1px solid rgba(10, 10, 11, .16); }
  .part.two { order: 5; animation-delay: .62s; }
  .part.three { order: 6; animation-delay: .74s; }
  .part:hover, .part:focus-visible { color: var(--pool-ink); }
  .part:active { background: #efece4; }
  .part .pool { display: none; }
  .part .plate { position: static; width: auto; text-align: left; }
  .part .name { font-size: 30px; letter-spacing: -.005em; }
  .part .say {
    opacity: 1; margin: 10px 0 0; color: var(--pool-ink-2);
    font-size: 14.5px; line-height: 1.62; transition: none;
  }

  /* And one axis for the rest of the page with it. Centred type is a wide layout's device: it
     needs width either side of it to read as centred at all. In a 342px column it only means
     every line starts somewhere different, and a stack of blocks each centred on its own is the
     shape of every page that was never laid out. Everything here hangs off the same left margin,
     which is a decision a reader can see. */
  .statement, .close { text-align: left; }
  .statement { padding-top: 92px; padding-bottom: 84px; }
  .close { padding-top: 92px; padding-bottom: 96px; }
  .buttons { justify-content: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* The delay has to go with the duration. The hero staggers its entrance up to 3.2s in, and
     these animations fill backwards, so zeroing only the duration leaves the words and both
     names invisible for three seconds for the people who asked for less movement. */
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
  }
}
