/* The frame around the content of every page (T30.2).
 *
 * What a visitor recognises from one page to the next: the width of the column, the
 * heading they read first, the header they came in through and the footer that says whose
 * data this is. It is written once here because a frame repeated in forty-six templates
 * is forty-six frames, and this milestone exists because they had drifted.
 *
 * Two of the rules below are repairs of defects the contact sheet of T30.1 measured on
 * the live address: the skip link drawn on top of the brand on every page, and a header
 * that took the whole first screen of a phone. Both are marked where they are fixed.
 */

/* The footer belongs at the bottom of the window on a short page -- the one that does not
 * exist, the one that broke -- rather than halfway up it. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

body > main.container {
  flex: 1 0 auto;
  max-width: var(--hc-page-width);
  padding-block: 1.5rem 4rem;
}

/* The measure: a line of prose stops where it stops being comfortable to read, rather
 * than at the edge of whatever window it is in. The column of the page itself stays wide
 * -- cards and tables want the room -- so this is set on the running text alone (the
 * narrow column of the `calm` direction, kept in the chosen one; `state/DECISIONS.md`). */
body > main p,
body > main hgroup > p,
body > main li {
  max-width: 42rem;
}

h1,
h2,
h3 {
  font-family: var(--hc-serif-family);
  letter-spacing: -0.01em;
}

/* The one heading that has to fit both a phone held in one hand and a desktop window.
 *
 * The phone end of the range is what it is because of Russian: at Pico's own 2rem the
 * word "конфиденциальности" is 420 px of bold serif on a 390 px screen, so `overflow-wrap:
 * break-word` does what it is for and splits it mid-syllable -- in the first heading of
 * the privacy policy, which is the page a stranger opens to decide whether to trust this
 * with their photographs. Measured by the loop of T30.3 and held by it (`test_shots.py`
 * refuses a heading whose word is drawn on two lines). The desktop end is unchanged, and
 * between the two the size follows the window rather than jumping at a breakpoint. */
h1 {
  font-size: clamp(1.35rem, 0.65rem + 3.2vw, 2.8rem);
  line-height: 1.15;
}

h2 {
  font-size: 1.6rem;
}

article {
  padding: 1.75rem;
}

article h2 {
  font-size: 1.3rem;
  margin-bottom: 0.5rem;
}

/* --- The first screen of the storefront ------------------------------------------------
 *
 * The family album: the heading beside three prints, tilted the way they land on a table
 * (the pictures are T30.4's). It was the `hearth` candidate's own until T30.5, when the
 * direction that won stopped being a candidate and `/` started wearing it -- so the rules
 * live here, in the frame every page is drawn with, rather than in a stylesheet linked by
 * one address. One column under a phone, two beside each other above it.
 */
.hero-hearth {
  display: grid;
  gap: 2rem;
  align-items: center;
  padding-block: 3rem 2.5rem;
}

.hero-hearth p {
  color: var(--pico-muted-color);
}

.hero-hearth__frames {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-start;
}

.hero-hearth__frame {
  display: block;
  width: 6.5rem;
  height: 7.5rem;
  /* The print is drawn at the frame's own proportions, so this crops nothing today; it is
   * here so that a picture redrawn at another shape is cropped rather than squashed. */
  object-fit: cover;
  border: 1px solid var(--pico-card-border-color);
  border-radius: 0.35rem;
  background-color: var(--hc-paper);
  box-shadow: var(--pico-card-box-shadow);
}

.hero-hearth__frame:nth-child(1) {
  transform: rotate(-4deg);
}

.hero-hearth__frame:nth-child(2) {
  transform: rotate(1.5deg);
}

.hero-hearth__frame:nth-child(3) {
  transform: rotate(5deg);
}

@media (min-width: 768px) {
  .hero-hearth {
    grid-template-columns: 3fr 2fr;
    gap: 3rem;
  }

  .hero-hearth__frames {
    justify-content: flex-end;
  }
}

