/* The home page (HomeScreen.js). The invitation takes the whole first screen; everything after it
   takes the room it needs, and nothing snaps. */

/* 1. The invitation ------------------------------------------------------------------------------

   The words over the galaxy the background field draws behind them (PixelField.js, its core under the
   words), the plugins on it as stars. It runs up behind the nav (the negative margin), so the galaxy
   is seen from the top of the window, and draws nothing of its own behind the words. */

.orbit {
  /* The whole screen, so the galaxy has it to itself and the plugin comes up with the first scroll,
     the arrow at its foot the one way on (decided 2026-10-20, the owner). */
  --orbit-height: max(34rem, 100svh); /* convention-allow viewport-unit: the small viewport, so the arrow sits above a phone's toolbar */
  position: relative;
  display: flex;
  align-items: center;
  min-height: var(--orbit-height);
  margin-top: -4.25rem; /* the height of the nav row (css/base.css, .navInner) */
  padding: 6rem 0 5rem;
  text-align: center;
}

/* The galaxy's box (PixelField.js) is fixed to the window, as the sky behind it is, so the two hold
   still together as one space while the words scroll over them: a galaxy moved by the scroll, from
   script or by a scroll-driven animation, stepped against the words on an iPhone. Its height is the
   large viewport's, which the toolbar showing and hiding does not change. */
.orbitGalaxy {
  position: fixed;
  top: 0;
  left: 0;
  width: calc(100% - var(--lock-room, 0rem)); /* the page's width under the dialog lock (css/base.css) */
  height: 100lvh; /* convention-allow viewport-unit: large viewport, constant as the URL bar shows/hides */
  z-index: -1;
  pointer-events: none;
}

/* Once the invitation has less than half the screen the galaxy and its stars fade (HomeScreen.js,
   InvitationBehavior), so its core never shines between the plugins' panels; a star takes no
   pointer from the start of the fade and no focus once hidden at its end. */
.orbitGalaxy,
.orbitCore {
  transition:
    opacity var(--md-sys-motion-duration-extra-long) var(--md-sys-motion-easing-standard),
    visibility var(--md-sys-motion-duration-extra-long) var(--md-sys-motion-easing-standard);
}

.orbit.past .orbitGalaxy,
.orbit.past .orbitCore {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* The words. The headline takes the hook's display-large (Hook.css), the largest role, which only a
   plugin's name on its own page shares. */

.orbitCenter {
  position: relative;
}

/* The sale (HomeScreen.js, SalePill): a glass pill over the kicker, the badge leading its words. It
   is as tall as a touch target, so it needs no hit area of its own. The badge's ink is
   the accent's own, 4.6:1 on Midnight in light and 7.7:1 on the primary in dark. */

/* The pill shows only once the Worker answers, so it lies in a room kept for it over the kicker
   from the first paint, sale on or off, rather than pushing the hook down as it comes. */
.orbitCenter:has(> .salePill) {
  padding-top: 4.5rem; /* the pill's 3rem and the 1.5rem under it */
}

.salePill {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: fit-content;
  max-width: 100%;
  min-height: 3rem;
  margin: 0 auto;
  padding: 0.25rem 1.25rem 0.25rem 0.5rem;
  border-radius: var(--md-sys-shape-corner-xl); /* round at its height, where the full corner could only snap to the pressed one */
  color: var(--ink);
  font: var(--md-sys-typescale-label-large);
  text-decoration: none;
}

/* It answers the pointer as the hero's chevron does: the glass state layers and the same lift. */
@media (hover: hover) {
  .salePill:hover {
    background: var(--md-state-glass-hover);
    transform: translateY(var(--md-comp-button-hover-lift)) scale(1.03);
  }
}

.salePill:is(:active, .held) {
  border-radius: var(--md-comp-pressed-morph);
  background: var(--md-state-glass-pressed);
}

.salePill .saleBadge {
  padding: 0.25rem 0.75rem;
  border-radius: var(--md-sys-shape-corner-lg); /* round at its height, where the full corner could only snap to the held one */
  background: var(--accent);
  color: var(--accent-ink);
  font: var(--md-sys-typescale-label-large);
  transition: border-radius var(--md-sys-motion-duration-medium) var(--md-sys-motion-easing-emphasized);
}

/* Held, the badge squares off with the pill, on the pill's clocks (css/expressive.css), so their
   corners move together. */
.salePill:is(:active, .held) .saleBadge {
  border-radius: var(--md-sys-shape-corner-xs);
  transition: border-radius var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard);
}

