/* JUNO-Xtra — white page, with the app icon's dark face bookending it and the
   logo's blue as the one accent.

   SHARES NO ASSETS with jx-3p.com or thissevengoestoeleven.com. Those two
   share none with each other either, deliberately, and copying between them is
   how three sites end up with one bug. Structure is borrowed; nothing else is.

   The type ladder and the colour names come from the APP (roland-junox-editor,
   docs/DESIGN.md), which is the reference for anything branded. */
:root {
  --bg: #ffffff;
  --raised: #f7f7f8;
  --line: #e3e3e7;
  --text: #1b1b1f;
  --muted: #5f5f68;
  --dim: #76767f;

  /* The app icon's face. The one real brand surface: build/icon.png and
     src/img/junox-icon.svg both sit the "Xt" on exactly this. */
  --panel: #2a2a2d;

  /* The logo's rule, fixed at this value inside junox-logo.svg. Used here for
     rules, the download bracket and its legend — graphics, not body type. */
  --blue: #3980c8;

  /* LINKS NEED A DARKER BLUE, and this is not a preference. --blue measures
     4.12:1 on white: fine for a 4px rule or a 21px legend, under the 4.5:1 a
     line of body text needs. This one measures 6.07:1. The 7/11 site made the
     same move for the same reason ("the felt red, dark enough to read on
     white"). Two tokens, one hue, each for the job it passes. */
  --blue-ink: #2b659e;

  /* The app's Roland green and its measured lighter variant. The brand green
     is used only as a large filled block with cream type on it (the Mac
     button); anything small or thin uses the lit one. DESIGN.md: the brand
     green measures 1.85:1 on the dark panel, the lit variant 4.2:1. */
  --green: #1f6e5b;
  --green-lit: #4fae94;
  --cream: #f7f1e6;
  /* Same treatment for the blue, so the two labels are a matched pair on the
     dark button faces: 5.67:1 and 5.33:1 on --panel. */
  --blue-lit: #6ea8e0;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--bg); color: var(--text);
  /* The app's own stack (DESIGN.md, "Font: Helvetica, 'Helvetica Neue',
     Arial, sans-serif"), which is also jx-3p.com's. The 7/11 site uses the
     system stack instead; Helvetica here keeps the site and the app in one
     voice, which matters more than matching the other site. */
  font: 17px/1.65 Helvetica, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* ONE COLUMN, and the header strip sits on it too, so the tagline lines up
   with the first paragraph below it. */
main { max-width: 46rem; margin: 0 auto; padding: 0 1.5rem 5rem; }

/* ── Header: the JUNO-X front panel ──────────────────────────────
   MEASURED VALUES, from src/panel-layout.js in the app repo. That file was
   measured off docs/Juno-X panel 1.png at 2276 px and is held true by a
   render-and-compare loop (153/153). Kept here as panel units multiplied by a
   scale, so a correction is one number rather than a sweep of pixel values.

     header bar      y 20-49, so 29 units tall
     section title   size 27, baseline 45 (cap rows 25-45), fill #f4f4f6
     bar inset       3 units in from the section divider at each end
     bottom strip    y 296-301, so 5 units, BREAKING 6 wide at every divider
     divider         1.5 units wide
     button (strip)  bezel 57 x 38 rx 5, face 50 x 29 rx 3
     family          Helvetica - already this site's body face

   TWO SCALES, ON PURPOSE. The instrument is 2259.5 units across; this header
   is about 1216 px. Scale straight and the titles land at 14 px and the
   buttons at 30 x 20. So bars and type take --pu and buttons take --bu, each
   keeping the instrument's internal proportions at a size the web can use. */
.site-head {
  --pu: 1px;            /* panel unit: bars, type, dividers */
  --bu: .75px;             /* button unit: bezel, face, ridge */
  --chassis: #696970;    /* measured (105,105,112) */
  --header-red: #b35d62; /* measured (179,94,98) */
  --strip-red: #a64649;  /* measured (166,70,73) */
  --bar: 29;             /* header bar height in panel units (measured) */
  --foot: 8;             /* strip height in panel units - see .bay-foot */
  /* THE DIVIDER CLEARS EACH BAR BY THIS PROPORTION OF THE BAR'S OWN HEIGHT.
     The app carries the same number as bands.dividerClearOfBar in
     src/panel-layout.js; change it in both. A ratio and not a unit count,
     because this header draws the panel at a different size - a unit here is
     a CSS pixel and the face is shorter than the instrument's, so a fixed
     count that is a hairline there is a visible gap here. */
  --divider-clear: .107;
  --divider: #c5c6c9;    /* measured (197,198,201) */
  --print: #bebfc1;      /* measured (190,191,193) */
  /* FULL BLEED. A front panel runs the width of the instrument; inset inside
     a page margin it reads as a picture of one. The wordmark and the tagline
     keep their inset from the panel edge instead. */
  max-width: none; margin: 0 0 2.6rem; padding: 0;
}

/* The bays are columns; their three rows line up across the whole panel
   through subgrid, which is what keeps every header bar on one line however
   tall a bay's contents are. The column gap IS the instrument's 6-unit break
   in the bottom strip - one measurement doing both jobs. */
/* THE PANEL BLEEDS; THE DECK SITS ON THE COLUMN. The chassis runs the width of
   the browser - a front panel does - but the wordmark, the buttons and the
   tagline line up with the page text below, so the header reads as the top of
   this page rather than as a band laid across it.

   The coloured bars have to reach the edge too, and they are grid items inside
   the deck. They get there with a box-shadow the width of the viewport, clipped
   by the panel's own overflow: the first bay's bars run left, the last bay's
   run right, and the chassis between them is the panel's own background. A
   second element either side would have been two more things to keep in step
   with the bars' colours and heights. */
.site-head .panel { background: var(--chassis); overflow: hidden; }
.site-head .deck {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  /* The strip row is given an explicit height rather than left to auto: the
     divider above has to stop exactly at its top, and a rule cannot measure
     a row. */
  grid-template-rows: auto 1fr calc(var(--foot) * var(--pu)) auto;
  column-gap: calc(6 * var(--pu));
  max-width: 46rem; margin: 0 auto;
}
/* 24 panel units is the wordmark's inset inside its bay and 1.5rem is the body
   column's padding - the same 24px, which is what puts the word over the first
   sentence. If either moves, move the other.

   ONLY THE BARS BLEED. The chassis between them is the panel's own background
   and already runs the full width, so the body and tagline rows need nothing.

   AN EXTENSION, NOT A SHADOW. This was a box-shadow offset by 100vw, which is
   wrong and looked it: a shadow with no spread paints a COPY of the box the
   same size, shifted - so a 300px bar put a 300px block of colour a screen
   away and left the gutter beside it bare. These are elements: same height as
   the bar by top/bottom, a viewport wide, taking the bar's own background by
   inherit so no colour is written down twice. The panel's overflow clips
   them, so none of this can scroll the page sideways. */
.bay-logo .bay-head, .bay-logo .bay-foot,
.headnav > .bay:last-child .bay-head, .headnav > .bay:last-child .bay-foot { position: relative; }
.bay-logo .bay-head::after, .bay-logo .bay-foot::after,
.headnav > .bay:last-child .bay-head::after, .headnav > .bay:last-child .bay-foot::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 100vw; background: inherit;
}
.bay-logo .bay-head::after, .bay-logo .bay-foot::after { right: 100%; }
.headnav > .bay:last-child .bay-head::after, .headnav > .bay:last-child .bay-foot::after { left: 100%; }
/* THE WRAPPER IS NOT THERE ON A WIDE SCREEN. display:contents takes its box
   away, so the three bays stay direct grid items of the deck and the panel is
   exactly what it was; the narrow query below turns it back into a real box
   for the burger to hide. */