/* --- The cards of the storefront --------------------------------------------------------
 *
 * The third defect of the contact sheet of T30.1: the four "Learn more" buttons stood at
 * four different heights, each one directly under a tagline of its own length, so a row of
 * cards read as four unrelated boxes. The card is a column now and the button is pushed to
 * the foot of it, which is the one line of the card that is the same on all four.
 */
main .grid > article {
  display: flex;
  flex-direction: column;
}

main .grid > article > a[role="button"] {
  margin-top: auto;
  align-self: flex-start;
}

/* What the application starts at, on its card and at the top of its own page (T30.5).
 * Quiet: it is there to be found by somebody comparing four of them, not to be the loudest
 * thing on a card that is selling what the application is for. */
.from-price {
  margin-bottom: 1rem;
  color: var(--pico-muted-color);
  font-size: 0.95rem;
}

/* --- What comes with every plan ---------------------------------------------------------
 *
 * Three promises, read as a row above the fold of a desktop and as a list on a phone
 * (T30.5). A list rather than three cards: they are sentences, and a card around each one
 * would make them look like three more things on sale.
 */
.promises {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--pico-muted-border-color);
}

.promises__list {
  display: grid;
  gap: 1rem;
  padding-left: 0;
  list-style: none;
}

/* The bullet is taken off the item and not off the list: Pico writes `list-style: square`
 * on `ul li`, which a rule on the list itself does not out-specify -- measured on the
 * shots, where three square markers stood outside the rule beside them. */
.promises__item {
  padding-left: 1rem;
  border-left: 3px solid var(--pico-primary);
  list-style: none;
}

@media (min-width: 768px) {
  .promises__list {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
  }
}

/* --- The picture of a product ---------------------------------------------------------
 *
 * On the storefront's cards and at the top of the product's own page (T30.4). Sized in
 * `rem` rather than left at the intrinsic width of the file, so that the four cards of the
 * storefront carry four pictures of one size whatever any one of them was drawn at; the
 * `width`/`height` attributes on the tag itself are what keeps the text below from jumping
 * as each one arrives.
 */
.product-art {
  display: block;
  width: 100%;
  max-width: 8.5rem;
  height: auto;
  margin-bottom: 0.75rem;
}

.product-art--page {
  margin-bottom: 1.25rem;
}

/* --- The way past the header, for whoever arrives on a keyboard --------------------
 *
 * Measured on the live address (T30.1): with no styles at all this link is drawn above
 * the brand on every page, so the first thing anybody sees of the product is an
 * instruction meant for somebody who cannot see it. `display: none` would take it away
 * from the keyboard it exists for, so it waits off the top of the page instead.
 */
.skip-link {
  position: absolute;
  top: -4rem;
  left: 0.75rem;
  z-index: 10;
  padding: 0.6rem 1rem;
  border-radius: var(--pico-border-radius);
  background-color: var(--pico-primary-background);
  color: var(--pico-primary-inverse);
  text-decoration: none;
}

.skip-link:focus {
  top: 0.75rem;
}

/* --- Header ------------------------------------------------------------------------
 *
 * The second defect of the contact sheet: on a phone the two lists below stacked into
 * full-width rows and the storefront started below the fold. They wrap now, and the
 * controls inside them keep their own width (`forms.css`).
 *
 * That left it at three rows on a phone -- brand, guest door, language switcher, each on
 * one of its own, about 150 px before the product said anything -- and what took the
 * third row was the switcher, which is a setting rather than a way in. It is in the
 * footer since T30.7, and what is left here is the name of the product and the doors: one
 * row for a stranger, and never more than two for a customer whose account pages are
 * named in it as well.
 */
.site-header {
  padding-block: 0.75rem;
  border-bottom: 1px solid var(--pico-muted-border-color);
}

.site-header nav {
  flex-wrap: wrap;
  gap: 0 1rem;
}

