/* ---- tokens.css ---- */

/* Brand faces and design tokens. Everything else in the sheet reads from here. */

@font-face {
  font-family: "Artisan";
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MSwicHVyIjoiYmxvYl9pZCJ9fQ==--2edcbe5dabfa1c7ad6a078e2dcd6331ef53ae1b9/artisan12.otf") format("opentype");
}
@font-face {
  font-family: "Olympia Script";
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MiwicHVyIjoiYmxvYl9pZCJ9fQ==--39f2eebf5ce9bfda075944ec6dcf77272b03527e/OlympiaScript.ttf") format("truetype");
}

@layer tokens {
  :root {
    color-scheme: light;

    --red-bright: #ef4444;
    --red: #991b1b;
    --red-deep: #7f1d1d;

    --ink: #16110f;
    --ink-soft: #574f4b;
    --paper: #ffffff;
    --paper-sunk: #f6f3f1;
    --rule: #ded7d2;

    --font-serif: prestige-elite-std, "Courier New", "Courier", monospace;
    --font-sans: var(--font-sans);
    --font-display: var(--font-sans);

    /* A 1.25 scale from 1rem, with the body text itself fluid. */
    --text-sm: 0.8rem;
    --text-base: clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
    --text-lg: 1.25rem;
    --text-xl: 1.563rem;
    --text-2xl: 1.953rem;
    --text-3xl: clamp(2rem, 1.6rem + 2vw, 2.441rem);

    --space-2xs: 0.25rem;
    --space-xs: 0.5rem;
    --space-sm: 0.75rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2.5rem;
    --space-2xl: 4rem;
    --space-3xl: 6rem;

    /* Wide enough for prose, narrow enough to stay readable. */
    --measure: 68ch;
    --page-max: 68rem;
    --gutter: clamp(1.25rem, 5vw, 3.5rem);

    --rule-weight: 1px;
    --focus-ring: 2px solid var(--red);
  }
}

/* ---- base.css ---- */

/* How bare elements read, before any component gets involved. */

@layer base {
  body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-serif);
    font-size: var(--text-base);
    line-height: 1.55;
    text-rendering: optimizelegibility;
  }

  h1,
  h2,
  h3 {
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: 0.01em;
    text-wrap: balance;
  }

  h1 {
    font-size: var(--text-3xl);
  }

  h2 {
    font-size: var(--text-2xl);
  }

  h3 {
    font-size: var(--text-xl);
  }

  h4 {
    font-family: var(--font-sans);
    font-size: var(--text-lg);
    font-weight: 700;
    line-height: 1.2;
  }

  p {
    text-wrap: pretty;
  }

  /*
   * Underlined by default and offset clear of the descenders. A link in running
   * prose has to be findable without colour alone doing the work.
   */
  a:where([href]) {
    color: var(--red-deep);
    text-decoration: underline;
    text-decoration-thickness: from-font;
    text-underline-offset: 0.15em;

    &:hover {
      color: var(--red-bright);
    }
  }

  :focus-visible {
    outline: var(--focus-ring);
    outline-offset: 3px;
  }

  strong,
  b {
    font-weight: 700;
  }

  blockquote {
    border-inline-start: 3px solid var(--red);
    padding-inline-start: var(--space-md);
    font-style: italic;
  }

  hr {
    border: 0;
    border-top: var(--rule-weight) solid var(--rule);
  }

  figcaption {
    color: var(--ink-soft);
    font-family: var(--font-sans);
    font-size: var(--text-sm);
  }

  ::selection {
    /* The look of a rubylith sheet laid over the page. */
    background: var(--red-bright);
    color: var(--paper);
  }
}

/* ---- layout.css ---- */

/* The page shell: masthead, nav, the column content sits in, footer. */

