/* chris-macleod.ca — page components.
 *
 * The page chrome is generated by build-pages.sh from template/, so there is one
 * copy of it and it cannot drift from the pages that use it. The identity block
 * in the header and the outbound links in the footer are part of that chrome, and
 * both are emitted on every page.
 *
 * Every selector here must be used by some generated page, and every class a page
 * uses must have a rule here or in common.css. build-pages.sh checks both
 * directions on every build, which is what keeps this file from accumulating
 * styles for markup that no longer exists.
 */

@layer qi.components {
  /* Shell: header, main and footer as a full-height column, so the footer sits at
     the bottom of a short page instead of floating mid-screen. */
  .shell {
    display: grid;
    min-height: 100vh;
    min-height: 100dvh;
    grid-template-rows: auto 1fr auto;
  }

  .shell > * {
    min-width: 0;
  }

  /* One width for the chrome and the text, so the nav's right edge and the text
     column's right edge line up on every page. */
  .wrap {
    width: min(calc(100% - (var(--qi-gutter) * 2)), var(--qi-measure));
    margin-inline: auto;
  }

  .skip-link {
    position: fixed;
    z-index: 100;
    inset-block-start: var(--qi-space-3);
    inset-inline-start: var(--qi-space-3);
    min-height: var(--qi-target-min);
    padding: var(--qi-space-2) var(--qi-space-4);
    transform: translateY(calc(-100% - var(--qi-space-6)));
    border: var(--qi-hairline) solid var(--qi-border-strong);
    border-radius: var(--qi-radius-control);
    background: var(--qi-surface-raised);
    color: var(--qi-text);
    font-weight: var(--qi-weight-semibold);
    text-decoration: none;
  }

  .skip-link:focus {
    transform: translateY(0);
  }

  /* Header: the identity block -------------------------------------------- */
  .site-header {
    border-block-end: var(--qi-hairline) solid var(--qi-border);
  }

  .header-inner {
    display: flex;
    min-height: var(--qi-space-16);
    flex-wrap: wrap;
    gap: var(--qi-space-2) var(--qi-space-5);
    align-items: center;
  }

  /* One link carries u-url and wraps both u-photo and p-name, so the whole
     identity block is one target and the identity URL is written down once. */
  .header-id a {
    display: inline-flex;
    min-height: var(--qi-target-min);
    gap: var(--qi-space-3);
    align-items: center;
    color: var(--qi-text);
    font-size: var(--qi-text-lg);
    font-weight: var(--qi-weight-semibold);
    letter-spacing: -0.015em;
    text-decoration: none;
  }

  .header-id a:hover {
    color: var(--qi-accent-hover);
  }

  /* alt is empty on purpose. The portrait sits directly beside the name it
     depicts and adds nothing the adjacent text does not already carry, and any
     alt inside a link would become the link's accessible name. The longer
     description is still announced, via aria-describedby in the markup. */
  .avatar {
    width: var(--qi-avatar);
    height: var(--qi-avatar);
    border: var(--qi-hairline) solid var(--qi-border);
    border-radius: var(--qi-radius-panel);
    background: var(--qi-surface-sunken);
    object-fit: cover;
  }

  /* Pushed to the far end, so the identity block stays left. */
  .site-nav {
    margin-inline-start: auto;
  }

  .site-nav ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--qi-space-1) var(--qi-space-5);
    align-items: center;
  }

  .site-nav a {
    display: inline-flex;
    min-height: var(--qi-target-min);
    align-items: center;
    color: var(--qi-text-muted);
    font-size: var(--qi-text-sm);
    font-weight: var(--qi-weight-medium);
    text-decoration: none;
  }

  .site-nav a:hover {
    color: var(--qi-accent-hover);
    text-decoration: underline;
    text-underline-offset: 0.24em;
  }

  /* Colour is not the only signal: the current page is also underlined and set
     in the full-strength text colour. */
  .site-nav a[aria-current="page"] {
    color: var(--qi-text);
    text-decoration: underline;
    text-decoration-thickness: var(--qi-hairline);
    text-underline-offset: 0.24em;
  }

  .main {
    padding-block: var(--qi-section);
  }

  /* Home ----------------------------------------------------------------- */
  .bio {
    max-width: 46ch;
    color: var(--qi-text);
    font-family: var(--qi-font-serif);
    font-size: var(--qi-text-lg);
    line-height: var(--qi-leading-prose);
  }

  /* Listing: recent articles on the home page -------------------------------- */
  .listing {
    margin-block-start: var(--qi-section);
    padding-block-start: var(--qi-space-6);
    border-block-start: var(--qi-rule) solid var(--qi-text);
  }

  .listing-header {
    display: flex;
    flex-wrap: wrap;
    gap: var(--qi-space-2) var(--qi-space-4);
    align-items: baseline;
    justify-content: space-between;
    margin-block-end: var(--qi-space-5);
  }

  .section-title {
    font-size: var(--qi-text-xl);
  }

  .all-link {
    font-size: var(--qi-text-sm);
    font-weight: var(--qi-weight-medium);
  }

  /* An untitled article is headed by its date, so the date is the anchor and the
     first paragraph is the link. A date on its own row keeps the two scannable. */
  .article-card-list > * + * {
    border-block-start: var(--qi-hairline) solid var(--qi-border);
  }

  .article-card {
    padding-block: var(--qi-space-5);
  }

  .article-meta {
    color: var(--qi-text-subtle);
    font-family: var(--qi-font-mono);
    font-size: var(--qi-text-label);
    letter-spacing: 0.04em;
  }

  .article-permalink {
    color: var(--qi-text-subtle);
    text-decoration: none;
  }

  .article-permalink:hover {
    color: var(--qi-accent-hover);
    text-decoration: underline;
    text-underline-offset: 0.24em;
  }

  .article-card-text {
    margin-block-start: var(--qi-space-2);
    max-width: 62ch;
    color: var(--qi-text);
    font-size: var(--qi-text-md);
    line-height: var(--qi-leading-body);
  }

  /* A whole paragraph as the link target is a long underline. Keeping it in the
     text colour with a quiet rule reads as text that happens to be clickable. */
  .article-card-text a {
    color: var(--qi-text);
    text-decoration-color: var(--qi-border-strong);
  }

  .article-card-text a:hover {
    color: var(--qi-accent-hover);
    text-decoration-color: currentColor;
  }

  /* Page header ---------------------------------------------------------- */
  .page-header {
    margin-block-end: var(--qi-space-10);
    padding-block-end: var(--qi-space-6);
    border-block-end: var(--qi-rule) solid var(--qi-text);
  }

  .page-title {
    margin-block-end: var(--qi-space-4);
  }

  .page-lede {
    max-width: 52ch;
    color: var(--qi-text-muted);
  }

  /* Archive: every article, grouped by month --------------------------------- */
  .archive-month + .archive-month {
    margin-block-start: var(--qi-space-10);
  }

  .archive-month-label {
    margin-block-end: var(--qi-space-2);
    padding-block-end: var(--qi-space-2);
    border-block-end: var(--qi-hairline) solid var(--qi-border-strong);
    font-family: var(--qi-font-mono);
    font-size: var(--qi-text-sm);
    font-weight: var(--qi-weight-medium);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .archive-entry {
    display: grid;
    grid-template-columns: var(--qi-archive-gutter) minmax(0, 1fr);
    gap: var(--qi-space-3);
    padding-block: var(--qi-space-4);
    border-block-end: var(--qi-hairline) solid var(--qi-border);
  }

  .archive-text {
    max-width: 62ch;
    color: var(--qi-text);
    line-height: var(--qi-leading-body);
  }

  .archive-text a {
    color: var(--qi-text);
    text-decoration-color: var(--qi-border-strong);
  }

  .archive-text a:hover {
    color: var(--qi-accent-hover);
    text-decoration-color: currentColor;
  }

  /* A single article --------------------------------------------------------- */
  .article-header {
    margin-block-end: var(--qi-space-6);
    padding-block-end: var(--qi-space-3);
    border-block-end: var(--qi-rule) solid var(--qi-text);
  }

  /* A titled article shows its title here. An untitled one is headed by its date,
     which this design already treats as the anchor. Either way the h1 is small
     and quiet, because the page's real subject is the text below it. */
  .article-title {
    font-family: var(--qi-font-mono);
    font-size: var(--qi-text-label);
    font-weight: var(--qi-weight-medium);
    letter-spacing: 0.04em;
  }

  .article-title a {
    color: var(--qi-text-subtle);
    text-decoration: none;
  }

  .article-title a:hover {
    color: var(--qi-accent-hover);
    text-decoration: underline;
    text-underline-offset: 0.24em;
  }

  .article-body {
    color: var(--qi-text);
    font-family: var(--qi-font-serif);
    font-size: var(--qi-text-lg);
    line-height: var(--qi-leading-prose);
  }

  .article-body > * + * {
    margin-block-start: var(--qi-prose-space);
  }

  .article-body a {
    text-decoration-thickness: 0.06em;
  }

  /* Footer: the one place outbound identity links appear ------------------- */
  .site-footer {
    padding-block: var(--qi-space-8);
    border-block-start: var(--qi-hairline) solid var(--qi-border);
    color: var(--qi-text-muted);
    font-size: var(--qi-text-sm);
  }

  /* These sit on every page, generated from shared/identity.json, so a link is
     never written twice and never exists on one page but not another. Mastodon
     reads rel=me off the home page, which is why they are rel=me rather than a
     bare list of links. */
  .rel-me-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--qi-space-1) var(--qi-space-5);
    align-items: center;
  }

  .rel-me-list a {
    display: inline-flex;
    min-height: var(--qi-target-min);
    align-items: center;
    font-weight: var(--qi-weight-medium);
  }
}