/* On a phone the line takes the smaller type, so the badge and the headline keep one line on a
   common phone and wrap under each other on a narrow one. */
@media (max-width: 40rem) {
  .orbitCenter:has(> .salePill) {
    padding-top: 4rem;
  }

  .salePill {
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.25rem 0.5rem;
    padding-right: 1rem;
    font: var(--md-sys-typescale-label-medium);
  }

  .salePill .saleBadge {
    font: var(--md-sys-typescale-label-medium);
  }
}

.orbit .heroKicker {
  letter-spacing: 0.32em;
}

/* The stars (HomeScreen.js, StarMap): the plugins round the point the galaxy's core lies behind, under
   the words, in the disc's own plane: each lies out on the disc at its angle and is drawn through the
   tilt, perspective and roll the field draws the disc with, leaning with it under the pointer. */

/* The slot sits well under the hook, so a star the disc's roll lifts on its left keeps its label off
   the words. */
.orbitMap {
  position: relative;
  height: 3.5rem;
  margin-top: 4.5rem;
}

/* The disc's shape, which the field writes here once it draws (PixelField.js, publishDisc); without
   WebGL there is no galaxy and the stars keep a flat ellipse of their own. Fixed like the galaxy, it
   stays where the slot lays it out at the top of the page (its static position, so no top), at the
   slot's middle. */
.orbitCore {
  --field-disc-radius: min(max(36vw, 27vh), 43vw); /* the radius the field draws (PixelField.js, galaxyPlacement) until it writes its own */
  --field-disc-flatten: 0.42;
  --field-disc-tilt: 0;
  --field-disc-roll: 0rad;
  --field-disc-perspective: 0;
  --field-disc-shift-x: 0rem;
  --field-disc-shift-y: 0rem;
  position: fixed;
  left: calc(50% - var(--lock-room, 0rem) / 2); /* the page's middle under the dialog lock (css/base.css) */
  margin-top: 1.75rem; /* half the slot's height */
}

.orbitStars {
  position: absolute;
  top: 0;
  left: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  /* The hook's entrance (heroRise, Hook.css), staggered after its headline. */
  animation: heroRise var(--md-sys-motion-duration-extra-long3) var(--md-sys-motion-easing-emphasized-decelerate) both;
  animation-delay: 0.2s;
}

/* A point of the disc, as the field's vertex shader draws one (PixelField.js, STAR_VERT): flattened by
   the tilt, nearer and so larger by the perspective on the near side, then rolled; down the page is
   positive here, up in the shader. */
.orbitStar {
  /* How far out on the disc a star lies, a share of its radius: out on the arms at the sides, nearer
     the core on the near side, so the star under the core keeps clear of the arrow. */
  --star-out: calc(0.65 - 0.13 * sin(var(--star-angle)));
  --star-near: calc(1 / (1 - var(--star-out) * sin(var(--star-angle)) * var(--field-disc-tilt) * var(--field-disc-perspective)));
  --star-x: calc(cos(var(--star-angle)) * var(--field-disc-radius) * var(--star-out) * var(--star-near));
  --star-y: calc(sin(var(--star-angle)) * var(--field-disc-radius) * var(--star-out) * var(--field-disc-flatten) * var(--star-near));
  position: absolute;
  top: calc(var(--star-y) * cos(var(--field-disc-roll)) - var(--star-x) * sin(var(--field-disc-roll)) + var(--field-disc-shift-y));
  left: calc(var(--star-x) * cos(var(--field-disc-roll)) + var(--star-y) * sin(var(--field-disc-roll)) + var(--field-disc-shift-x));
}

/* The link is the star's 48dp circle; its label and its card hang off it. */
.orbitStarLink {
  position: absolute;
  top: -1.5rem;
  left: -1.5rem;
  display: block;
  width: 3rem;
  height: 3rem;
  border-radius: var(--md-sys-shape-corner-full);
  color: var(--ink);
  text-decoration: none;
}