@layer layout {
  .page {
    display: grid;
    grid-template-rows: auto 1fr auto;
    min-height: 100svh;
  }

  /* Sends keyboard users past the masthead; visible only once focused. */
  .skip-link {
    position: absolute;
    inset-inline-start: var(--space-md);
    inset-block-start: var(--space-md);
    z-index: 10;
    background: var(--paper);
    padding: var(--space-xs) var(--space-md);
    transform: translateY(-200%);

    &:focus {
      transform: none;
    }
  }

  .masthead__banner {
    aspect-ratio: 16 / 4;
    background-color: var(--paper);
    background-image: url("/assets/rubylith-film-f8869abc.webp");
    background-position: 46% 34%;
    background-size: cover;

    @media (width < 40rem) {
      aspect-ratio: 16 / 7;
    }
  }

  .masthead__bar {
    display: flex;
    flex-wrap: wrap;

    /* The top, not the baseline: an image wordmark has no text baseline, so
       baseline alignment sat the nav on the logo's bottom edge. */
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-sm) var(--space-xl);

    /* No rule under the bar: the masthead is separated from the page by its own
       space, not by a line drawn across it. */
    padding: var(--space-md) var(--gutter);
  }

  .masthead__wordmark {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    line-height: 1;
    letter-spacing: 0.02em;
    text-transform: lowercase;

    /* The wordmark is the site's name, not a link in prose. */
    &:where([href]) {
      color: var(--ink);
      text-decoration: none;
    }

    & span {
      color: var(--red);
    }
  }

  .masthead__logo {
    display: block;
    width: auto;

    /* 7.5rem is the logo variant's own height -- media_variants limits it to
       600x120 -- so the mark is as large as it goes before the browser would be
       upscaling it. Raise the variant first if it should be larger. */
    max-height: 7.5rem;
  }

  /* Populated from the CMS once pages exist; styled here so it lands dressed. */
  .site-nav {
    & ul {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-md) var(--space-lg);
      margin: 0;
      padding: 0;
      list-style: none;
    }

    & a {
      color: var(--ink-soft);
      font-family: var(--font-sans);
      font-size: var(--text-sm);
      letter-spacing: 0.06em;
      text-decoration: none;
      text-transform: lowercase;

      &:hover,
      &[aria-current="page"] {
        color: var(--red-deep);
      }

      &[aria-current="page"] {
        text-decoration: underline;
        text-underline-offset: 0.35em;
      }
    }

    /* A page drawn in the nav as images. The nav variant is 80px tall, so the
       art stays sharp at 2x well below that; the width follows the height. */
    & .cms-nav-image img {
      width: auto;
      height: 1.9rem;
    }
  }

  /* Half the space below the content, and half above the footer: the gap
     between the two is half what it was. */
  .page__main {
    padding: var(--space-2xl) var(--gutter) calc(var(--space-3xl) / 2);
  }

  /* The article is the page column, centred on the page. Everything inside it
     starts at its left edge -- a heading and the paragraph under it have to
     share an edge, and centring each block separately strands the prose in the
     middle of the page with the heading off to one side. */
  .page__main > :where(*) {
    margin-inline: auto;
    max-width: var(--page-max);
  }

  /* The page heading and the first section under it need air between them. */
  .page__main h1 {
    margin-block-end: var(--space-xl);
  }

  /* A page heading drawn as an image. The header stamps share one canvas
     with a common baseline, so one height gives every page the same letter
     size; the width follows, and a phone narrower than the stamp shrinks it. */
  .page__main h1 img {
    width: auto;
    height: 3rem;
    max-width: 100%;
    object-fit: contain;
    object-position: left bottom;
  }

  .prose {
    max-width: var(--measure);

    & > * + * {
      margin-block-start: var(--space-md);
    }

    & > * + :is(h2, h3) {
      margin-block-start: var(--space-xl);
    }
  }

  .site-footer {
    padding: calc(var(--space-xl) / 2) var(--gutter) var(--space-xl);
    color: var(--ink-soft);
    font-family: var(--font-sans);
    font-size: var(--text-sm);

    & > * {
      margin-inline: auto;
      max-width: var(--page-max);
    }

    & > * + * {
      margin-block-start: var(--space-xs);
    }
  }

  /* Whatever links staff put in site settings, on one line, centred on the
     page column -- and on each other, so a label sits level with an image. */
  .site-footer__social {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-md) var(--space-xl);
  }

  /* A link drawn as an image (phaedo-cms 0.30), tall enough that lettering
     on it reads; the width follows. A little over the social variant's 91px:
     its 2x source keeps it sharp on a high-density screen, and a 1x screen
     stretches it by a few percent. */
  .site-footer__social-image {
    display: block;
    width: auto;
    height: 6.05rem;
  }

  /* The envelope is nearly twice as wide as it is tall, so at the others'
     height it outweighs them. Drawn a little narrower than the newsletter
     instead, and set nearer to it than to the camera. */
  .site-footer__social a[href^="mailto:"] .site-footer__social-image {
    height: 4.44rem;
  }

  .site-footer__social li:has(> a[href^="mailto:"]) {
    margin-inline-end: calc(var(--space-sm) * -1);
  }

  /* The camera's flash rays fill the top of its canvas, so centring the
     canvas sits the camera itself low. Raised by the gap, 8% of its height,
     its body centres on the same line as the envelope and the newsletter. */
  .site-footer__social a[href*="instagram.com"] .site-footer__social-image {
    translate: 0 -8%;
  }
}

