/* ==========================================================================
   bento-grid-theme / grid layer
   --------------------------------------------------------------------------
   The choreography. A container, five span utilities, the reflow from a
   four-column desktop mosaic to a one-column phone stack, and three named
   arrangements you can paste.

   This is the file tokens.css cannot be. A gap and a radius are values; a
   mosaic that collapses without leaving holes in it is a set of rules about
   how those values get placed, and rules do not fit in custom properties.

   Every value here is a var() reference to tokens.css, with two exceptions,
   both structural rather than visual:

     1. The two breakpoints, 640px and 1024px. A media query cannot read a
        custom property, so these are literals and there is no way around it.
        Checked rather than assumed: a rule inside
        @media (min-width: var(--x)) never applies, at any value of --x.
     2. The span integers. These are written out, and the honest reason is not
        the one an earlier version of this comment gave. It said a token would
        have to go through calc() in a context where engines disagree. That was
        never measured, and when it was, it turned out to be false:
        span calc(1 + 1), span min(2, 4) and span var(--n) all resolve
        correctly and produce exactly the width of span 2.

        They stay written out because a token would not buy anything. The
        column count changes at each breakpoint, so the utilities have to be
        redefined per breakpoint whatever the span is written as, and a
        variable read inside those blocks would need a different value in each
        one. That is the same edit in a less obvious form.

   Requires tokens.css. components.css is independent of this file and this
   file is independent of components.css: the grid places compartments, the
   components dress them. Load them in whichever order suits you.

     <link rel="stylesheet" href="tokens/tokens.css" />
     <link rel="stylesheet" href="components/components.css" />
     <link rel="stylesheet" href="components/grid.css" />

   Naming: the span classes read width by height in cells. bn-cell-2x1 is two
   columns wide and one row tall. They do not imply the .bn-cell surface class
   from components.css, and they are scoped to direct children of .bn-grid, so
   a bare <figure> can take a span without taking any dressing.
   ========================================================================== */

/* ==========================================================================
   THE CONTAINER
   ========================================================================== */

/* The phone case is the base, so no span utility is declared here at all.
   That is deliberate rather than lazy. In a one-column grid a leftover
   `grid-column: span 2` does not collapse to one column; it makes the grid
   generate an implicit second column.

   What that costs is quieter than an earlier version of this comment claimed,
   and worth stating exactly, because the vague version sends people hunting
   the wrong symptom. Measured at 390px with a 14px gap: a one-column grid
   holding one spanning child computes its tracks as `376px 0px` rather than
   `390px`. The phantom track is zero wide and still takes a gap, so every cell
   that is not spanning loses 14px and stops meeting the container's right
   edge, while the spanning cell still reaches it. Nothing overflows and the
   page does not scroll sideways. The cells simply stop agreeing on where the
   page ends, which is the kind of fault that gets blamed on padding for an
   hour.

   Declaring the spans only inside min-width queries means there is nothing to
   unset, so that bug has no way in.

   Row height goes to auto here for the same class of reason. A stat cell
   pinned to a 176px track at four columns is correctly proportioned; the same
   cell full-width on a phone is a short line of text stranded in a tall empty
   box. At one column the content sets the height. */
.bn-grid {
  display: grid;
  grid-template-columns: repeat(var(--bn-cols-sm), minmax(0, 1fr));
  grid-auto-rows: auto;
  gap: var(--bn-gap-sm);
}

/* A grid item whose content is wider than its track (a code block, a long
   unbroken string) will otherwise push that track past 1fr and take the rest
   of the row with it. minmax(0, 1fr) above handles the track; this handles the
   item sitting in it. */
.bn-grid > * {
  min-width: 0;
}

/* Auto-placement leaves a hole when a wide cell does not fit in what is left
   of the current row: the cursor moves down and the tail of the old row stays
   empty. Dense flow backfills those holes.

   The cost is real, which is why this is opt-in rather than the default.
   Dense placement changes visual order without changing DOM order, so a
   sighted mouse user reads the cells in one sequence and a keyboard or screen
   reader user reads them in another. Use it for a gallery whose cells have no
   narrative order. Do not use it where cell three is a consequence of cell
   two. */
.bn-grid-dense {
  grid-auto-flow: dense;
}

/* ==========================================================================
   ARRANGEMENTS
   --------------------------------------------------------------------------
   Three compositions known to reflow without holes, given the cell count each
   one names. Put the arrangement class on the container alongside .bn-grid and
   the cells need no span classes of their own:

     <div class="bn-grid bn-arr-stats-board"> ... seven cells ... </div>

   Reading the ledgers: each line is one row and the numbers are the widths of
   the cells in it, by child index. A row is whole when its numbers sum to the
   column count. Every row in every ledger below sums, at both breakpoints,
   which is what "no orphan cells" means in practice.

   Add a cell beyond the count an arrangement names and it lands as a plain
   1x1 at the end. Usually fine at four columns; usually a half-empty last row
   at two. Check the tablet width when you do it.

   The arrangements sit above the span utilities on purpose. An arrangement
   rule and a `.bn-grid > .bn-cell-*` rule have identical specificity, so
   source order decides it, and this order is what lets an explicit class on
   one cell override the arrangement around it. Move this block below the
   utilities and that escape hatch stops working.

   All three are declared once, inside the 640px query, and are correct at
   1024px too without being restated. `span 2` means two columns at either
   width; what changes underneath is how many columns a row has, which is the
   whole trick.
   ========================================================================== */

/* --------------------------------------------------------------------------
   FEATURE WALL, six cells.
   A held hero with five supporting claims around it. The arrangement for a
   product's what-it-does section.

     four columns          two columns
     [ 1 1 2 2 ]           [ 1 1 ]
     [ 1 1 3 4 ]           [ 1 1 ]
     [ 5 5 6 6 ]           [ 2 2 ]
                           [ 3 4 ]
                           [ 5 5 ]
                           [ 6 6 ]
   -------------------------------------------------------------------------- */