/* The mark, in its plugin's color, darkened on light so it reads over the ink: a faint orbit, a ring
   broken in four with a tick at each quarter, like a system on a star chart. A plugin still to come
   is an unexplored system: dim, its ring dotted, with no ticks and no flare. */
.orbitStarMark {
  position: absolute;
  inset: 0;
  color: light-dark(color-mix(in srgb, rgb(var(--product-accent)) 70%, var(--ink)), rgb(var(--product-accent)));
}

.orbitStar.soon .orbitStarMark {
  opacity: 0.6;
  transition: opacity var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard);
}

/* On light a clearing of the page's ground behind the mark, so the ring reads over the galaxy's ink. */
.orbitStarMark::before {
  content: "";
  position: absolute;
  inset: -0.5rem;
  border-radius: var(--md-sys-shape-corner-full);
  background: radial-gradient(closest-side, light-dark(var(--bg), transparent) 65%, transparent);
}

.orbitStarReticle {
  position: absolute;
  inset: 0;
  overflow: visible;
}

.orbitStarOrbit {
  fill: none;
  stroke: currentColor;
  stroke-opacity: 0.3;
  stroke-width: 0.75;
  transition: stroke-opacity var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard);
}

.orbitStarRing {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-dasharray: 14.4 6;
  stroke-linecap: round;
  transform: rotate(22deg);
  transform-box: fill-box;
  transform-origin: center;
}

.orbitStarTicks {
  fill: none;
  stroke: currentColor;
  stroke-opacity: 0.6;
}

.orbitStar.soon .orbitStarRing {
  stroke-dasharray: 2 4;
}

.orbitStar.soon .orbitStarTicks {
  display: none;
}

/* The star itself: a hot point in the core's ink on dark and its color on light, its glow, and the
   four-point flare a bright star makes, which a plugin still to come lacks. */
.orbitStarCore {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.5rem;
  height: 0.5rem;
  margin: -0.25rem 0 0 -0.25rem;
  border-radius: var(--md-sys-shape-corner-full);
  background: light-dark(rgb(var(--product-accent)), var(--ink));
}

.orbitStarCore::before {
  content: "";
  position: absolute;
  inset: -1.25rem;
  border-radius: var(--md-sys-shape-corner-full);
  background: radial-gradient(closest-side, rgba(var(--product-accent), 0.6), rgba(var(--product-accent), 0.16) 45%, transparent);
}

.orbitStarCore::after {
  content: "";
  position: absolute;
  inset: -1.25rem -1.5rem;
  background:
    linear-gradient(90deg, transparent, light-dark(rgb(var(--product-accent)), var(--ink)), transparent) center / 100% 0.0625rem no-repeat,
    linear-gradient(transparent, light-dark(rgb(var(--product-accent)), var(--ink)), transparent) center / 0.0625rem 80% no-repeat;
}

.orbitStar.soon .orbitStarCore::after {
  display: none;
}

/* The line from the ring to the label, up and out; on the disc's east side it turns back toward the
   core, so no label runs off the screen. */
.orbitStarLeader {
  position: absolute;
  top: -0.75rem;
  left: 2rem;
  overflow: visible;
  fill: none;
  stroke: rgba(var(--product-accent), 0.7);
  stroke-width: 1;
  transition: opacity var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard);
}

.orbitStar.east .orbitStarLeader {
  right: 2rem;
  left: auto;
  transform: scaleX(-1);
}

/* The label at the line's end: the plugin's name in the display face, and over it its number and
   whether it is out yet. It is the star's surface for the state layers, glass under the pointer. */
.orbitStarLabel {
  position: absolute;
  top: 0;
  left: 4.75rem;
  display: grid;
  padding: 0.25rem 0.75rem;
  border-radius: var(--md-sys-shape-corner-xl);
  text-align: start;
  text-shadow: 0 0 0.75rem var(--bg), 0 0 0.25rem var(--bg);
  white-space: nowrap;
  transform: translateY(-50%);
  transition:
    opacity var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard),
    background var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard),
    border-radius var(--md-sys-motion-duration-medium) var(--md-sys-motion-easing-emphasized);
}