.site-header nav ul {
  /* The ways in stay on one line and move down together (T36.1): a wrapping list broke
   * into a row each, and the header of a phone measured 235 px against a ceiling of 160
   * (`tests/design/test_shots.py`). Wrapping is the job of the nav above, which puts the
   * whole list under the brand when it no longer fits beside it. */
  flex-wrap: nowrap;
  align-items: center;
  gap: 0 0.75rem;
}

/* And the room they take is their own words, not the frame's default padding: a phone is
 * 390 px wide, the brand and the two ways in beside it are 305 px of text, and pico's own
 * padding on every item of a nav was what pushed the row over the edge and the header
 * over the ceiling. Vertical padding stays -- it is what makes a link on a phone big
 * enough to press. */
.site-header nav li {
  padding-inline: 0;
}

.site-header__brand {
  font-family: var(--hc-serif-family);
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--pico-h1-color);
  text-decoration: none;
}

/* --- What an application is doing ------------------------------------------------------
 *
 * The first line of a card, read before the three facts under it (T30.6). The tone is
 * decided in code (`app/dashboard/cards.py`) and is the only thing about the status the
 * markup carries; here it is three ways of drawing one line, quiet enough that the one
 * which means "something is wanted of you" is the only one anybody notices.
 */
.app-state {
  display: inline-block;
  margin-bottom: 0.75rem;
  padding: 0.2rem 0.7rem;
  border: 1px solid var(--pico-muted-border-color);
  border-radius: 2rem;
  background-color: var(--hc-paper);
  font-size: 0.9rem;
}

.app-state--working {
  border-color: var(--pico-primary-underline);
  color: var(--pico-primary);
}

/* Something is happening to it and nobody has to do anything about that. */
.app-state--busy {
  color: var(--pico-muted-color);
}

.app-state--attention {
  border-color: var(--hc-warning-border);
  background-color: var(--hc-warning-background);
}

/* --- A list with nothing in it ---------------------------------------------------------
 *
 * One screen for all five of them (`templates/partials/nothing_here.html`). Drawn as a
 * card that is deliberately not filled in: the border says the thing that would have been
 * here has a place, which is the difference between "you have nothing yet" and a page that
 * failed to draw.
 */
.nothing-here {
  border: 1px dashed var(--pico-muted-border-color);
  background-color: transparent;
  box-shadow: none;
  text-align: center;
}

.nothing-here p {
  max-width: 32rem;
  margin-inline: auto;
  color: var(--pico-muted-color);
}

.nothing-here a[role="button"] {
  width: auto;
}

/* --- A refusal ------------------------------------------------------------------------
 *
 * Why something did not happen, on the three pages that say so (T30.6). The warning colour
 * of the frame and not the invalid-field red: nothing here is broken and nobody typed
 * anything wrong -- an application is busy, a tariff is the largest one, a screen was left
 * open too long.
 */
.refusal {
  border-left: 4px solid var(--hc-warning-border);
  background-color: var(--hc-warning-background);
}

.refusal p:last-child {
  margin-bottom: 0;
}

/* --- What the flow says back -------------------------------------------------------- */
.messages {
  margin-bottom: 1.5rem;
  padding-left: 0;
  list-style: none;
}

.messages li {
  margin-bottom: 0.5rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--pico-card-border-color);
  border-left: 4px solid var(--pico-primary);
  border-radius: var(--pico-border-radius);
  background-color: var(--hc-paper);
}

.messages li.error,
.messages li.warning {
  border-left-color: var(--pico-form-element-invalid-border-color);
  background-color: var(--hc-warning-background);
}

/* --- Footer -------------------------------------------------------------------------- */
.site-footer {
  padding-block: 1.5rem 2.5rem;
  border-top: 1px solid var(--pico-muted-border-color);
  color: var(--pico-muted-color);
  font-size: 0.9rem;
}

.site-footer nav ul {
  flex-wrap: wrap;
  padding-left: 0;
}

