/* Light and dark for the mnemonics.eu theme.

   Bootstrap 4 has no dark mode of its own, so the colours live here as custom
   properties and the few Bootstrap rules that set a colour are overridden below.
   The markup keeps its Bootstrap classes, so nothing else had to change.

   Three ways a theme gets picked, in order:
     :root                      light, the default
     prefers-color-scheme       the system setting, unless a choice was stored
     [data-theme]               what the toggle stored, which wins over both
*/

:root {
  --bg: #ffffff;
  --surface: #ffffff;
  --bar: #f5f5f5;
  --line: #dee2e6;
  --ink: #212529;
  --ink-dim: #6c757d;
  --accent: #0035aa;
  --accent-over: #002676;
  --link: var(--accent);
  --link-over: var(--accent-over);
  --button: var(--accent);
  --button-over: var(--accent-over);
  --button-ink: #ffffff;
  --ink-strong: #282828;
  --ink-soft: #646464;
}

/* Dark wears Dark707's own fiery orange, #ff8214, so the site and the plugins
   share an accent.

   The system's own setting, but only while nobody has pressed the toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #15181c;
    --surface: #1d2126;
    --bar: #1a1e23;
    --line: #2e343b;
    --ink: #e6e8ea;
    --ink-dim: #9aa3ab;
    --accent: #ff8214;
    --accent-over: #ff9d47;
    --link: var(--accent);
    --link-over: var(--accent-over);
    --button: var(--accent);
    --button-over: var(--accent-over);
    --button-ink: #15181c;
  --ink-strong: #d7d7d7;
  --ink-soft: #9b9b9b;
    --ink-strong: #d7d7d7;
    --ink-soft: #9b9b9b;
  }
}

/* And the stored choice, which beats the system either way. */
:root[data-theme="dark"] {
  --bg: #15181c;
  --surface: #1d2126;
  --bar: #1a1e23;
  --line: #2e343b;
  --ink: #e6e8ea;
  --ink-dim: #9aa3ab;
  --accent: #ff8214;
  --accent-over: #ff9d47;
  --link: var(--accent);
  --link-over: var(--accent-over);
  --button: var(--accent);
  --button-over: var(--accent-over);
  --button-ink: #15181c;
}

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

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

body {
  margin: 0;
  padding-top: 4.25rem;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 1rem;
  line-height: 1.5;
  background-color: var(--bg);
  color: var(--ink);

  /* The column that puts the footer at the foot of a short page: body is the
     flex container, the footer takes the leftover room above it. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

main {
  flex: 1 0 auto;
  padding-top: 2rem;
  padding-bottom: 2rem;
}

.container {
  width: 100%;
  max-width: 68rem;
  margin: 0 auto;
  padding: 0 1rem;
}

h1, h2, h3, h4 {
  line-height: 1.2;
  margin-top: 0;
}

p {
  margin-top: 0;
}

.lead {
  font-size: 1.15rem;
  max-width: 48rem;
}

a {
  color: var(--link);
  text-decoration: none;
}

a:hover,
a:focus {
  color: var(--link-over);
  text-decoration: underline;
}

code {
  font-size: 0.9em;
}

hr {
  border: 0;
  border-top: 1px solid var(--line);
}

/* Icons are drawn inline and take the colour of the text around them. */
.icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.125em;
}

abbr[title] {
  text-decoration: none;
  border: 0;
}

/* ---- The bar across the top ---------------------------------------------- */

.navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 1rem;
  background-color: var(--bar);
  border-bottom: 1px solid var(--line);
}

.brand {
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--ink);
  margin-right: auto;
}

.brand:hover,
.brand:focus {
  color: var(--ink);
  text-decoration: none;
}

/* ---- The menu drawer ------------------------------------------------------ */

/* Over the page from the left, at every width. The bar keeps only the button,
   the name and the light/dark switch. */
.drawer {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  z-index: 50;
  width: min(18rem, 78vw);
  padding: 4.5rem 1.5rem 1.5rem;
  overflow-y: auto;
  background-color: var(--surface);
  border-right: 1px solid var(--line);
  transform: translateX(-100%);

  /* Out of the tab order while it is shut, and the delay keeps it visible for
     as long as it takes to slide away. */
  visibility: hidden;
  transition: transform 180ms ease, visibility 0s linear 180ms;
}

