/* =============================================================================
   Gilead Press, base

   Reset, element defaults, the type scale applied, the focus ring, and the
   handful of utilities that earn their place. Nothing here knows about a
   component.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The header is sticky, so an in-page anchor must not land under it.

     THIS IS scroll-padding ON THE SCROLLPORT, NOT scroll-margin ON THE
     TARGETS, and the two must never both be used for the same offset. They
     ADD: a page carrying 100px of scroll-padding and a panel carrying 112px of
     scroll-margin puts the heading 212px down, which looks like the jump
     overshot and is the kind of thing that gets "fixed" by tuning one of the
     two numbers until it happens to look right on one page.

     One offset, set here, sized to whichever header is sticky on the page. */
  scroll-padding-top: calc(var(--gp-header-h) + var(--gp-space-24));
}

/* The dashboard's topbar is 96px against the storefront masthead's 76, so the
   offset follows the shell rather than being one number that is wrong on one
   of them. :has on the root element, because the shell class sits on a div
   inside the body while the scrollport is <html>.

   IT CANNOT READ --gp-dash-topbar-height, AND THAT IS THE TRAP HERE. Those
   tokens are declared on .gp-dashboard, which is a DESCENDANT of this element.
   Custom properties inherit down the tree and never up, so on <html> that name
   resolves to nothing, the calc is invalid at computed-value time, and the
   whole declaration is dropped: every anchor on every dashboard page would
   land under the topbar, silently. The same mistake already cost this codebase
   a mobile drawer that rendered fully transparent.

   So it is composed from the ROOT spacing scale, which does reach here, and
   96 + 16 is the same 112px the dash tokens describe. If the topbar height
   changes, this line changes with it, and the comment on the token says so. */