.orbitStar.east .orbitStarLabel {
  right: 4.75rem;
  left: auto;
  justify-items: end;
  text-align: end;
}

.orbitStarName {
  font: var(--md-sys-typescale-title-large);
}

.orbitStar.soon .orbitStarName {
  font: var(--md-sys-typescale-title-medium);
  color: var(--ink-2);
}

.orbitStarStatus {
  order: -1;
  font: var(--md-sys-typescale-label-small);
  font-feature-settings: var(--figures);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: light-dark(var(--ink-2), rgb(var(--product-accent)));
}

.orbitStar.soon .orbitStarStatus {
  color: var(--ink-2);
}

/* What the star leads to, under the pointer: its picture and its promise on a card of the strong glass,
   which holds its words over the galaxy's bright core, lit along its top in the plugin's color, beside
   the label and under it. */
.orbitStarCard {
  position: absolute;
  top: 1.75rem;
  left: 4.75rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 21rem;
  padding: 0.75rem;
  overflow: hidden;
  border-radius: var(--md-sys-shape-corner-lg);
  background: var(--glass-strong);
  text-align: start;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard),
    visibility var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard);
}

.orbitStarCard::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 0.125rem;
  background: linear-gradient(90deg, transparent, rgb(var(--product-accent)), transparent);
}

.orbitStar.east .orbitStarCard {
  right: 4.75rem;
  left: auto;
}

.orbitStarCard img {
  flex: none;
  width: 7.5rem;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--md-sys-shape-corner-sm);
  object-fit: cover;
}

.orbitStarCardText {
  display: grid;
  gap: 0.5rem;
  font: var(--md-sys-typescale-body-medium);
  color: var(--ink-2);
  white-space: normal;
}

.orbitStarCall {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font: var(--md-sys-typescale-label-large);
  color: var(--accent-text);
}

/* Under the pointer the label takes the glass's hover layer, the orbit brightens and the card opens,
   and the keyboard's focus opens it too; held, the label takes the pressed layer and rounds off, as
   the link squishes (expressive.css). The star in use lies over the others. Where there is a pointer, a
   plugin still to come keeps its name and its line until the pointer or the focus comes to it, so the
   first screen names the plugins that are out; a tablet shows every name, the soon ones quieter. */
@media (hover: hover) {
  .orbitStar.soon .orbitStarLabel,
  .orbitStar.soon .orbitStarLeader {
    opacity: 0;
  }

  .orbitStar:hover {
    z-index: 2;
  }

  .orbitStarLink:hover .orbitStarLabel {
    opacity: 1;
    background: var(--md-state-glass-hover);
  }

  .orbitStarLink:hover .orbitStarLeader,
  .orbitStarLink:hover .orbitStarMark {
    opacity: 1;
  }

  .orbitStarLink:hover .orbitStarOrbit {
    stroke-opacity: 0.8;
  }

  .orbitStarLink:hover .orbitStarCard {
    opacity: 1;
    visibility: visible;
  }
}

.orbitStar:focus-within {
  z-index: 2;
}

.orbitStarLink:focus-visible .orbitStarCard,
.orbitStarLink:focus-visible .orbitStarLabel,
.orbitStarLink:focus-visible .orbitStarLeader,
.orbitStarLink:focus-visible .orbitStarMark {
  opacity: 1;
  visibility: visible;
}

.orbitStarLink:is(:active, .held) .orbitStarLabel {
  border-radius: var(--md-comp-pressed-morph);
  background: var(--md-state-glass-pressed);
}

/* Forced colors flatten the glass's state layers and the card's lit edge, so the label under the
   pointer or held takes a system outline, and the edge a system line. */
@media (forced-colors: active) {
  .orbitStarLink:is(:active, .held) .orbitStarLabel {
    outline: 0.0625rem solid Highlight;
  }

  .orbitStarCard::before {
    forced-color-adjust: none;
    background: CanvasText;
  }
}

@media (forced-colors: active) and (hover: hover) {
  .orbitStarLink:hover .orbitStarLabel {
    outline: 0.0625rem solid Highlight;
  }
}

/* The way on, at the foot of the screen */