/* ---- sections.css ---- */

/*
 * One rule set per CMS section type. These are the only styles that depend on
 * what the CMS can produce, so they are kept apart from the page shell.
 */

@layer components {
  /* Sections stack down the page with air between them, capped at a readable
     measure and aligned with the heading above them. Each decides its own width
     by overriding this.
  */
  .section {
    max-width: var(--measure);

    & + & {
      margin-block-start: var(--space-xl);
    }
  }

  .section--rich-text {
    /* .prose supplies the spacing; nothing more is needed here. */
  }

  /*
   * Action Text writes plain HTML with no classes of its own, so the elements
   * an editor produces are styled by element inside the section.
   */
  .prose :is(ul, ol) {
    padding-inline-start: var(--space-lg);
    list-style: revert;
  }

  .prose li + li {
    margin-block-start: var(--space-2xs);
  }

  /*
   * Everything an editor can put inside .lexxy-content, the wrapper
   * layouts/action_text/contents/_content.html.erb renders around a body.
   *
   * The gem ships lexxy-content.css for this and the public site deliberately
   * does not link it. It is 14kB behind two serial round trips, most of it
   * Prism token colours and mention chrome nothing here can produce; it styles
   * .lexxy-content itself, which no layer trick stops from beating an inherited
   * --ink; and it keys block spacing off <p>, which the pages Trix wrote are
   * not made of. These rules are shorter, in this palette, and element-agnostic
   * so old and new bodies stack alike.
   */
  .lexxy-content {
    /* .prose spaces its own children, but Action Text renders this wrapper in
       between, and `> * + *` does not reach through it. */
    & > * + * {
      margin-block-start: var(--space-md);
    }

    & > * + :is(h2, h3) {
      margin-block-start: var(--space-xl);
    }

    /* Lexxy's toolbar can insert a table, and its engine widens Action Text's
       sanitizer to let one through -- so tables reach the public site now,
       where nothing had ever styled them. The wrapper scrolls rather than
       widening the page, the way a wide code block would. */
    & :is(figure:has(table), table) {
      max-inline-size: 100%;
      overflow-x: auto;
    }

    & table {
      border-collapse: collapse;
    }

    & :is(th, td) {
      border: var(--rule-weight) solid var(--rule);
      padding: var(--space-2xs) var(--space-xs);
      text-align: start;
    }

    /* One long line in a code block otherwise scrolls the whole document. */
    & pre {
      overflow-x: auto;
      padding: var(--space-sm);
      background-color: var(--paper-sunk);
    }

    & :is(pre, code) {
      font-family: ui-monospace, "SF Mono", menlo, monospace;
      font-size: var(--text-sm);
    }

    /* The highlight button, which would otherwise be browser yellow. */
    & mark {
      background-color: color-mix(
        in oklab,
        var(--red-bright) 18%,
        var(--paper)
      );
      color: inherit;
    }

    & .attachment {
      display: inline-block;
      max-width: 100%;
      margin-block: var(--space-md);
    }

    & .attachment img {
      width: 100%;
    }

    & .attachment__caption {
      display: block;
      color: var(--ink-soft);
      font-family: var(--font-sans);
      font-size: var(--text-sm);
      text-align: center;
    }

    /* An editor can drop several images in a row; they share the width. */
    & .attachment-gallery {
      display: flex;
      flex-wrap: wrap;
      gap: var(--space-sm);

      & > :is(action-text-attachment, .attachment) {
        flex: 1 0 12rem;
      }
    }
  }

  .callout {
    border-inline-start: 4px solid var(--callout-accent, var(--red));
    background: var(--callout-ground, var(--paper-sunk));
    padding: var(--space-md) var(--space-lg);

    &.callout--note {
      --callout-accent: var(--ink-soft);
    }

    &.callout--warning {
      --callout-accent: var(--red-bright);
      --callout-ground: color-mix(in oklab, var(--red-bright) 8%, var(--paper));
    }

    &.callout--success {
      --callout-accent: #2f6f3e;
      --callout-ground: color-mix(in oklab, #2f6f3e 8%, var(--paper));
    }
  }

  .section--image {
    & img {
      width: 100%;
    }

    & figcaption {
      margin-block-start: var(--space-xs);
    }

    /* The two wider settings break out of the measure: wide fills the page
       column, full escapes it entirely. */
    &.section--wide {
      max-width: var(--page-max);
    }

    &.section--full {
      max-width: none;
      /* Full bleed out of the centred column. */
      margin-inline: calc(50% - 50vw);
    }
  }

  .section--gallery {
    max-width: var(--page-max);
  }

  .gallery {
    display: grid;
    /* The editor's column count is the ceiling, not the count: the grid still
       collapses on a narrow screen rather than producing six slivers. */
    grid-template-columns: repeat(
      auto-fit,
      minmax(
        min(14rem, 100%),
        calc(100% / var(--gallery-columns, 3) - var(--space-sm))
      )
    );
    gap: var(--space-sm);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .gallery__item img {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
  }

  /* A link drawn big: a button in the site's red, aligned with the prose
     around it, or an image chosen for it, which is the link itself and fills
     the measure as an image section does. */
  .cta-button {
    display: inline-block;
    padding: var(--space-md) var(--space-xl);
    background: var(--red);
    color: var(--paper);
    font-family: var(--font-sans);
    font-size: var(--text-lg);
    font-weight: 700;
    text-decoration: none;
    /* Labelled with its link when it has no words of its own, which can be
       one unbroken run as wide as the link is long. */
    overflow-wrap: anywhere;

    &:hover {
      background: var(--red-deep);
    }

    &:focus-visible {
      outline: var(--focus-ring);
      outline-offset: 3px;
    }
  }

  /* Centred in the column the prose sits in. */
  .section--call-to-action {
    text-align: center;
  }

  /* Button-sized, not the measure: an image here is a drawn button, and
     only the image is the link, not the row it sits in. The link is as wide
     as the image, so the auto margins centre it. */
  .cta-image {
    display: block;
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;

    & img {
      display: block;
      width: 19.5rem;
      max-width: 100%;
    }

    &:focus-visible {
      outline: var(--focus-ring);
      outline-offset: 3px;
    }
  }

  /* A bio (phaedo-cms 0.35): the name across the top, and under it the
     picture beside the words, so the picture starts level with the bio
     itself rather than with the name. .bio__text only wraps the two; its name
     and body are placed in the section's grid directly. Where the column is
     too narrow for both, they stack: name, picture, words. */
  .section--bio {
    display: grid;
    grid-template-columns: 12rem minmax(0, var(--measure));
    grid-template-areas:
      ".       name"
      "picture body";
    align-items: start;
    gap: var(--space-md) var(--space-lg);
    max-width: var(--page-max);

    /* No name: the picture and the words share the top row. */
    &:not(:has(.bio__text > h2)) {
      grid-template-areas: "picture body";
    }

    /* No picture: the words take the left edge, as prose does. */
    &:not(:has(.bio__picture)) {
      grid-template-columns: minmax(0, var(--measure));
      grid-template-areas: "name" "body";
    }

    /* Where the old flex row wrapped: a column under 31.5rem, the picture's
       12rem, the gap and the words' 18rem. */
    @media (width < 35rem) {
      grid-template-columns: minmax(0, 1fr);
      grid-template-areas: "name" "picture" "body";
    }
  }

  .bio__picture {
    grid-area: picture;
    width: 100%;
    max-width: 12rem;
  }

  .bio__text {
    display: contents;

    & > h2 {
      grid-area: name;
    }

    /* The grid's row gap spaces it from the name, not .prose. */
    & > .lexxy-content {
      grid-area: body;
      margin-block-start: 0;
    }
  }

  /* An embed (phaedo-cms 0.34), drawn by the engine's own partial. Acuity
     centres its booking form, at most 900px wide, in whatever frame it gets,
     inset 33px from either side, so a frame as wide as the page column left
     the form floating in the middle of the page. The frame is only as wide
     as the form and its insets, and starts one inset left of the column, so
     the form's left edge lines up with the prose above it. The 33px and
     900px are Acuity's, measured 2026-11-02: if its layout changes, these
     follow. Acuity's frames only: anything else framed has no such insets,
     and fills the column from its left edge, as the prose does. */
  .cms-section--embed iframe[src^="https://app.acuityscheduling.com/"] {
    width: calc(100% + 33px);
    max-width: calc(900px + 66px);
    margin-inline-start: -33px;
  }
}

/* Test strips behind every page but Home: an image from the media library,
   tilted, hanging off the right edge of the screen and fixed there as the
   page scrolls past. Each page is keyed on its og:title, the only per-page
   hook the public layout draws, so renaming a page drops its strip. The
   media library does not know this sheet uses the images, and will let
   them be deleted.

   A page sets which image, its shape and its width, and may change the
   placement below from its defaults: --strip-tilt (-15deg), --strip-shadow
   (the shadow's offset, which has to be turned back by the tilt) and
   --strip-overhang (1 / 3 of the width off the edge).

   Every width also gives way to the screen's height, (100svh - 11rem) times
   the strip's shape: a strip fixed to the screen never scrolls, so the whole
   of it has to fit below the masthead or its foot is never seen. */
@layer components {
  html:has(meta[property="og:title"][content="About Rubylith"]) {
    --strip-image: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTIzLCJwdXIiOiJibG9iX2lkIn19--07f1212b020305a0e1b59806ba78630d798cb56d/bg1%20copy.webp");
    --strip-ratio: 1108 / 1547;

    /* Stops growing at 26rem, which it reaches around 1160px wide. The
       widest strip, so its tilt carries its corner furthest down: 2rem more
       of the screen's height is left for that. */
    --strip-width: clamp(14rem, min(36vw, (100svh - 13rem) * 1108 / 1547), 26rem);
  }

  html:has(meta[property="og:title"][content="Facilities"]) {
    --strip-image: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTM2LCJwdXIiOiJibG9iX2lkIn19--e1331859c32cf96e50c0e7ed998cc6e22055386d/bg2.webp");
    --strip-ratio: 542 / 2089;
    --strip-width: clamp(7rem, min(15vw, (100svh - 11rem) * 542 / 2089), 12rem);
    --strip-tilt: -10deg;
    --strip-shadow: 0.29rem 0.66rem;
    --strip-overhang: 1 / 10;
  }

  /* Between the other two in every measurement: its shape, so a width
     between theirs also stands between them in height, and its tilt and how
     far it hangs off the edge. */
  html:has(meta[property="og:title"][content="Membership"]) {
    --strip-image: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTQwLCJwdXIiOiJibG9iX2lkIn19--dcad531aee68f445394c8547b47fb22b5dbf36af/bg3.webp");
    --strip-ratio: 795 / 2046;
    --strip-width: clamp(10rem, min(22vw, (100svh - 11rem) * 795 / 2046), 16rem);
    --strip-tilt: -12.5deg;
    --strip-shadow: 0.26rem 0.67rem;
    --strip-overhang: 1 / 5;
  }

  /* Between About's and Membership's in every measurement: its shape, so a
     width between theirs also stands between them in height, its tilt, how
     far it hangs off the edge, and the height left for its tilt. */
  html:has(meta[property="og:title"][content="Rubylith Darkroom School"]) {
    --strip-image: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTQzLCJwdXIiOiJibG9iX2lkIn19--11c403a720d6a918bdd469940c57cd524dedff64/bg4.webp");
    --strip-ratio: 936 / 1602;
    --strip-width: clamp(12rem, min(29vw, (100svh - 12rem) * 936 / 1602), 22rem);
    --strip-tilt: -13.75deg;
    --strip-shadow: 0.25rem 0.68rem;
    --strip-overhang: 1 / 4;
  }

  /* Members' and Events' strips are shaped between School's and
     Membership's -- Members' nearer School's, Events' nearer Membership's --
     and every measurement sits between those two in the same proportion. */
  html:has(meta[property="og:title"][content="Members"]) {
    --strip-image: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTQ2LCJwdXIiOiJibG9iX2lkIn19--51393968437645798aa6c3093ecdef0e7de1c863/bg5.webp");
    --strip-ratio: 604 / 1127;
    --strip-width: clamp(11.5rem, min(27vw, (100svh - 12rem) * 604 / 1127), 20.5rem);
    --strip-tilt: -13.5deg;
    --strip-shadow: 0.25rem 0.68rem;
    --strip-overhang: 1 / 4;
  }

  html:has(meta[property="og:title"][content="Events"]) {
    --strip-image: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MTQ4LCJwdXIiOiJibG9iX2lkIn19--f6a82e2c8186aaeba0cdbd4f79a2c12c83e578f8/bg6.webp");
    --strip-ratio: 667 / 1481;
    --strip-width: clamp(10.5rem, min(24vw, (100svh - 11rem) * 667 / 1481), 18rem);
    --strip-tilt: -13deg;
    --strip-shadow: 0.25rem 0.67rem;
    --strip-overhang: 1 / 5;
  }

  /* Shaped between Facilities' and Membership's, nearer Facilities', and
     every measurement sits between those two in the same proportion. */
  html:has(meta[property="og:title"][content="Godspeed"]) {
    --strip-image: url("/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MjI4LCJwdXIiOiJibG9iX2lkIn19--9a46d8fe194baf559cdef084ee3b16cde45f6fab/bg7.webp");
    --strip-ratio: 506 / 1643;
    --strip-width: clamp(8rem, min(18vw, (100svh - 11rem) * 506 / 1643), 13.5rem);
    --strip-tilt: -11deg;
    --strip-shadow: 0.28rem 0.67rem;
    --strip-overhang: 1 / 7;
  }

  html:has(meta[property="og:title"]:is(
    [content="About Rubylith"],
    [content="Facilities"],
    [content="Membership"],
    [content="Rubylith Darkroom School"],
    [content="Members"],
    [content="Events"],
    [content="Godspeed"]
  )) .page__main::before {
    content: "";

    /* Placed by the screen, not the page, so the part hanging off the edge
       is out of reach rather than something to scroll sideways to. */
    position: fixed;
    inset-block-start: 9rem;
    inset-inline-end: calc(var(--strip-width) * var(--strip-overhang, 1 / 3) * -1);

    /* Behind everything on the page, the footer included: the body's paper
       is drawn as the canvas, so nothing between covers the strip, and it
       slides under the footer as the page scrolls. */
    z-index: -1;
    width: var(--strip-width);
    aspect-ratio: var(--strip-ratio);
    background: var(--strip-image) center / contain no-repeat;
    rotate: var(--strip-tilt, -15deg);
    opacity: 0.6;

    /* The shadow turns with the strip, so its offset is turned back by the
       same angle to keep it falling down and to the right. */
    filter: drop-shadow(var(--strip-shadow, 0.23rem 0.68rem) 0.9rem rgb(0 0 0 / 0.3));
    pointer-events: none;

    /* Narrower than the page column, the strip lies under the text rather
       than beside it, so it steps back far enough to read over. */
    @media (width < 60rem) {
      opacity: 0.2;
    }
  }
}