@media (min-width: 640px) {
  .bn-arr-feature-wall > :nth-child(1) {
    grid-column: span 2;
    grid-row: span 2;
  }

  .bn-arr-feature-wall > :nth-child(2),
  .bn-arr-feature-wall > :nth-child(5),
  .bn-arr-feature-wall > :nth-child(6) {
    grid-column: span 2;
  }
}

/* --------------------------------------------------------------------------
   STATS BOARD, seven cells.
   One headline number and six readings. Cell one is the number the page is
   about; the other six are the evidence it is not a fluke.

     four columns          two columns
     [ 1 1 2 3 ]           [ 1 1 ]
     [ 4 5 6 7 ]           [ 2 3 ]
                           [ 4 5 ]
                           [ 6 7 ]
   -------------------------------------------------------------------------- */
@media (min-width: 640px) {
  .bn-arr-stats-board > :nth-child(1) {
    grid-column: span 2;
  }
}

/* --------------------------------------------------------------------------
   PORTFOLIO MOSAIC, six cells.
   Mixed heights, which is what stops a gallery reading as a contact sheet.
   Two of the six are tall, and they are the two the eye lands on.

     four columns          two columns
     [ 1 1 2 3 ]           [ 1 1 ]
     [ 1 1 2 4 ]           [ 1 1 ]
     [ 5 5 6 6 ]           [ 2 3 ]
                           [ 2 4 ]
                           [ 5 5 ]
                           [ 6 6 ]
   -------------------------------------------------------------------------- */
@media (min-width: 640px) {
  .bn-arr-portfolio-mosaic > :nth-child(1) {
    grid-column: span 2;
    grid-row: span 2;
  }

  .bn-arr-portfolio-mosaic > :nth-child(2) {
    grid-row: span 2;
  }

  .bn-arr-portfolio-mosaic > :nth-child(5),
  .bn-arr-portfolio-mosaic > :nth-child(6) {
    grid-column: span 2;
  }
}

/* ==========================================================================
   SPAN UTILITIES, two columns from 640px
   --------------------------------------------------------------------------
   The intermediate step, and the one that does the work. Going straight from
   four columns to one throws the tablet away; going to two keeps the
   composition legible as a composition on the device a bento layout is
   checked on last.

   Each utility states both axes even where one of them is the default. That
   is what makes a span class a complete override of an arrangement rather
   than a partial one: put bn-cell-1x1 on the hero of a feature wall and it
   becomes a 1x1, rather than a one-row cell that is still two columns wide.
   ========================================================================== */
@media (min-width: 640px) {
  .bn-grid {
    grid-template-columns: repeat(var(--bn-cols-md), minmax(0, 1fr));
    gap: var(--bn-gap);

    /* minmax rather than a flat height. A flat grid-auto-rows gives every row
       exactly one track height, and a cell whose content needs more spills out
       past its own rounded corner, which is the most common way a bento
       layout breaks in the wild. minmax sets a floor and lets the row grow.
       Cells that fit still line up, because they all take the floor. */
    grid-auto-rows: minmax(var(--bn-row-md), auto);
  }

  /* Every width above one collapses to the full two columns here. There is no
     useful three-quarters cell at two columns: a cell is either half the row
     or all of it. */
  .bn-grid > .bn-cell-1x1 {
    grid-column: span 1;
    grid-row: span 1;
  }

  .bn-grid > .bn-cell-2x1 {
    grid-column: span 2;
    grid-row: span 1;
  }

  .bn-grid > .bn-cell-1x2 {
    grid-column: span 1;
    grid-row: span 2;
  }

  .bn-grid > .bn-cell-2x2 {
    grid-column: span 2;
    grid-row: span 2;
  }

  .bn-grid > .bn-cell-full {
    grid-column: 1 / -1;
    grid-row: span 1;
  }
}

/* ==========================================================================
   SPAN UTILITIES, four columns from 1024px
   The mosaic.
   ========================================================================== */
@media (min-width: 1024px) {
  .bn-grid {
    grid-template-columns: repeat(var(--bn-cols), minmax(0, 1fr));
    grid-auto-rows: minmax(var(--bn-row), auto);
  }

  .bn-grid > .bn-cell-1x1 {
    grid-column: span 1;
    grid-row: span 1;
  }

  .bn-grid > .bn-cell-2x1 {
    grid-column: span 2;
    grid-row: span 1;
  }

  .bn-grid > .bn-cell-1x2 {
    grid-column: span 1;
    grid-row: span 2;
  }

  .bn-grid > .bn-cell-2x2 {
    grid-column: span 2;
    grid-row: span 2;
  }

  .bn-grid > .bn-cell-full {
    grid-column: 1 / -1;
    grid-row: span 1;
  }
}

/* ==========================================================================
   AUTHORING THE WIDTHS YOURSELF
   --------------------------------------------------------------------------
   If you are not using an arrangement, one rule keeps the reflow clean:

     between any two full-width cells, the widths of the cells in between have
     to sum to a whole number of rows at every breakpoint.

   At four columns that means runs summing to four: 2+2, 2+1+1, 1+1+1+1. At
   two columns every width of two or more has already collapsed to a full row,
   so what is left has to pair: 1+1. A run of three 1x1 cells is whole at four
   columns and orphaned at two, and it is the most common way a mosaic that
   looked finished on a laptop breaks on a tablet.

   Heights need no such rule. Auto-placement steps forward past an occupied
   cell, so a 1x2 beside a 1x1 gets its second row filled by whatever comes
   after it rather than leaving a gap underneath.
   ========================================================================== */