.orbitNext {
  position: absolute;
  left: 50%;
  bottom: 1.75rem;
  display: grid;
  place-items: center;
  /* 40dp like the other icon buttons, where the fixed pill radius reads perfectly round and can still
     morph on press — a 50% circle can only snap, never morph. */
  width: 2.5rem;
  height: 2.5rem;
  margin-left: -1.25rem;
  border: 0.0625rem solid var(--glass-line);
  border-radius: var(--md-comp-shape-pill);
  background: var(--glass);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(1rem) saturate(1.6);
  backdrop-filter: blur(1rem) saturate(1.6);
  color: var(--ink-2);
  transition: color var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard);
}

/* A gentle resting bob, on the icon only — the button's own transform stays free for the press-squish
   and corner morph (expressive.css / below), so the chevron presses like every other button and still
   nods to say "scroll". A small, even up-and-down float, not a big downward dip. */
.orbitNext svg {
  animation: orbitNudge 2.4s ease-in-out infinite;
}

@keyframes orbitNudge {
  0%,
  100% {
    transform: translateY(-0.0625rem);
  }
  50% {
    transform: translateY(0.0625rem);
  }
}

/* The chevron answers the pointer like the other icon controls — the page-ink state layer over its
   glass — and lifts a little on hover, then on press takes the buttons' squish (expressive.css) and
   corner shape-morph. */
@media (hover: hover) {
  .orbitNext:hover {
    color: var(--ink);
    background: var(--md-state-glass-hover);
    transform: translateY(var(--md-comp-button-hover-lift)) scale(1.03);
  }
}

.orbitNext:is(:active, .held) {
  border-radius: var(--md-comp-pressed-morph-small);
  background: var(--md-state-glass-pressed);
}

/* 2. The plugin ----------------------------------------------------------------------------------

   With room. One plugin is out, so it gets what a catalog would take: large type, the video at a
   size where the plugin can be seen working, and air between everything. */

/* The arrow at the foot of the invitation lands here, and everything about the plugin — the title,
   the clip, the buttons and the three reasons — is on screen when it does: the section is one
   screen high, centers what it holds, and leaves the top clear of the nav that lies over it. */

/* A normal section, not a full-screen stretch. Its foot is pulled in, though: the reasons don't need
   a whole section's air under them before the closing statement starts, so the seam into the next block is
   tighter than a default section-to-section gap. */
.homePlugin {
  scroll-margin-top: 0;
  padding-bottom: clamp(1.5rem, 3vw, 2.25rem);
}

.homePluginWrap {
  position: relative;
}

/* The plugins under the featured one: two boxes of equal width with a gap down the middle, and one
   under the other once the pair would be narrower than the words in them. */
.homePluginRow {
  display: grid;
  /* minmax(0, 1fr), or a long name or a wide button row would give one box more than its half. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
  margin-top: clamp(1rem, 2vw, 1.5rem);
}

@media (max-width: 56.25rem) {
  .homePluginRow {
    grid-template-columns: 1fr;
  }
}

.homePluginGrid {
  display: grid;
  /* The plugin at work on the left, the words on the right, in the markup's order, the pair held
     on one glass panel (.glass) so the section reads as a composed M3 surface, not floating text. */
  grid-template-columns: 0.8fr 1.2fr; /* the words take the wider half, the clip the narrower */
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
  align-content: center;
  min-height: var(--panel-height);
  padding: clamp(1.25rem, 3vw, 2.25rem);
  border-radius: var(--md-sys-shape-corner-xl);
}

/* Half the width, so the artwork goes over the words instead of beside them, and the panel is as
   tall as what is in it rather than as tall as the hero. */
.homePluginSmall {
  grid-template-columns: 1fr;
  gap: clamp(1rem, 2vw, 1.5rem);
  min-height: 0;
}

.homePluginSmall .homePluginText {
  align-self: auto;
  text-align: center;
}

/* The name is set for the full panel's width; in half of it, it takes the role a step down, so
   "Stereo Tool" does not run edge to edge. */
.homePluginSmall .homePluginTitle {
  font: var(--md-sys-typescale-display-small);
}

.homePluginSmall .homePluginTagline {
  font: var(--md-sys-typescale-title-large);
}

.homePluginSmall .homePluginActions {
  justify-content: center;
}

/* The type and the air scale with the height of the window as well as its width, so on a low
   laptop screen the whole section — reasons included — still fits in one. */