.headnav { display: contents; }
.bay { display: grid; grid-row: 1 / 4; grid-template-rows: subgrid; position: relative; }

/* THE SECTION DIVIDER, measured. panel-svg.js draws it as

     rect x = sectionEdge - 1.5, width 3, y = header.y1 + 8, down to
     dividerBottom (293.5)

   so the rule is 3 units wide, which is what the width below is.

   THE GAP AND THE RULE ARE THE SAME MEASUREMENT. Header bars inset 3 units
   from each section edge, so the gap between two bars is 6, centred on an
   edge; the strip breaks over that same edge by gapHalf 3 either side. The
   column gap is that 6, and the rule is the 3 in the middle of it.

   THE RULE STOPS JUST SHORT OF EACH BAR, by --divider-clear of the header
   bar's height at both ends - the same proportion the app uses, and measured
   off two close photographs of the instrument (see :root above, and
   bands.dividerClearOfBar in the app's panel-layout.js).

   Both of the obvious readings are wrong and both were tried. Taking the
   app's old flat 8 units off the top gives three times the real gap. Running
   the rule corner to corner gives none at all, and doubles a division the
   bars already make with their own gaps. */
.bay:not(.bay-logo)::before {
  content: ""; position: absolute;
  left: calc(-4.5 * var(--pu));
  top: calc((var(--bar) + var(--bar) * var(--divider-clear)) * var(--pu));
  bottom: calc((var(--foot) + var(--bar) * var(--divider-clear)) * var(--pu));
  width: calc(3 * var(--pu)); background: var(--divider);
}