/* Wrapped onto a phone these become a column, and Pico's spacing for a row of links
 * reads there as a gap between paragraphs. */
.site-footer nav li {
  padding-block: 0.15rem;
}

.site-footer a {
  color: var(--pico-muted-color);
}

/* The language, under the legal links rather than in the row with them: it is a control,
 * and a control standing in a line of links reads as a link that behaves oddly. */
.site-footer .language-switcher {
  margin-top: 0.75rem;
}

/* --- The three cookies, said once ----------------------------------------------------
 *
 * A strip at the top of the page, in its flow (T36.2). It has been in three places now,
 * and each move was a measurement: written after the footer it was never read (T30.7);
 * pinned across the foot of the window it was read and stood *in front of the product* --
 * on the storefront of the live stand the bar lay over the "Buy" button of every card,
 * which is one of the four things the owner meant by "nothing works". A fixed strip covers
 * whatever the first screen happens to end with, and no ceiling on its height can see
 * that: the bar was within its height and still on top of a button.
 *
 * So it takes its own room rather than borrowing the product's: the first band of the
 * document, above the header, where a visitor reads it first and presses it away, and
 * where nothing of the page is ever behind it. What that costs is a strip of the first
 * screen -- which is what T30.7 refused to spend, on a sentence four times this one's
 * length. The measure that holds it is the seventh property of `test_shots.py`
 * (`covered`), and what keeps the strip a strip is the ceiling in the same file.
 */
.cookie-notice {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.75rem;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 1rem;
  border-bottom: 1px solid var(--pico-card-border-color);
  background-color: var(--hc-paper);
  font-size: 0.85rem;
  line-height: 1.4;
}

.cookie-notice form {
  margin-bottom: 0;
}

/* Small print and a small button, now that the strip is room the product gives up rather
 * than window it borrows: on a phone in Russian the sentence wraps onto four lines, and at
 * Pico's own sizes those four lines and the button under them measured 196 px of an 844 px
 * screen -- a quarter of the first screen spent before the product says what it is. The
 * same words at these sizes measure 159 px there, and 71 on a desktop. */
.cookie-notice button {
  width: auto;
  padding: 0.3rem 0.9rem;
  font-size: inherit;
}

/* The sentence takes the room that is left and the button stands at the end of it, rather
 * than the sentence taking the whole width and pushing the button onto a line of its own:
 * measured on the live address, where that cost the bar a third row on a desktop. Under
 * the basis below there is no room for both, and the phone gets the stacked one. */
.cookie-notice small {
  flex: 1 1 24rem;
  /* The size is set on the bar, once: `small` inside it would take Pico's 0.875 of that
   * as well, and a sentence at 12 px is a notice given in a way nobody reads either. */
  font-size: inherit;
}

/* --- A phone, which is not a narrow desktop -------------------------------------------
 *
 * Pico keeps 46 px of margin on each side of a 390 px screen and this file puts another
 * 28 inside every card, so a heading is written into 288 px of the 390 there are -- and a
 * Russian one does not fit on one line of it (measured, T30.3). Both are narrowed here,
 * and the three containers together rather than the content alone: the brand, the text
 * and the footer links line up on one left edge, and a page where they do not is a page
 * drawn by two stylesheets.
 *
 * Last in the file, not beside the rules it refines: these carry the same weight as those,
 * so what decides the argument is which one is read second.
 */
@media (width < 576px) {
  body > main.container,
  .site-header,
  .site-footer {
    padding-inline: 1rem;
  }

  article {
    padding: 1rem;
  }

  /* And the brand gives up what the ways in need (T36.1): with a sign-in link beside the
   * demo's button, the row measured 368 px of the 358 a phone has and the header broke
   * into two -- 173 px against a ceiling of 160. Taken off the name of the product rather
   * than off the links, because the name is read once and the links are what the visitor
   * came to press. */
  .site-header__brand {
    font-size: 1.05rem;
  }

  .site-header nav {
    gap: 0 0.5rem;
  }
}