html:has(.gp-dashboard) {
  scroll-padding-top: calc(var(--gp-space-96) + var(--gp-space-16));
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd,
ul, ol {
  margin: 0;
}

/* WRAPPED IN :where() SO IT CANNOT OUT-SPECIFY A COMPONENT, and that is not a
   refinement, it is a bug fix.

   role="list" is on these lists because removing the bullets also removes the
   list semantics in Safari with VoiceOver, so the role puts them back. The
   side effect is that the reset's selector is an ATTRIBUTE selector, (0,1,1),
   while every component that styles one of these lists is a single class,
   (0,1,0). The reset therefore beat the component, silently, on padding.

   Three real things were broken by it and none of them looked like a
   specificity problem from the outside:

     .footer-group__list   its bottom padding never applied, so the last link
                           in a footer group sat almost on the rule that was
                           supposed to separate it from the next group. This
                           is the footer spacing complaint.
     .sheet__sub           the inset on the mobile subject panel was dropped.
     .nav__menu            the desktop subject dropdown lost its padding.

   :where() has zero specificity, so the reset still applies to every list that
   wants it and loses to any component that says otherwise. Every other
   component rule here sets padding: 0 anyway, so nothing else moves. */
:where(ul[role='list'], ol[role='list']) {
  list-style: none;
  padding: 0;
}

body {
  min-height: 100vh;
  background: var(--gp-ground);
  color: var(--gp-ink);
  font-family: var(--gp-font-body);
  font-size: var(--gp-fs-body);
  line-height: var(--gp-lh-body);
  font-weight: var(--gp-fw-regular);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img,
picture,
svg,
video,
canvas {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

table {
  border-collapse: collapse;
  width: 100%;
}

hr {
  border: 0;
  border-top: 1px solid var(--gp-rule);
  margin: var(--gp-space-32) 0;
}

/* -----------------------------------------------------------------------------
   Typography

   Merriweather sets the voice, Source Sans 3 does the work. Headings are the
   display face; navigation, buttons, metadata, forms and body are the body
   face. That split is the brand, and it is also why the page and the book PDFs
   read as one object: the interiors already use this pairing.
   -------------------------------------------------------------------------- */

h1, h2, h3, h4 {
  font-family: var(--gp-font-display);
  font-weight: var(--gp-fw-bold);
  color: var(--gp-ink);
  text-wrap: balance;
}

h1 {
  font-size: var(--gp-fs-h1);
  line-height: var(--gp-lh-h1);
  letter-spacing: var(--gp-ls-h1);
}

h2 {
  font-size: var(--gp-fs-h2);
  line-height: var(--gp-lh-h2);
  letter-spacing: var(--gp-ls-h2);
}

h3 {
  font-size: var(--gp-fs-h3);
  line-height: var(--gp-lh-h3);
}

h4 {
  font-size: var(--gp-fs-h4);
  line-height: var(--gp-lh-h4);
}

/* The display size is for the home hero and nothing else. It is a size, not a
   level: it is applied to an h1, never used to make a div look like one. */
.t-display {
  font-size: var(--gp-fs-display);
  line-height: var(--gp-lh-display);
  letter-spacing: var(--gp-ls-display);
}

.t-lead {
  font-size: var(--gp-fs-lead);
  line-height: var(--gp-lh-lead);
  color: var(--gp-ink);
}

.t-small { font-size: var(--gp-fs-small); line-height: var(--gp-lh-small); }
.t-meta  { font-size: var(--gp-fs-meta);  line-height: var(--gp-lh-meta);
           color: var(--gp-ink-muted); }

.t-eyebrow {
  font-size: var(--gp-fs-eyebrow);
  line-height: var(--gp-lh-eyebrow);
  letter-spacing: var(--gp-ls-eyebrow);
  text-transform: uppercase;
  font-weight: var(--gp-fw-semi);
  color: var(--gp-accent);
}

.t-muted   { color: var(--gp-ink-muted); }
.t-display-face { font-family: var(--gp-font-display); }
.t-measure { max-width: var(--gp-measure-prose); }

p + p,
p + ul,
p + ol {
  margin-top: var(--gp-space-16);
}

/* -----------------------------------------------------------------------------
   Links

   Underlined by default in prose, because an underline is the only link
   affordance that survives a colour-blind reader and a bad screen. Chrome and
   card links opt out with .u-nolink.
   -------------------------------------------------------------------------- */

a {
  color: var(--gp-accent);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  transition: color var(--gp-dur-link) var(--gp-ease-out);
}

a:hover {
  color: var(--gp-accent-face);
  text-decoration-thickness: 2px;
}

.u-nolink,
.u-nolink:hover {
  text-decoration: none;
}

/* -----------------------------------------------------------------------------
   Focus

   The ring is two-tone and is defined here, once. No component overrides it.
   No single colour clears 3:1 against every ground and every button face at
   the same time, including an olive-ink face, which is exactly where a focus
   ring matters most.

   :focus-visible only, so a mouse click does not paint a ring, but the ring is
   never removed: outline:none with nothing after it makes the site unusable by
   keyboard.
   -------------------------------------------------------------------------- */

:focus {
  outline: none;
}

:focus-visible {
  outline: 2px solid var(--gp-focus-outer);
  outline-offset: 2px;
  box-shadow: 0 0 0 2px var(--gp-focus-inner);
  border-radius: var(--gp-radius-sm);
}

/* On the closing band the two tones swap, because the outer ring is Deep
   Forest and the band is Deep Forest. */
.band :focus-visible,
.sheet :focus-visible {
  outline-color: var(--gp-warm-ivory);
  box-shadow: 0 0 0 2px var(--gp-deep-forest);
}

/* -----------------------------------------------------------------------------
   Skip link. Visually hidden until focused, then a real, visible target.
   -------------------------------------------------------------------------- */

.skip-link {
  position: absolute;
  top: var(--gp-space-8);
  left: var(--gp-space-8);
  z-index: 999;
  padding: var(--gp-space-12) var(--gp-space-16);
  background: var(--gp-accent-face);
  color: var(--gp-on-accent);
  font-weight: var(--gp-fw-semi);
  border-radius: var(--gp-radius);
  text-decoration: none;
  transform: translateY(-200%);
}

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

/* -----------------------------------------------------------------------------
   Utilities. Deliberately few.
   -------------------------------------------------------------------------- */

.visually-hidden:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

[hidden] {
  display: none !important;
}

.u-clamp-1,
.u-clamp-2,
.u-clamp-3 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Centres inline content. Earned its place on the auth screens, where the
   card is centred and one control inside it was not. */
.u-center { text-align: center; }
/* text-align does not move flex children, so a flex container that is asked to
   centre must be told twice. */
.u-center.form-actions,
.u-center .form-actions { justify-content: center; }

.u-clamp-1 { -webkit-line-clamp: 1; line-clamp: 1; }
.u-clamp-2 { -webkit-line-clamp: 2; line-clamp: 2; }
.u-clamp-3 { -webkit-line-clamp: 3; line-clamp: 3; }

/* The icon sprite itself is never painted. */
.icon-sprite {
  display: none;
}

.icon {
  width: 1.25em;
  height: 1.25em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon--sm { width: 1em; height: 1em; }
.icon--lg { width: 1.75em; height: 1.75em; }

/* -----------------------------------------------------------------------------
   Scroll reveal

   The .js class is stamped on <html> by an inline script in the head, before
   first paint. The start state therefore only ever applies when the script
   that clears it is running: with JS off, or if reveal.js fails to load,
   content is simply visible rather than permanently hidden.

   Nothing above the fold carries .reveal.
   -------------------------------------------------------------------------- */

.js .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--gp-dur-reveal) var(--gp-ease-out),
              transform var(--gp-dur-reveal) var(--gp-ease-out);
}

.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* -----------------------------------------------------------------------------
   Reduced motion

   Honoured without exception. The reveal does not become a faster reveal, it
   becomes no reveal: the content is simply there.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .js .reveal {
    opacity: 1;
    transform: none;
  }
}

/* -----------------------------------------------------------------------------
   Print. A reader printing a receipt or a policy should get the document and
   not the furniture.
   -------------------------------------------------------------------------- */

@media print {
  /* The dashboard chrome drops here too, and it belongs in this list rather
     than as a .no-print class hand-applied per template. A receipt is the one
     screen somebody actually prints, and a rail down the left of a printed
     receipt is a column of wasted toner on a document a finance officer is
     going to file. */
  .site-header,
  .site-footer,
  .sheet,
  .scrim,
  .skip-link,
  .dash-rail,
  .dash-top,
  .no-print {
    display: none !important;
  }

  /* With the rail gone the shell is one column, and the content should use
     the page rather than keep a 248px hole where the rail was. */
  .dash {
    display: block !important;
  }

  .dash-main {
    padding: 0 !important;
  }

  body {
    background: #fff;
    color: #000;
    font-size: 12pt;
  }

  a[href^='http']::after {
    content: ' (' attr(href) ')';
    font-size: 10pt;
    color: #444;
  }
}