/* Side by side (above 56.25rem), the words range right off the panel edge, the plugin at work on
   their left; the buttons row stays ranged right with them. Stacked on a phone, the clip over the
   words, they center instead (the max-width: 56.25rem block at the end of this sheet). The column
   stretches to the clip's height and its spare room is shared above the name and under the
   tagline: the two sit in the middle of the words' space, and the buttons drop to the foot, level
   with the clip's bottom edge, over the hairline to the reasons. */
.homePluginText {
  display: flex;
  flex-direction: column;
  align-self: stretch;
  text-align: right;
}

.homePluginText .homePluginTitle {
  margin-top: auto;
}

.homePluginText .homePluginTagline {
  margin-bottom: auto;
  text-wrap: balance; /* ranged right, a lone last word would hang off the edge */
}

/* The name, the tagline, the actions: set as the product page's hero sets them (ProductScreen.css,
   .productTitle / .productLead / .productActions). Change both together. */
.homePluginTitle {
  margin-top: 0;
  font: var(--md-sys-typescale-display-medium);
  white-space: nowrap; /* side by side, the name stays on one line (the column is sized to hold it) */
}

.homePluginTagline {
  margin-top: clamp(0.75rem, 1.5vh, 1.25rem);
  font: var(--md-sys-typescale-title-large);
  font-size: clamp(1.25rem, 1.8vw, 1.625rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.homePluginActions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: clamp(1rem, 2vh, 1.75rem);
}

/* The buttons are the standard M3 Small size (base .button): 40dp, and they morph on press like
   every other button on the site — no size-up, so the same "Add to cart" reads the same here as on
   the product page. */

/* The price leads the row, set the way the product page sets it, a size up. */

.homePluginPrice {
  align-self: stretch;
  display: inline-flex;
  align-items: center;
  margin-right: 0.5rem;
  padding-right: 1.25rem;
  border-right: 0.0625rem solid var(--line);
  font-size: 1.625rem; /* the size the struck price (0.6em) and the price take from; the product hero's too */
}

.homePluginPrice .price {
  font-family: var(--display);
  font-size: 1em;
  letter-spacing: 0.01em;
  color: var(--ink);
}

.homePluginPrice:has(.price:empty) {
  display: none; /* no price yet, no rule standing alone */
}

.homePluginMedia {
  --home-plugin-art-width: 100%; /* the artwork's, which the chip's corner follows */
  position: relative; /* holds the category's chip */
}

/* Coming soon: the clip or the artwork dimmed in its own colors, as on the plugin list's cards (base.css);
   the empty state of a picture still to come stays as it is. */
.homePluginMedia.soon > :not(.categoryChip, div.homePluginArt) {
  filter: brightness(0.7) saturate(0.85);
}

/* A plugin without a clip shows its artwork in the clip's 16:10 frame, filled, so the panel keeps its
   height when the arrows bring it in; its box is held before the picture arrives. */
.homePluginArt {
  display: block;
  width: var(--home-plugin-art-width);
  aspect-ratio: 16 / 10;
  margin-inline: auto;
  border-radius: var(--md-sys-shape-corner-xl);
  object-fit: cover;
}

/* A picture still to come glows in the plugin's color, as it does on a card (PictureToCome.js). */
div.homePluginArt {
  background: rgba(var(--product-accent), 0.12);
}

/* The category's chip on the artwork's corner, as on a card: the artwork is centered in the column. A clip
   fills it, and the chip keeps the corner base.css gives it. */
.homePluginMedia:has(.homePluginArt) .categoryChip {
  left: calc((100% - var(--home-plugin-art-width)) / 2 + 0.75rem);
}

/* Three reasons under it, a long way under it: the product page's own feature style, three across. */

/* The three reasons are the panel's lower row, under the clip and the words, across both columns,
   a hairline between the two rows. */
.homeReasonList {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  margin-top: clamp(0.5rem, 1.5vh, 1.25rem);
  padding-top: clamp(1.25rem, 2.5vh, 2rem);
  border-top: 0.0625rem solid var(--line);
}

/* A subgrid starts the paragraphs level however their headings wrap. Each bar stays on the side
   its text leans to, so the centered middle reason has none. */
.homeReason {
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  row-gap: 0;
  padding: 0.25rem 0 0.25rem 1.75rem;
  border-left: 0.1875rem solid var(--ink-3);
  border-radius: 0.0625rem; /* m3-allow: 1px softening of the 3px bar's outer corners, not a card corner */
}

.homeReason:nth-child(2) {
  border-left: 0;
  padding: 0.25rem 0;
  text-align: center;
}

.homeReason:nth-child(3) {
  border-left: 0;
  border-right: 0.1875rem solid var(--ink-3);
  padding: 0.25rem 1.75rem 0.25rem 0;
  text-align: right;
}

.homeReason h3 {
  font: var(--md-sys-typescale-title-large);
  margin-bottom: 0.75rem;
}

.homeReason p {
  color: var(--ink-2);
  font: var(--md-sys-typescale-body-large);
  text-wrap: pretty;
}

/* 3. Who we are, what is new, and the newsletter ----------------------------------------------------

   Three steps down to the footer. The closing statement is a hook at full size on the sky with no
   panel, as the invitation is, so the page ends the way it opens, then its line and the way to the
   trial. Then the newest articles as cards with their covers, then the newsletter as a bar with the
   mark on it. */

.homeClosing {
  padding: clamp(2rem, 4vw, 3rem) 0 0;
}

.homeStatement {
  padding: clamp(2rem, 5vw, 4.5rem) 0;
  text-align: center;
}

.homeStatement .heroKicker {
  text-wrap: balance; /* "By musicians, / for musicians" on a phone, never the last word alone */
}

.homeStatement .heroTitle {
  margin-bottom: 0;
}

.homeStatementLine {
  margin: 1.5rem auto 0;
  max-width: 32rem;
  color: var(--ink-2);
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  text-wrap: balance;
}

.homeStatementCall {
  margin-top: 2.25rem;
}

/* News: a headline, "News", and the news page's lead and cards under it, which news.css draws (the
   page loads that sheet for this). The way to /news/ is the nav's. */

.homeNews {
  margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
}

.homeNewsTitle {
  margin: 0 0 1rem;
  padding: 0 0.25rem;
  font: var(--md-sys-typescale-headline-medium);
}

/* The grid's own gap, which no headline splits here as "More articles" does on the news page. */
.homeNews .newsList {
  margin-top: 1.75rem;
}

@media (max-width: 56.25rem) {
  /* The column may be narrower than the name (minmax(0, ...)), so on the narrowest phones the
     name breaks between its words instead of pushing the panel past the page's gutters. */
  .homePluginGrid {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0; /* on a phone the panel is as tall as its content */
  }

  /* Stacked under the clip, the words have no edge to face: the name, the tagline and the buttons
     center. */
  .homePluginText {
    text-align: center;
  }

  .homePluginTitle {
    font: var(--md-sys-typescale-display-small);
    white-space: normal;
  }

  .homePluginActions {
    justify-content: center;
  }

  /* The buttons share the full width, as on the product page's hero; three too wide for one line
     leave the cart's, the last, a line of its own. */
  .homePluginActions .button {
    flex: 1 1 auto;
  }

  /* The price takes a line of its own over the buttons, without its rule: alone on a line the
     rule would stand with nothing after it and push the price off the column's center. A sale's
     price wraps inside its block on the narrowest phones; its lines center too. */
  .homePluginPrice {
    flex-basis: 100%;
    justify-content: center;
    margin-right: 0;
    padding-right: 0;
    border-right: 0;
  }

  .homeReasonList {
    grid-template-columns: 1fr;
    gap: 2rem;
  }

  /* One reason under another, none leans to a side and the headings part them, so each centers
     with no bar. The middle and last are named so the rule outranks their own. */
  .homeReason,
  .homeReason:nth-child(2),
  .homeReason:nth-child(3) {
    border-right: 0;
    border-left: 0;
    padding: 0;
    text-align: center;
  }

}

/* Below the fold each label hangs under its star, the ones at the screen's edges kept to them, since a
   label beside its star would run into the core; a card would have no room, so a tap goes straight to
   the plugin. On a phone a name takes the text face's title, and a plugin still to come shows its mark
   alone, its name left to a screen reader, since three names do not fit round so small a disc. */
@media (max-width: 56.25rem) {
  .orbitMap {
    margin-top: 2.5rem;
  }

  .orbitStarLeader,
  .orbitStarCard {
    display: none;
  }

  .orbitStarMark::after {
    content: "";
    position: absolute;
    top: 2.75rem;
    left: 50%;
    width: 0.0625rem;
    height: 0.5rem;
    background: rgba(var(--product-accent), 0.7);
  }

  .orbitStarLabel,
  .orbitStar.east .orbitStarLabel {
    top: 3.25rem;
    right: auto;
    left: 50%;
    justify-items: center;
    padding: 0.25rem 0.5rem;
    text-align: center;
    transform: translateX(-50%);
  }

  .orbitStar.west .orbitStarLabel {
    left: 0;
    justify-items: start;
    text-align: start;
    transform: none;
  }

  .orbitStar.east .orbitStarLabel {
    right: 0;
    left: auto;
    justify-items: end;
    text-align: end;
    transform: none;
  }
}

@media (max-width: 40rem) {
  .orbitStarName {
    font: var(--md-sys-typescale-title-medium);
  }

  .orbitStar.soon .orbitStarLabel,
  .orbitStar.soon .orbitStarMark::after {
    opacity: 0;
  }

  .orbitStarStatus {
    letter-spacing: 0.1em;
  }
}

/* On the narrowest phones the map rises a little toward the hook and a name takes a size down, so the
   star under the core keeps clear of the arrow and the label beside it. */
@media (max-width: 21.25rem) {
  .orbitMap {
    margin-top: 1.5rem;
  }

  .orbitStarName {
    font: var(--md-sys-typescale-title-small);
  }
}

/* A phone on its side (css.md "Values"): the invitation's 34rem floor is taller than the screen, and its
   words alone fill most of it, so the air is tight and the arrow goes, which sat under Safari's
   toolbar there, and so do the stars, which have no room: the top of the plugin's panel shows under
   the hook in their place. The artwork that stands in for a clip is held to the
   screen's height, and the three reasons take a size down. */
@media (max-height: 30rem) {
  .orbit {
    --orbit-height: max(18rem, 80svh); /* convention-allow viewport-unit: most of the small viewport, so the panel's top shows in the arrow's place */
    padding: 4.5rem 0 4rem; /* the nav row above, and room below the core's glow */
  }

  .orbitMap {
    margin-top: 1rem;
  }

  .orbitStars {
    display: none;
  }

  .orbitNext {
    display: none;
  }

  .homePlugin {
    padding-top: 1rem;
  }

  .homePluginMedia {
    --home-plugin-art-width: min(100%, calc((100svh - 6rem) * 16 / 10)); /* convention-allow viewport-unit: the clip's own rule on a short screen (Showcase.css) */
  }

  .homeReason h3 {
    margin-bottom: 0.25rem;
    font: var(--md-sys-typescale-title-medium);
  }

  .homeReason p {
    font: var(--md-sys-typescale-body-medium);
  }
}

/* The featured plugin on a phone on its side: the clip and the words side by side again, and the three
   reasons in a row, so the panel is not two screens tall. */
@media (max-width: 56.25rem) and (max-height: 30rem) {
  .homePluginGrid:not(.homePluginSmall) {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr);
    gap: 1.5rem;
  }

  .homeReasonList {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
  }

  .homePluginTitle {
    font: var(--md-sys-typescale-headline-large);
  }

  .homePluginTagline {
    font-size: 1.125rem;
  }

  /* Beside the clip again, the featured panel's buttons keep their own width. */
  .homePluginGrid:not(.homePluginSmall) .homePluginActions .button {
    flex: none;
  }
}

/* Less motion asked for: the field is a still frame (PixelField.js), and the words' entrance and
   the nudge stop here. */

@media (prefers-reduced-motion: reduce) {
  .orbitStars {
    animation: none;
  }

  /* The global reduced-motion rule (base.css) only strips transition/animation; a resting :hover or
     :active transform still applies, so the hero's controls would jump. Zero them, the way base.css
     does for .productCard, which the news cards are. */
  .orbitNext:hover,
  .salePill:hover {
    transform: none;
  }
}
