@layer components {
  /* A screen that is the product surface rather than content standing in a
   * gutter on a page.
   *
   * Worn by the calendar, the properties list and the bookings list. The
   * calendar had grown its own copy of all of this before the other two arrived,
   * which is the moment COMPONENTS.md says to fold: the padding below is a clamp
   * somebody chose, the border under the toolbar is a decision, and separate
   * copies of a decision are things that drift. Every value in
   * .popover__surface is a plain var() and those are still not folded, for the
   * same reason in reverse.
   *
   * The inbox is flush too and deliberately does not wear this. It is a grid of
   * three panes rather than a column with a toolbar over it, and its header
   * belongs to one of those panes rather than to the screen — so the only thing
   * it would take from here is the canvas and the floor. .inbox still states
   * both itself, which is the one duplication this file knows about and is not
   * pretending otherwise.
   *
   * It pairs with .main--flush, which supplies the height and takes the page's
   * gutter away; this is what stands in that space. What a screen puts inside
   * is its own: the calendar is a grid, the properties list is a table, and
   * neither is this component's business.
   */
  .screen {
    /* A floor, so a short window scrolls the page rather than squeezing the
       screen into a sliver. Both the calendar and the inbox arrived at the same
       number independently, which is most of why it is here now. */
    --screen-min-height: 24rem;

    display: flex;
    flex-direction: column;
    flex: 1;
    min-block-size: var(--screen-min-height);
    background: var(--color-canvas);
  }

  /* What this screen is, and what there is to do about it. A flush screen has
     no gutter to stand a .page-header in, so the title comes inside — which is
     also what makes this bar the top edge anything sticky underneath sticks to.

     The h1 is reset here rather than at each call site: three screens setting
     `margin: 0` on their own title is the drift this component exists to
     prevent. */
  .screen__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space);
    padding: var(--space) var(--screen-gutter);
    border-block-end: var(--border);

    h1 {
      margin: 0;
    }
  }

  /* The start of the toolbar: what this screen is, and how it is narrowed at the
     top level. A tab strip belongs here rather than in __filters when it chooses
     between two lists rather than narrowing one — the bookings screen's Today
     and Upcoming are two windows, and putting them among the filters would read
     as a fifth thing to combine with the other four. */
  .screen__heading {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-and-half);
  }

  /* What there is to do to this screen, at the end of the toolbar — the same
     place .page-header__actions puts it, so the primary action of every screen
     in the app is where the last one was. */
  .screen__actions {
    display: flex;
    align-items: center;
    gap: var(--space-half);
  }

  /* The line under the title: what this screen is showing, counted.
   *
   * Every declaration .page-header__meta has, because it is the same sentence in
   * the place a flush screen keeps it — and it had drifted within one branch of
   * being written. That one is a *row* on purpose ("a subtitle, a count, a status
   * badge … usually two or three things and not a sentence"), and this had
   * dropped the row and added a size, so the first flush screen to put a badge
   * beside its count would have got a working layout on a gutter page and a
   * broken one here.
   *
   * Still two blocks rather than one, and that is the next fold rather than this
   * one: .screen__toolbar is .page-header plus a border and minus a margin, which
   * is a modifier waiting to be written. It wants doing when a third screen wants
   * a header, not on the way past. */
  .screen__meta {
    display: flex;
    align-items: center;
    gap: var(--space-half);
    margin: var(--space-quarter) 0 0;
    color: var(--color-ink-soft);
    font-size: var(--text-normal);
  }

  /* The strip that narrows what is below — a filter bar, usually.
   *
   * Outside __scroll on purpose, and this is the same rule .inbox__filters
   * follows: a scroll container is a clipping ancestor, so a combobox opened
   * from inside the scroller would have its list cut off at the bottom of the
   * list it is filtering.
   *
   * No rule under it. What separates it from the content is the card's own top
   * edge, and two lines with the gutter's worth of nothing between them read as
   * a strip that failed to fill in. Where there is no card — a blank slate — the
   * rule was worse: a line across the screen with an empty field under it, which
   * reads as a table whose rows did not load. */
  .screen__filters {
    padding: var(--space-three-quarters) var(--screen-gutter);
  }

  /* The only thing on the screen that scrolls, which is the whole point of
     .main--flush: one scrollbar, belonging to the thing the screen is for,
     rather than a bounded region inside a page that scrolls as well. */
  .screen__scroll {
    /* Positioned, and that is a containment rule rather than a placement one: it
       clips, so it should also *contain* what it clips. An absolutely positioned
       box is only clipped by ancestors in its containing-block chain, and with
       nothing positioned above it that chain starts at the page — so a
       .visually-hidden span inside a cell two thousand pixels along the grid sat
       two thousand pixels along the *document*, gave the page a horizontal
       scrollbar it had no business having, and the sticky sidebar then slid over
       the grid the moment anybody used it. One label did it. Every screen with a
       scroller has hidden labels in it, so this belongs here rather than on
       whichever component noticed. */
    position: relative;
    flex: 1;
    min-block-size: 0;
    overflow: auto;
    overscroll-behavior: contain;
  }

  /* A screen whose content is a card rather than the whole surface.
   *
   * The calendar is the grid and the inbox is the panes — both run to the edges
   * of the window, and __scroll above is what they use. A table is the other
   * shape: nine columns hard against both edges of the window read as a
   * spreadsheet somebody opened rather than as a list on a screen, and there is
   * no border to say where the rows stop.
   *
   * So the screen keeps the gutter and gives it back here. The card inside is
   * an ordinary .panel — one elevation decision, as everywhere else — and this
   * is only the room around it.
   */
  .screen__inset {
    display: flex;
    /* Top rather than stretch, which is the default and was wrong: a card
       holding five rows should be five rows tall. Stretched, every short list
       was a full-height box with a field of white under the last row, reading
       as rows that had failed to load. */
    align-items: flex-start;
    flex: 1;
    min-block-size: 0;
    padding: var(--screen-gutter);
    /* A step down at the top, because the strip above has already spent its own
       padding-bottom there and the two together would be half again the gutter
       the card has on its other three sides. */
    padding-block-start: var(--space);
  }

  /* The card, and the one scrollbar on the screen.
   *
   * Composes with .panel.panel--flush for the border and the corner; what is
   * here is the sizing and the scrolling, which belong to the screen rather
   * than to the panel — a panel does not know whether it is one section of a
   * page or the whole of a screen.
   *
   * Both, together, are what makes a sticky header and a pinned first column
   * work: they stick against this box, so they stop at the card's own edges
   * instead of sliding out from under its rounded corners.
   *
   * The child selector is deliberate. .panel--flush says overflow: hidden and
   * both are one class deep, so a bare .screen__card would win or lose on which
   * stylesheet the manifest happened to load second. */
  .screen__inset > .screen__card {
    /* Along the inline axis it takes the width; along the block axis it takes
       its content, up to what is left of the screen — past that the ceiling
       holds and the card scrolls rather than pushing the window down. */
    flex: 1;
    max-block-size: 100%;
    overflow: auto;
    overscroll-behavior: contain;
  }

  /* Printed, a screen is what is on it: the strip that narrowed it has already
     done its work, and a scroller with `overflow: auto` prints only the part of
     itself that happened to be in view. */
  @media print {
    .screen__filters {
      display: none;
    }

    .screen__scroll,
    .screen__inset > .screen__card {
      overflow: visible;
      max-block-size: none;
    }
  }

  /* Nothing to show, standing where the content would have. Centred in what is
     left of the screen rather than at the top of it: a sentence about an empty
     list, pinned under a full-height header, reads as a row that failed to
     render. .inbox__blank-slate is the same decision inside a pane. */
  .screen__nothing {
    display: grid;
    place-items: center;
    flex: 1;
    min-block-size: 0;
    padding: var(--space-double) var(--screen-gutter);
  }
}