.drawer.open {
  transform: translateX(0);
  visibility: visible;
  transition: transform 180ms ease, visibility 0s;
}

.menu {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.menu a {
  font-size: 1.05rem;
  color: var(--ink);
}

.menu a:hover,
.menu a:focus {
  color: var(--accent);
  text-decoration: none;
}

/* What dims the page behind the drawer, and what you press to shut it. */
.veil {
  position: fixed;
  inset: 0;
  z-index: 40;
  background-color: rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease;
}

.veil.open {
  opacity: 1;
  pointer-events: auto;
}

/* The page behind holds still while the drawer is over it. */
body.drawer-open {
  overflow: hidden;
}

/* Somebody who has asked for less movement gets the drawer without the slide. */
@media (prefers-reduced-motion: reduce) {
  .drawer,
  .veil {
    transition: none;
  }
}

/* ---- Cards --------------------------------------------------------------- */

.card {
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0.25rem;
  margin-bottom: 1.5rem;
}

.card-header {
  margin: 0;
  padding: 0.75rem 1.25rem;
  font-size: 1.1rem;
  font-weight: 600;
  background-color: var(--bar);
  border-bottom: 1px solid var(--line);
  border-radius: 0.25rem 0.25rem 0 0;
}

.card-body {
  padding: 1.25rem;
}

.card-title {
  font-size: 1.15rem;
  margin-bottom: 0.35rem;
}

.card-meta small,
.text-muted {
  color: var(--ink-dim);
}

.card address {
  font-style: normal;
  margin-bottom: 1rem;
}

.card address:last-child {
  margin-bottom: 0;
}

.contact {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

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

.btn {
  display: inline-block;
  font: inherit;
  padding: 0.4rem 0.9rem;
  cursor: pointer;
  color: var(--button-ink);
  background-color: var(--button);
  border: 1px solid var(--button);
  border-radius: 0.25rem;
}

.btn:hover,
.btn:focus {
  color: var(--button-ink);
  background-color: var(--button-over);
  border-color: var(--button-over);
  text-decoration: none;
}

/* ---- The homepage's two columns ------------------------------------------ */

.home-title {
  margin-bottom: 0.5rem;
}

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

@media (min-width: 48rem) {
  .home-columns {
    grid-template-columns: minmax(16rem, 22rem) 1fr;
    align-items: start;
  }
}

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

.footer {
  flex-shrink: 0;
  padding: 1rem 0;
  background-color: var(--bar);
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
}

.footer-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

/* The toggle in the navbar. A button rather than a link, since it goes nowhere. */
/* The two buttons in the bar. One rule, so the menu button and the light/dark
   switch cannot drift apart. */
.navtoggle,
.themetoggle {
  display: inline-flex;
  align-items: center;
  background: none;
  border: 1px solid var(--line);
  border-radius: 0.25rem;
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  font-size: 1.05rem;
  line-height: 1;
  padding: 0.35rem 0.6rem;
}

.navtoggle:hover,
.navtoggle:focus,
.themetoggle:hover,
.themetoggle:focus {
  color: var(--link-over);
  border-color: var(--accent);
}

/* The two faces of it: the one for the theme you would switch to is the one
   shown, and the other is out of the way. */
.themetoggle .tolight { display: none; }
:root[data-theme="dark"] .themetoggle .tolight { display: inline; }
:root[data-theme="dark"] .themetoggle .todark { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .themetoggle .tolight { display: inline; }
  :root:not([data-theme="light"]) .themetoggle .todark { display: none; }
}

/* Pictures in the content carry the page's own frame rather than none at all. */
main img {
  max-width: 100%;
  height: auto;
}

/* The GitHub corner. Was three copies of the same inline style and the same
   <style> block; now one partial and one set of rules.

   It takes its two colours from the theme rather than naming black and white,
   so the triangle stays visible on a dark page instead of sinking into it. */
.github-corner svg {
  position: absolute;
  top: 56px;
  right: 0;
  width: 80px;
  height: 80px;
  fill: var(--ink);
  color: var(--bg);
}

.github-corner .octo-arm {
  transform-origin: 130px 106px;
}

.github-corner:hover .octo-arm {
  animation: octocat-wave 560ms ease-in-out;
}

@keyframes octocat-wave {
  0%, 100% { transform: rotate(0); }
  20%, 60% { transform: rotate(-25deg); }
  40%, 80% { transform: rotate(10deg); }
}

/* On a small screen there is no hovering, so the arm waves on arrival instead. */
@media (max-width: 500px) {
  .github-corner:hover .octo-arm { animation: none; }
  .github-corner .octo-arm { animation: octocat-wave 560ms ease-in-out; }
}

/* The map on the about page. */
.maptile {
  width: 100%;
  height: 280px;
  border: 0;
}

/* Pictures in content.

   The common case: the same file, inverted by the browser in dark mode. Invert
   leaves the alpha channel alone, so a transparent background stays transparent.

   The other case: a file with a dark twin beside it, where inverting would look
   wrong. Then both are in the markup and one of them is shown. */
:root[data-theme="dark"] .invertible { filter: invert(1); }

.onlight { display: inline-block; }
.ondark { display: none; }

:root[data-theme="dark"] .onlight { display: none; }
:root[data-theme="dark"] .ondark { display: inline-block; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .invertible { filter: invert(1); }
  :root:not([data-theme="light"]) .onlight { display: none; }
  :root:not([data-theme="light"]) .ondark { display: inline-block; }
}

/* The logo. One path with the lettering cut out of it, so the letters take
   whatever the page is behind them and no second file is needed for dark. */
.sitelogo {
  display: block;
  width: 100%;
  /* The old PNG drew its pill 1126px wide inside a 1196px canvas. The drawing
     is cropped tight, so the cap is the pill's own width and the margin below
     replaces the transparent border the file used to carry. */
  max-width: 1126px;
  margin: 0 0 2rem;
  color: var(--accent);
}

/* The file carries its size in millimetres, which is no use in a page. */
.sitelogo svg {
  display: block;
  width: 100%;
  height: auto;
}

/* An inlined drawing from content. It stands where the <img> used to, so it
   carries the same sizing. */
.figure {
  display: block;
  max-width: 100%;
}

.figure svg {
  display: block;
  width: 100%;
  height: auto;
}

/* The dialog. Its own element rather than a library, so it wears the theme like
   everything else and asks whatever it is handed. */
.ask {
  max-width: 32rem;
  width: calc(100% - 2rem);
  padding: 0;
  color: var(--ink);
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0.3rem;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
}

.ask::backdrop {
  background-color: rgba(0, 0, 0, 0.6);
}

.ask-title {
  margin: 0;
  padding: 1rem 1.25rem;
  font-size: 1.1rem;
  font-weight: 600;
  background-color: var(--bar);
  border-bottom: 1px solid var(--line);
}

.ask-body {
  margin: 0;
  padding: 1.25rem;
}

.ask-buttons {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  padding: 0 1.25rem 1.25rem;
}

.ask-buttons button {
  font: inherit;
  padding: 0.375rem 0.9rem;
  border-radius: 0.25rem;
  cursor: pointer;
  border: 1px solid var(--line);
  color: var(--ink);
  background-color: transparent;
}

.ask-buttons button:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* The one that carries the action reads as a button rather than a way out. */
.ask-yes {
  color: var(--button-ink);
  background-color: var(--button);
  border-color: var(--button);
}

.ask-yes:hover {
  color: var(--button-ink);
  background-color: var(--button-over);
  border-color: var(--button-over);
}

/* Where the two navbar buttons sit.

   On a phone they group at the right end, theme switch then menu, both always
   reachable. From the breakpoint up the menu button is gone and the switch goes
   back to the far right, past the links. */
.navbar .themetoggle {
  margin-left: auto;
}

.navbar .navbar-toggler {
  margin-left: 0.4rem;
}

@media (min-width: 768px) {
  .navbar .navbar-collapse { order: 2; }
  .navbar .themetoggle { order: 3; margin-left: 0.5rem; }
}

/* A message rather than a question: nothing to decline, so the second button
   is not shown. */
.ask.telling .ask-no {
  display: none;
}

/* The contact card and the text beside it. Side by side from the breakpoint up,
   stacked below it, and stacked they ran into each other. The gap lives on the
   card, which is harmless in the two-column case since the column it sits in is
   the shorter of the pair. */
.col-sm-4 > .card {
  margin-bottom: 2rem;
}

/* ---- The shop ---------------------------------------------------------- */

/* Each plugin's own colour, taken from its panel.css, so the shop looks like
   the things it sells. Declared once per id rather than carried in the markup. */
.p-dark707      { --product: #ff8214; }
.p-darkerbox    { --product: #e0506e; }
.p-darklight    { --product: #56c96b; }
.p-darkmatter2  { --product: #4e86d8; }
.p-darkoperator { --product: #cf9a3a; }
.p-darkorbit    { --product: #9b6dd6; }
.p-darkwave     { --product: #c4483c; }
.p-bundle       { --product: var(--accent); }
.p-dark         { --product: #ff8214; }

.shop-title {
  margin-bottom: 0.5rem;
}

.shop-lead {
  margin-bottom: 2rem;
}

.products {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: 1.25rem;
  margin-bottom: 2rem;

  /* Each card is as tall as its own contents and sits on the line of the row.
     Stretched instead, an ordinary card beside a wide one would be pulled to
     twice its height with the gap left hanging under its words. */
  align-items: end;
}

/* A card rather than a row: it stands on the page, and the band at the top is
   the slot a panel screenshot drops into later. */
.product-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--ink);
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0.35rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
  text-decoration: none;
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}

.product-card:hover,
.product-card:focus {
  color: var(--ink);
  text-decoration: none;
  border-color: var(--product, var(--accent));
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
  transform: translateY(-2px);
}

/* The picture slot. A panel is wider than it is tall, so the empty state keeps
   the same shape a screenshot will, and the card never changes height when one
   arrives. Empty, it is the product's own colour rather than a grey hole. */
.shot {
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background-color: var(--surface);
  background-image: linear-gradient(
    150deg,
    var(--product, var(--accent)),
    color-mix(in srgb, var(--product, var(--accent)) 45%, #000));
}

.shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;

  /* Panels are taller than the slot, so something is cropped. Held to the top,
     what goes is the keyboard along the bottom rather than the title bar with
     the plugin's name in it. */
  object-position: top;

  /* Eased in over the colour once it has arrived, rather than appearing at
     once. shots.js adds the class; nothing else about it is its business. */
  opacity: 0;
  transition: opacity 280ms ease;
}

.shot img.here {
  opacity: 1;
}

/* Without JavaScript nothing adds the class, so the picture is simply there. */
.no-js .shot img {
  opacity: 1;
}

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

/* A slot that stands for a whole set rather than one plugin: the bundle, and a
   line on the shop front. The pictures are stacked in the one box and shots.js
   moves the class along, so the change is the fade declared above. */
.shot-many {
  position: relative;
}

.shot-many img {
  position: absolute;
  inset: 0;
}

/* The one coming in lies over the one going out, and the one going out is held
   at full opacity until it is covered. Fading both at once would let the colour
   behind show through the middle of every change. */
.shot-many img.here {
  z-index: 1;
}

.shot-many img.going {
  opacity: 1;
  transition: none;
}

/* Without JavaScript nothing cycles, so only the first one shows. */
.no-js .shot-many img + img {
  opacity: 0;
}


.product-body {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  flex: 1 1 auto;
  padding: 1rem 1.15rem 1.15rem;
}

.product-name {
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--product, var(--accent));
  line-height: 1.2;
}

.product-what {
  color: var(--ink-dim);
  font-size: 0.9rem;
}

.product-summary {
  margin-top: 0.35rem;
}

.product-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1.15rem;
  background-color: var(--bar);
  border-top: 1px solid var(--line);
}

.product-price {
  font-weight: 600;
}

.product-go {
  color: var(--product, var(--accent));
}

/* The cards that stand for a whole set: the bundle, and a line on the shop
   front. Two columns rather than the whole row, so an ordinary card still sits
   beside one and the row is not left half empty. Two columns is also the width
   at which a panel fills the slot above without being cropped to a strip.

   Which comes first is the weight in the front matter, not this rule: put the
   big one first and a small one follows it, put a small one first and the big
   one lands beside it. Below two columns there is nothing to span. */
@media (min-width: 38rem) {
  .product-wide,
  .hero {
    grid-column: span 2;
  }
}

/* A product's own page. */
.product-page {
  max-width: 44rem;
}

.product-head {
  border-left: 4px solid var(--product, var(--accent));
  padding-left: 1rem;
  margin-bottom: 1.5rem;
}

.product-title {
  margin: 0;
  color: var(--product, var(--accent));
}

.product-head .product-what {
  margin: 0;
}

.product-body {
  margin-bottom: 2rem;
}

/* The buy control. */
.buy {
  display: grid;
  gap: 0.5rem;
  padding: 1.25rem;
  margin-bottom: 2rem;
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0.25rem;
  max-width: 26rem;
}

.buy-label {
  margin: 0;
  color: var(--ink-dim);
}

.buy-email {
  font: inherit;
  padding: 0.5rem 0.65rem;
  color: var(--ink);
  background-color: var(--bg);
  border: 1px solid var(--line);
  border-radius: 0.25rem;
}

.buy-email:focus {
  outline: none;
  border-color: var(--product, var(--accent));
}

.buy-go {
  font: inherit;
  padding: 0.55rem 1rem;
  cursor: pointer;
  color: var(--button-ink);
  background-color: var(--product, var(--accent));
  border: 1px solid var(--product, var(--accent));
  border-radius: 0.25rem;
}

.buy-go:hover {
  filter: brightness(1.12);
}

/* Switched off rather than taken away. It keeps its colour, dimmed, so the
   price is still readable and the control still reads as the thing that will
   work later. */
.buy-off .buy-email,
.buy-off .buy-go {
  opacity: 0.5;
  cursor: not-allowed;
}

.buy-off .buy-go:hover {
  filter: none;
}

.buy-note {
  margin: 0;
  font-size: 0.85rem;
  color: var(--ink-dim);
}

.downloads {
  margin-bottom: 2rem;
}

.download-list {
  padding-left: 1.2rem;
}

.product-back {
  color: var(--ink-dim);
}

/* A line of products, given room rather than stretched across a row. The band
   is where artwork for the line goes once there is any. */
.hero {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--ink);
  background-color: var(--surface);
  background-image: linear-gradient(
    160deg,
    color-mix(in srgb, var(--product, var(--accent)) 16%, var(--surface)),
    var(--surface) 60%);
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  text-decoration: none;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

.hero:hover,
.hero:focus {
  color: var(--ink);
  text-decoration: none;
  border-color: var(--product, var(--accent));
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}

.hero-body {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 2.25rem 2rem 1.25rem;
}

.hero-name {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--product, var(--accent));
}

.hero-what {
  font-size: 1.15rem;
}

.hero-meta {
  color: var(--ink-dim);
  font-size: 0.9rem;
}

.hero-go {
  align-self: flex-start;
  margin: 0 2rem 2.25rem;
  padding: 0.5rem 1.1rem;
  color: var(--button-ink);
  background-color: var(--product, var(--accent));
  border-radius: 0.25rem;
}

/* On the product's own page the picture leads, at the width of the column and
   whole. A card may crop, being a thumbnail among others of one shape. This is
   the thing itself, so the slot takes the panel's shape instead of imposing
   one, and nothing of the plugin is cut off.

   The img carries its real width and height, so the space is reserved at the
   right size before the picture arrives and the page does not jump. */
.product-page .shot {
  aspect-ratio: auto;
  border-radius: 0.35rem;
  border: 1px solid var(--line);
  margin-bottom: 1.5rem;
}

.product-page .shot img {
  height: auto;
}

/* Except the bundle, whose picture is a stack of seven panels with no one shape
   between them. That keeps the card's. */
.product-page .shot-many {
  aspect-ratio: 16 / 10;
}

.product-page .shot-many img {
  height: 100%;
}