/* THE HEADER BAR. 29 units tall, as measured.

   THE TITLE IS THE ONE DIMENSION THAT IS NOT. The instrument sets it at 27 in
   that 29-unit bar - a cap filling two thirds of the plate, which works on a
   panel where the title is the only word in its section and the controls
   below it carry the weight. Here the section titles sit beside a wordmark
   and over two buttons, and at 27 they shouted over both. 20 keeps them
   labels. Everything else in this header stays measured.

   White, not the measured #f4f4f6: that reads 4.10:1 on this red and plain
   white reads 4.51, which clears the bar this app holds itself to. */
.bay-head {
  height: calc(var(--bar) * var(--pu));
  background: var(--header-red);
  /* The cap is centred in the bar, which is what the instrument does to
     within a unit (5 above, 4 below). Centring the LINE BOX would sit it high
     by half the descender space, so the text is pushed down by .18em - the
     difference between Helvetica's ascent-to-cap gap and its descent. Set in
     em, so it survives any change of scale. */
  display: flex; align-items: center; justify-content: center;
  padding: .18em calc(16 * var(--pu)) 0;
  color: #fff; font-size: calc(16 * var(--pu)); font-weight: 400;
  letter-spacing: 0; text-transform: none; line-height: 1;
  margin: 0; white-space: nowrap;
}
.bay-logo .bay-head { background: var(--blue); }

/* THE BOTTOM STRIP: 5 units of a deeper red than the bar above it. Two reds,
   both measured; it is not one colour used twice. */
/* THE BOTTOM STRIP. The instrument measures 5 units of a deeper red than the
   bar above it - two reds, both measured; it is not one colour used twice.

   DRAWN AT 8, NOT 5. At the measured weight the strips read as the panel
   simply ending; a web header wants them to read as rules, and the blue one
   has a second job since the wordmark gave up its own underline. The colours
   stay measured, the weight does not.

   ALL STRIPS ARE THE SAME HEIGHT, which is not a detail. The dividers have to
   stop where they meet a strip, and with a 10-unit blue beside a 7-unit red
   there is no single height at which they meet both. It is doing a second job - the
   wordmark used to carry its own blue rule and now this is it, so it has to
   read as an underline and not just as the panel closing. */
.bay-foot { height: calc(var(--foot) * var(--pu)); background: var(--strip-red); align-self: end; }
.bay-logo .bay-foot { background: #2d6cab; }

/* Controls centre under their section title, the way the panel sets them -
   which only shows on NOTES and CONTACT, whose single button is narrower
   than its title. DOWNLOAD's pair is already wider than the word above it.
   The wordmark is the exception: it sits at the left edge of its bay. */
/* THE BUTTONS WRAP RATHER THAN ESCAPE. Three bays across a 360px phone give
   DOWNLOAD about 120px, and its two buttons plus their hit padding need more
   than that - they used to hang over the divider into NOTES. Wrapping fixes
   it at every width without a breakpoint and without shrinking the buttons
   below a thumb: on a narrow phone the pair stacks, all three bays grow by a
   row together because they share the subgrid, and nothing moves on a wide
   screen. */
.bay-body {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: calc(22 * var(--bu));
  padding: calc(16 * var(--pu)) calc(18 * var(--pu));
}
/* THE WORDMARK SITS DOWN ON ITS STRIP, not centred in the bay - the way the
   instrument sets its own name low on the cheek with the strapline under it,
   rather than floating it in the middle of the face. */
.bay-logo .bay-body {
  align-items: flex-end; justify-content: flex-start;
  padding-left: calc(24 * var(--pu)); padding-bottom: calc(3 * var(--pu));
}

/* THE WORD IS SIZED FROM ITS BAY, NOT THE VIEWPORT. It used to take 36vw,
   which was right while the panel ran the full width of the browser. The deck
   is 46rem now and the three function bays take what they need from it, so
   36vw overflowed the logo bay and the word ran under the buttons. Filling
   the bay is the honest measure: the word gets whatever is left once
   DOWNLOAD, NOTES and CONTACT have had their width.

   The ceiling is in PIXELS on purpose - in rem it depends on the reader's
   root font size, and at a large one the word grows past its bay. */
/* THE CAP IS ON THE LINK, NOT ON THE SVG. It was max-width on the <svg>
   itself, which Safari does not honour reliably on a replaced element sized
   width:100% with height:auto - on an iPhone the word took the full width of
   its bay and ran off the screen (Daniel, 2 Nov 2026, iPhone 16 Pro, where it
   measured ~380px against a 300px cap). Chromium honours it, which is why
   this never showed up in testing. The <a> is an ordinary block and caps
   predictably; the svg then simply fills it. */
/* flex-basis, NOT max-width. The cap was max-width on the <svg> first, which
   Safari ignores on a replaced element sized width:100%; moving it to the <a>
   was not enough either - on an iPhone the word still took more than 300 and
   pushed the burger onto its own line. A basis of 300 that may shrink and may
   not grow says the same thing in the one place flex is certain to honour. */
.wordmark { display: block; flex: 0 1 300px; min-width: 0; color: #fff; text-decoration: none; }
.wordmark svg { display: block; height: auto; width: 100%; }
.wordmark:hover svg { color: var(--cream); }

/* A PRINTED LABEL OVER ITS BUTTON, as the panel sets them. 11 units, which is
   the panel's lowerSub size - its knob-and-button label is 12.5, but the
   section titles here are set at 16 rather than the instrument's 27, and at
   12.5 the label and the title above it were nearly the same size. Both
   numbers are measured; this is the pair that keeps the hierarchy.

   Not the measured print grey (#bebfc1), which reads 2.96:1 on this chassis:
   on a photographed panel the ink has an edge and a highlight, on a screen it
   is flat. White reads 5.45:1 and is what a label this small needs. */
.pcell { display: flex; flex-direction: column; align-items: center; gap: calc(5 * var(--bu)); }
.plabel {
  color: #fff; font-size: calc(11 * var(--pu)); line-height: 1;
  white-space: nowrap;
}

/* THE BUTTON IS THE APP'S OWN DRAWING. _includes/panel-button.svg is output
   from src/panel-svg.js, not a copy of it by hand - bezel, rim, face, inset
   and the light ridge along the bottom lip, exactly as the app renders a
   part button. The stylesheet only sizes it and swaps two fills.

   The padding is hit area, not bezel, and the vertical half is in PIXELS:
   scaled with --bu it would shrink along with the button it is meant to
   protect, and a 43 x 29 button with proportional padding lands under the
   44 px a thumb needs. Fixed, the target stays usable however small the
   drawn button goes. */
.pbtn {
  display: block; padding: 9px calc(7 * var(--bu)); border: 0; background: none;
  cursor: pointer; line-height: 0; -webkit-tap-highlight-color: transparent;
}
.pbtn-svg {
  display: block;
  width: calc(59 * var(--bu)); height: calc(40 * var(--bu));
}

/* LIT AT REST, in the measured blue. On the instrument a button that does
   something sits lit; dark means off, and none of these are off. The rim is
   that colour at 20%, which is the app's own shade(use, 0.2). */
.pb-rim { fill: #1a232b; }
.pb-face { fill: url(#jx-face-blue); }

/* BRIGHTER UNDER THE POINTER, under the press, and on the page you are on:
   the panel's cyan, which is the selected one of a lit row. All three mean
   the same thing here - this is the one in play. */
.pbtn:hover .pb-rim,
.pbtn:active .pb-rim,
.pbtn.is-here .pb-rim { fill: #263232; }
.pbtn:hover .pb-face,
.pbtn:active .pb-face,
.pbtn.is-here .pb-face { fill: url(#jx-face-cyan); }
.pbtn:hover .pbtn-svg,
.pbtn:active .pbtn-svg,
.pbtn.is-here .pbtn-svg {
  filter: drop-shadow(0 0 calc(5 * var(--bu)) rgba(190, 248, 252, .55));
}

.pbtn:focus-visible { outline: 2px solid #fff; outline-offset: -2px; border-radius: 4px; }

/* THE STRAPLINE, off the panel and on the page. Sentence case with the hook
   bold - the <strong> is in _config.yml, which is why it survives wherever
   the tagline is printed.

   ALIGNED TO THE WORDMARK, not to the content column below. It is the
   panel's caption, so it hangs off the word it describes: the same inset the
   wordmark takes inside its bay, measured from the same panel edge. Set tight
   under the bottom strip for the same reason - a caption that drifts down the
   page starts reading as the first line of the body. */
/* ONE CONTINUOUS FIELD. The tagline sits on the SAME chassis as the bays, not
   on a band of its own - so the bottom strips read as rules drawn across the
   face rather than as the edge the panel stops at. The instrument has a
   darker lower face (#52525a) and using it here split the header into two
   plates, which is not what the panel does.

   Type is #f4f4f6, the measured print white, at 4.96:1 on this chassis. The
   measured print GREY (#bebfc1) reads 2.96 and cannot be used on a screen;
   the hook goes pure white at 5.45. */
.site-head .tagline {
  grid-column: 1 / -1; grid-row: 4;
  background: var(--chassis);
  margin: 0; padding: calc(10 * var(--pu)) calc(24 * var(--pu)) calc(14 * var(--pu));
  color: #f4f4f6; font-size: 1.02rem; line-height: 1.4;
}
.site-head .tagline strong { color: #fff; }

/* THE BURGER. Three bars, in the panel's own print white, sized from the bay
   titles so it reads as part of the panel rather than a web widget dropped on
   it. Hidden until the script adds .has-burger: without JavaScript the three
   bays stay visible, stacked, which is a worse layout and not a broken one. */
.burger {
  display: none; flex-direction: column; justify-content: center; align-items: center; gap: 5px;
  margin-left: auto; padding: 12px 9px; min-width: 44px; min-height: 44px;
  border: 0; background: none;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.burger > span { display: block; width: 26px; height: 3px; border-radius: 1px; background: #fff; }
.burger:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* THE NARROW MENU IS TEXT, not the panel stacked. Daniel, 2 Nov 2026: "a
   hamburger menu with a regular menu, not the buttons" and "just text within
   the expanded menu". Four rows on the chassis, divided by the panel's own
   rule colour, each a full-width target. A row with nothing behind it yet is
   dimmed and is not a link, so it cannot be tapped to no effect. */
.menu { display: none; }
.menu > a, .menu > span {
  display: block; padding: 14px 1.5rem; color: #fff; text-decoration: none;
  font-size: 1.02rem; border-top: 1px solid rgba(197, 198, 201, .22);
}
.menu > a:active { background: rgba(255, 255, 255, .09); }
.menu > .is-soon { color: #c2c2cb; opacity: .65; }

/* NARROW: ONE TREATMENT, NOT TWO. There used to be a middle layout here - the
   three bays side by side on one shelf - which was cramped from about 420px
   down and needed its own rules for button wrapping and title sizes. Daniel,
   2 Nov 2026: "generally, the hamburger menu is the way to go." So everything
   under the desktop panel gets the same thing: the logo, the tagline under it,
   and the three bays behind a button.

   THE TAGLINE SITS UNDER THE WORDMARK AT EVERY WIDTH - "if buttons ... tagline
   below JUNO-Xtra (not below buttons)". In the markup it comes after the bays,
   because on a wide screen it is the row beneath them. Here `order` puts it
   back under the word without moving it in the document, so the reading order
   a screen reader follows is the same one the eye follows. */
@media (max-width: 52rem) {
  .site-head { --pu: .72px; --bu: .8px; }
  .site-head.has-burger .burger { display: flex; }
  /* the menu is drawn at this width only; .has-burger then decides open/shut */
  .site-head .menu { display: block; }
  .site-head .deck { display: flex; flex-direction: column; }
  /* subgrid needs a grid parent; without one the bay's three rows stack, which
     is what is wanted anyway */
  .bay { display: block; }
  .bay-logo { order: 1; }
  .site-head .tagline { order: 2; }
  /* THE PANEL BAYS ARE A WIDE-SCREEN THING ONLY. They are not what the burger
     opens - the menu below is - so here they are gone outright rather than
     hidden and waiting. */
  .headnav { display: none; }
  .menu { order: 3; }
  .site-head.has-burger:not(.is-open) .menu { display: none; }
  /* stacked, the bays are full width and there is nothing to divide */
  .bay:not(.bay-logo)::before { display: none; }
  .bay-logo .bay-body { justify-content: space-between; padding-left: 1.5rem; padding-right: 1rem; }
  .bay-head { font-size: calc(17 * var(--pu)); padding: .18em 1.5rem 0; justify-content: flex-start; }
  .bay-body { gap: calc(16 * var(--bu)); padding: calc(12 * var(--pu)) 1.5rem; justify-content: flex-start; }
  .site-head .tagline {
    padding: calc(9 * var(--pu)) 1.5rem calc(13 * var(--pu));
    font-size: .97rem;
  }
}

/* ── Page typography ──────────────────────────────────────────────────── */
h1 { font-size: 2.1rem; line-height: 1.2; letter-spacing: -.02em; margin: 0 0 1.4rem; }
/* Section heads are small, uppercase and tracked — the app's own
   "12px/700 uppercase tracking .12em region header" step, which is also what
   both other sites do with an h2. */
h2 {
  font-size: .82rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); margin: 2.6rem 0 .9rem;
}
h3 { font-size: 1.1rem; margin: 2rem 0 .6rem; }
p { margin: 0 0 1.15rem; }
a { color: var(--blue-ink); }
main ul { margin: 0 0 1.15rem 1.1rem; }
main li { margin: .3rem 0; }
.lede { font-size: 1.18rem; }
.muted { color: var(--muted); }
strong { font-weight: 700; }

/* A paragraph Daniel still has to write. Visible on purpose: a grey box is
   easier to find than a comment, and it cannot be published by accident
   without somebody seeing it. Delete the rule with the last placeholder. */
.todo {
  background: #fffbe8; border-left: 4px solid #c39a3a; border-radius: 0 4px 4px 0;
  padding: .9rem 1.1rem; margin: 0 0 1.15rem; color: #5a4a20; font-size: .95rem;
}

/* Feature lists: rules instead of bullets, indented so they sit under the
   heading they belong to. */
.features { list-style: none; margin: 0 0 1.5rem; padding-left: 1.25rem; }
.features li { padding: .55rem 0; border-bottom: 1px solid var(--line); margin: 0; }
.features li:first-child { border-top: 1px solid var(--line); }

/* What is not built yet, said once, in its own box. Both other sites keep
   this separate from the feature list rather than mixing a "soon" into it —
   a list that mixes the two is a list you cannot trust.

   NOTHING WEARS THIS TODAY. The box was deleted from the homepage on 1 Nov
   (see README, "Still to do"). The rule stays because the pattern is shared
   with the two sibling sites and the box returns at release; it costs 5
   lines and rewriting it later costs more. */
.soon {
  background: var(--raised); border: 1px solid var(--line); border-radius: 6px;
  padding: .4rem 1.2rem 1.2rem; margin: 2rem 0 0;
}
.soon h2 { margin-top: 1.2rem; }
.soon ul { margin-bottom: 0; }

/* ── Screenshots: a STRIP, not a grid ─────────────────────────────────────
   Stacked, four screenshots run the page down several screens before the
   writing resumes. Across, they read as a filmstrip you open. */
.shots {
  display: flex; gap: .5rem; margin: 2rem 0;
  overflow-x: auto; scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch; scrollbar-width: thin;
}
.shot { position: relative; margin: 0; flex: 1 1 0; min-width: 0; scroll-snap-align: start; }
/* Too narrow to show the set at any useful size, so show one and a bit — the
   part-visible neighbour is what says the strip keeps going. */
@media (max-width: 44rem) { .shot { flex: 0 0 76%; } }
.shot-open {
  display: block; width: 100%; padding: 0; border: 1px solid var(--line);
  border-radius: 6px; overflow: hidden; background: none; cursor: zoom-in;
  transition: border-color .15s ease, transform .15s ease;
}
.shot-open:hover, .shot-open:focus-visible { border-color: var(--blue); transform: translateY(-2px); }
.shot-open img { display: block; width: 100%; height: auto; }
@media (prefers-reduced-motion: reduce) {
  .shot-open { transition: none; }
  .shot-open:hover, .shot-open:focus-visible { transform: none; }
}

dialog.shot-modal {
  width: min(77vw, 1280px); padding: 0; border: none; border-radius: 8px;
  background: none; overflow: visible;
  /* The UA centres a modal dialog with `margin: auto`, which the `* {margin:0}`
     reset at the top of this file wipes out. Put back explicitly. */
  margin: auto;
  /* NO `position` here, deliberately. A modal <dialog> centres itself in the
     VIEWPORT only while it keeps the UA's `position: fixed`. Setting
     `relative` lays it out against the document instead, and on a phone,
     tapping a screenshot 600px down the page dims the screen and puts the
     picture 600px above it, off-screen. The arrows do not need `relative`:
     `fixed` is a containing block for absolute children just the same. */
}
dialog.shot-modal::backdrop { background: rgba(0, 0, 0, .72); }
/* Stop the page scrolling behind the open picture. Keyed off the [open]
   attribute the browser sets and clears itself, so no exit path can leave the
   page unscrollable. */
html:has(dialog.shot-modal[open]) { overflow: hidden; }
dialog.shot-modal img { display: block; width: 100%; height: auto; border-radius: 8px; cursor: zoom-out; }
.shot-caption { color: #e8e8ea; text-align: center; font-size: .9rem; margin: .6rem 0 0; }
.shot-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 2.6rem; height: 3.4rem; border: none; border-radius: 6px;
  background: rgba(0, 0, 0, .55); color: #fff; font-size: 1.9rem; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.shot-nav:hover { background: rgba(0, 0, 0, .8); }
.shot-nav.prev { left: .5rem; }
.shot-nav.next { right: .5rem; }
@media (max-width: 34rem) { .shot-nav { width: 2.1rem; height: 2.8rem; font-size: 1.5rem; } }
/* On a phone, fitting a 1200px-wide app window to the screen makes it about
   210px tall — barely larger than the thumbnail it opened from. So it opens
   at a size you can read and pans sideways instead. */
@media (max-width: 44rem) {
  dialog.shot-modal { width: 96vw; overflow-x: auto; overflow-y: hidden; }
  dialog.shot-modal img { width: 900px; max-width: none; cursor: grab; }
  /* Pinned to the viewport, or they scroll away the moment you pan. */
  .shot-nav { position: fixed; }
}

/* ── Downloads ──────────────────────────────────────────────
   Two buttons under a bracketed DOWNLOAD legend. The bracket is 7/11's
   treatment (there it is the Crumar's CLAVI TABS hairline); the legend and
   the hairline are the logo's blue, the only line on this site that is not
   grey.

   THE BUTTONS ARE THE JUNO-X's PART BUTTONS. Not panel artwork - the shape
   language: a dark face, a hairline outline, a small radius, and a colour
   that appears only when the button is lit. The app draws its part marks the
   same way (src/index.html, .fx-pdot - 3px radius, outlined when off, filled
   lit with dark type when on), so the two agree without either one redrawing
   the other.

   UNLIT IS THE RESTING STATE, NOT A DISABLED ONE. Every part button on the
   instrument sits dark until you press it. That also happens to be the
   honest state today: nothing is signed or packaged, so a press lights the
   button and does nothing else - which is what the paragraph above the block
   already says in words. */
.downloads { margin: 1.8rem 0 .9rem; }
.dl-legend {
  font-size: 1.05rem; font-weight: 700; letter-spacing: .1em;
  color: var(--blue-ink); margin: 0 0 .15rem;
}
.dl-bracket { display: block; width: 15.5rem; max-width: 100%; height: .7rem; }
.dl-bracket path { fill: none; stroke: var(--blue); stroke-width: 1; }

.dl-row { display: flex; gap: .7rem; margin: .35rem 0 0; flex-wrap: wrap; }
.dl-btn {
  display: inline-flex; align-items: center; gap: .45rem;
  min-width: 7.2rem; justify-content: center;
  padding: .7rem 1.3rem; border-radius: 4px;
  background: var(--panel); border: 1.5px solid #55555e;
  font: inherit; font-weight: 700; font-size: 1rem; letter-spacing: .04em;
  text-decoration: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .06s linear, border-color .06s linear, color .06s linear;
}
.dl-btn .dl-ico { width: 1em; height: 1em; flex: none; }
/* MAC green, PC blue - the app's own two colours, in their MEASURED variants,
   because unlit they are type on a dark face and not a filled block.
   5.33:1 and 5.67:1 on --panel. */
.dl-btn.is-mac { color: var(--green-lit); }
.dl-btn.is-pc { color: var(--blue-lit); }
.dl-btn:hover { border-color: #83838e; }
.dl-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }

/* LIT. Held down, the button fills with its own colour and the type goes
   dark - the instrument's part button, and the app's .fx-pdot.is-on. The
   glow is what separates a LIT button from a merely coloured one at a
   glance. It goes out when you let go: nothing latches, because nothing has
   happened. */
.dl-btn:active { color: #16202b; }
.dl-btn.is-mac:active {
  background: var(--green-lit); border-color: var(--green-lit);
  box-shadow: 0 0 10px rgba(79, 174, 148, .55);
}
.dl-btn.is-pc:active {
  background: var(--blue-lit); border-color: var(--blue-lit);
  box-shadow: 0 0 10px rgba(110, 168, 224, .55);
}

/* NOTHING TO DOWNLOAD YET. No shape change any more - unlit says it, and the
   paragraph above the block says it in words. The button still presses and
   still lights; it simply has nothing behind it. */
.dl-btn.is-soon { cursor: pointer; }

@media (prefers-reduced-motion: reduce) { .dl-btn { transition: none; } }

/* WHICH VERSION THE BUTTON WILL HAND YOU. Ships hidden, revealed only once
   the relay has answered. An absent version is a small loss; a stale one, left
   over from a previous release, is the thing worth avoiding. */
.dl-version {
  color: var(--muted); font-size: .9rem; font-variant-numeric: tabular-nums;
  margin: .8rem 0 1.1rem;
}
.dl-version[hidden] { display: none; }

/* A first-run warning, named before it happens. Quieter than the donation
   line because it only concerns some visitors. */
.install-note {
  color: var(--muted); font-size: .9rem; line-height: 1.5;
  margin: 0 0 1.1rem; max-width: 32rem;
}


/* PRESENT, NOT ASKED: a line under the buttons, no prompt and nothing to
   dismiss. Nobody donates for software they have not run. */
.donate-line { color: var(--dim); font-size: .95rem; margin: 0 0 1.6rem; }

/* ── Notes index ──────────────────────────────────────────────────────── */
.notes-head {
  position: relative; padding-left: .75rem; margin: 0 0 .45rem;
  font-size: .82rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
}
.notes-head::before {
  content: ""; position: absolute; left: 0; top: .05em; bottom: .05em;
  width: 4px; background: var(--blue);
}
.notes-subhead { font-style: italic; color: var(--muted); margin: 0 0 1.6rem; }
.notes-list { margin-top: 1.6rem; }
.note-entry { padding: 1.5rem 0; border-top: 1px solid var(--line); }
.note-entry:last-child { border-bottom: 1px solid var(--line); }
.note-entry-date { display: block; color: var(--muted); font-size: .9rem; margin-bottom: .3rem; }
/* The .notes-list prefix outranks the global link colour. */
.notes-list .note-entry-title {
  display: inline-block; font-size: 1.3rem; font-weight: 600; line-height: 1.3;
  color: var(--text); text-decoration: none; transition: color .15s ease;
}
.notes-list .note-entry-title:hover { color: var(--blue-ink); }
.note-entry-excerpt { margin: .45rem 0 0; color: var(--muted); }
.notes-list .note-entry-more {
  display: inline-block; margin-top: .7rem; font-weight: 600;
  color: var(--blue-ink); text-decoration: none;
}
.notes-list .note-entry-more:hover { text-decoration: underline; }
.notes-empty { margin-top: 1.6rem; color: var(--muted); font-style: italic; }
.post-date { color: var(--muted); font-size: .9rem; margin-top: -.8rem; }

/* Images inside a Notes post: a modest thumbnail that expands on click, using
   the homepage's own lightbox (shot.js wraps these), so the site has ONE
   enlarge mechanism rather than two that drift. Authoring stays plain
   markdown — ![alt](/assets/img/x.png) — with no separate -thumb file. */
.post-shot {
  display: block; margin: 1.75em auto; padding: 0;
  background: none; border: none; cursor: zoom-in;
}
.post-shot img {
  display: block; max-width: 100%; height: auto; border-radius: 6px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .12);
  transition: transform .18s ease;
}
@media (min-width: 700px) { .post-shot img { max-width: 380px; } }
.post-shot:hover img { transform: scale(1.04); }
.post-shot:focus-visible img { outline: 2px solid var(--blue); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .post-shot img { transition: none; }
  .post-shot:hover img { transform: none; }
}

/* ── Contact form (Web3Forms — no backend of our own) ─────────────────── */
.contact-form { display: flex; flex-direction: column; gap: .4rem; max-width: 34rem; }
.contact-form label { font-size: .9rem; color: var(--muted); margin-top: .6rem; }
/* Every text-ish input, not just one named type: on 7/11 a rule written for
   input[type=email] meant the name field added later rendered with the
   browser's default box beside a styled one. The honeypot is excluded by type
   so it stays invisible. */
.contact-form input:not([type=checkbox]):not([type=hidden]), .contact-form textarea {
  font: inherit; font-size: 1rem; padding: .55rem .7rem;
  border: 1px solid var(--line); border-radius: 4px; background: #fff; color: var(--text);
}
.contact-form textarea { resize: vertical; }
.contact-form button {
  align-self: flex-start; margin-top: 1rem;
  font: inherit; font-size: 1rem; font-weight: 700; cursor: pointer;
  padding: .6rem 1.5rem; border: none; border-radius: 4px;
  /* The app's primary action: the brand green as a large filled block with
     cream type on it, which is the one place it is legible. */
  background: var(--green); color: var(--cream);
}
.contact-form button:hover { filter: brightness(1.12); }
.contact-form .hp { position: absolute; left: -9999px; }

/* ── Footer ───────────────────────────────────────────────────────────── */
.site-foot {
  max-width: 46rem; margin: 0 auto; padding: 1.5rem;
  border-top: 1px solid var(--line); color: var(--muted); font-size: .9rem;
}
.foot-strip { height: 4px; background: var(--blue); }
.foot-inner {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: .5rem;
  max-width: 46rem; margin: 0 auto; padding: 1.4rem 1.5rem .4rem;
  color: var(--muted); font-size: .9rem; text-align: center;
}
.foot-dot { color: var(--line); }
.foot-ig { display: inline-flex; align-items: center; color: var(--muted); margin-left: .2rem; }
.foot-ig:hover { color: var(--blue-ink); }
.foot-fine {
  max-width: 46rem; margin: 0 auto; padding: 0 1.5rem 2.5rem;
  color: var(--dim); font-size: .82rem; text-align: center;
}

@media (max-width: 34rem) { body { font-size: 16px; } h1 { font-size: 1.7rem; } }
