/* ==========================================================================
   bento-grid-theme / components
   --------------------------------------------------------------------------
   Six components: cell, stat, badge, button, plot, nav.

   Every value here is a var() reference to tokens.css. There is not one color
   literal in this file, which is what makes retheming a matter of editing one
   file rather than auditing four.

   The class names follow the shadcn shape: one base class carrying the
   structure, one variant class carrying the intent (bn-cell + bn-cell-accent).

   This file is the surface half of the theme and components/grid.css is the
   layout half. They do not depend on each other. That separation is the whole
   argument the repo makes: bento is a layout archetype, so the surface under
   it is meant to be swapped. demo/reskin.html swaps it three ways without
   touching a single rule in grid.css.

   Requires tokens.css. Load it explicitly rather than letting this file pull
   it in, so the dependency is visible at the call site:

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

/* ==========================================================================
   CELL
   The compartment. Variants: bn-cell-tint-cool, bn-cell-tint-warm,
   bn-cell-tint-mute, bn-cell-accent, bn-cell-flush, bn-cell-link
   Parts:    bn-cell-eyebrow, bn-cell-head, bn-cell-title, bn-cell-body,
             bn-cell-foot
   ========================================================================== */

/* Flex column rather than block, because a cell in a fixed-floor grid track is
   usually taller than its content and something has to decide where the slack
   goes. Here it goes to whichever child claims it with margin-top: auto, which
   is how a stat's number sits at the foot of its compartment while its label
   stays at the head. */
.bn-cell {
  display: flex;
  flex-direction: column;
  gap: var(--bn-space-3);
  padding: var(--bn-cell-pad-sm);

  color: var(--bn-ink);
  background: var(--bn-surface);
  border: var(--bn-border-width) solid var(--bn-border-color);
  border-radius: var(--bn-radius-cell);
  box-shadow: var(--bn-shadow);
}

/* The one breakpoint literal outside grid.css, and it is the same 640px, on
   purpose. Cell padding and column count have to change together: a 24px
   inset that reads as generous in a quarter-width cell reads as wasteful in a
   full-width one on a phone. */
@media (min-width: 640px) {
  .bn-cell {
    padding: var(--bn-cell-pad);
  }
}

.bn-cell-tint-cool {
  background: var(--bn-tint-cool);
}

.bn-cell-tint-warm {
  background: var(--bn-tint-warm);
}

.bn-cell-tint-mute {
  background: var(--bn-tint-mute);
}

/* The accent cell rebinds the ink tokens for its own subtree rather than
   setting a color on each part. One cell per arrangement takes this; two and
   the grid has no focal point again. Rebinding rather than overriding is also
   what lets a plot, a badge and a hairline inside the cell come along without
   any of them knowing they are on dark ground. */
.bn-cell-accent {
  --bn-ink: var(--bn-accent-ink);
  --bn-ink-muted: var(--bn-accent-ink-muted);
  --bn-border-color: var(--bn-accent-rule);

  color: var(--bn-accent-ink);
  background: var(--bn-accent);
  border-color: var(--bn-accent-rule);
}

/* A cell holding artwork edge to edge. The padding goes and the overflow gets
   clipped, so the artwork takes the cell's corner radius rather than sitting
   square inside a rounded box. */
.bn-cell-flush {
  position: relative;
  padding: 0;
  overflow: hidden;
}

/* Artwork in a flush cell comes out of flow and pins to the cell's box.

   Left in flow, an SVG at height: 100% has no definite parent height to
   resolve against, so it falls back to its own aspect ratio: a 320x160
   drawing in a 530px wide cell asks for 265px of height and drags the whole
   grid row up with it, along with every other cell sharing that row. Pinning
   it inverts that, so the mosaic sizes the artwork rather than the artwork
   sizing the mosaic. */
.bn-cell-flush > .bn-plot {
  position: absolute;
  inset: 0;
}

.bn-cell-eyebrow {
  margin: 0;
  font-size: var(--bn-text-xs);
  font-weight: var(--bn-weight-medium);
  letter-spacing: var(--bn-tracking-wide);
  text-transform: uppercase;
  color: var(--bn-ink-muted);
}

.bn-cell-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--bn-space-3);
}

.bn-cell-title {
  margin: 0;
  font-size: var(--bn-text-h3);
  font-weight: var(--bn-weight-semibold);
  line-height: var(--bn-leading-snug);
  letter-spacing: var(--bn-tracking-tight);
  text-wrap: balance;
}

.bn-cell-body {
  margin: 0;
  font-size: var(--bn-text-sm);
  line-height: var(--bn-leading-body);
  color: var(--bn-ink-muted);
}

/* Takes the slack, so footers line up along the bottom edge of a row of cells
   whatever their titles did. */
.bn-cell-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--bn-space-2);
  margin-top: auto;
  padding-top: var(--bn-space-2);
}

/* A cell that is itself a link. The lift is the only motion in the theme. */
.bn-cell-link {
  text-decoration: none;
  transition:
    transform var(--bn-duration) var(--bn-ease),
    box-shadow var(--bn-duration) var(--bn-ease);
}

.bn-cell-link:hover {
  transform: translateY(calc(var(--bn-lift) * -1));
  box-shadow: var(--bn-shadow-lift);
}

/* The ring is offset outside the border so it traces the cell radius rather
   than cutting across it. */
.bn-cell-link:focus-visible,
.bn-focusable:focus-visible {
  outline: var(--bn-ring-width) solid var(--bn-ring);
  outline-offset: var(--bn-ring-offset);
}

/* ==========================================================================
   STAT
   The most common thing a bento cell holds: one number, its label, and one
   line saying why the number is what it is.
   Parts: bn-stat-label, bn-stat-value, bn-stat-unit, bn-stat-note
   ========================================================================== */
.bn-stat-label {
  margin: 0;
  font-size: var(--bn-text-xs);
  font-weight: var(--bn-weight-medium);
  letter-spacing: var(--bn-tracking-wide);
  text-transform: uppercase;
  color: var(--bn-ink-muted);
}

/* margin-top: auto is what puts the number at the foot of the compartment with
   the label at its head. In a grid of mixed-height cells that alignment is
   most of what makes the board read as one instrument rather than as six.

   Tabular figures because these numbers sit in a column and change on
   refresh, and proportional digits make a stack of them wobble. */
.bn-stat-value {
  margin: var(--bn-space-2) 0 0;
  margin-top: auto;
  font-size: var(--bn-text-stat);
  font-weight: var(--bn-weight-semibold);
  line-height: var(--bn-leading-tight);
  letter-spacing: var(--bn-tracking-tight);
  font-variant-numeric: tabular-nums;
  color: var(--bn-ink);
}

/* The unit rides at the size of body text so the figure keeps the weight. */
.bn-stat-unit {
  margin-left: 0.1em;
  font-size: var(--bn-text-lead);
  font-weight: var(--bn-weight-medium);
  color: var(--bn-ink-muted);
}

.bn-stat-note {
  margin: 0;
  font-size: var(--bn-text-sm);
  line-height: var(--bn-leading-snug);
  color: var(--bn-ink-muted);
}

/* ==========================================================================
   BADGE
   Variants: bn-badge-neutral, bn-badge-cool, bn-badge-warm
   ========================================================================== */

/* Ink on a pale tint, at every variant. This theme has no green-up and no
   red-down badge, and the omission is deliberate: a delta that is only a color
   is unreadable to a share of readers and illegible in a screenshot. The sign
   goes in the text, and the tint groups rather than judges. */
.bn-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--bn-space-1);
  padding: var(--bn-space-1) var(--bn-space-3);

  font-family: var(--bn-font-sans);
  font-size: var(--bn-text-xs);
  font-weight: var(--bn-weight-medium);
  line-height: var(--bn-leading-snug);
  letter-spacing: var(--bn-tracking-wide);

  color: var(--bn-ink);
  border: var(--bn-border-width) solid var(--bn-border-color);
  border-radius: var(--bn-radius-pill);
  white-space: nowrap;
}

.bn-badge-neutral {
  background: var(--bn-tint-mute);
}

.bn-badge-cool {
  background: var(--bn-tint-cool);
}

.bn-badge-warm {
  background: var(--bn-tint-warm);
}

/* Inside an accent cell the tints are still the light ones from the default
   register, so a badge there takes the cell's ground and its rule instead. */
.bn-cell-accent .bn-badge {
  color: var(--bn-accent-ink);
  background: transparent;
  border-color: var(--bn-accent-rule);
}

/* ==========================================================================
   BUTTON
   Variants: bn-btn-primary, bn-btn-default, bn-btn-ghost
   Sizes:    bn-btn-sm, (base)
   ========================================================================== */
.bn-btn {
  /* 44px minimum on both axes. Anything smaller fails on a real thumb. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--bn-space-2);
  min-height: 44px;
  padding: var(--bn-space-3) var(--bn-space-6);

  font-family: var(--bn-font-sans);
  font-size: var(--bn-text-sm);
  font-weight: var(--bn-weight-semibold);
  line-height: var(--bn-leading-snug);
  text-decoration: none;
  white-space: nowrap;

  border: var(--bn-border-width) solid transparent;
  border-radius: var(--bn-radius-tight);
  cursor: pointer;
  transition: background-color var(--bn-duration) var(--bn-ease);
}

.bn-btn:focus-visible {
  outline: var(--bn-ring-width) solid var(--bn-ring);
  outline-offset: var(--bn-ring-offset);
}

.bn-btn:disabled,
.bn-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

.bn-btn-primary {
  color: var(--bn-primary-ink);
  background: var(--bn-primary);
}

.bn-btn-default {
  color: var(--bn-ink);
  background: var(--bn-surface);
  border-color: var(--bn-border-color);
  box-shadow: var(--bn-shadow-sm);
}

.bn-btn-default:hover {
  background: var(--bn-surface-sunk);
}

.bn-btn-ghost {
  color: var(--bn-ink);
  background: transparent;
}

.bn-btn-ghost:hover {
  background: var(--bn-surface-sunk);
}

.bn-btn-sm {
  min-height: 44px; /* the visual box shrinks, the touch target does not */
  padding: var(--bn-space-2) var(--bn-space-4);
  font-size: var(--bn-text-sm);
}

/* On an accent cell the primary fill would be a second saturated colour on a
   surface that is already the loud one. The button borrows the cell's ink
   instead and states itself with a rule. */
.bn-cell-accent .bn-btn-default {
  color: var(--bn-accent-ink);
  background: transparent;
  border-color: var(--bn-accent-rule);
  box-shadow: none;
}

.bn-cell-accent .bn-btn-default:hover {
  background: var(--bn-accent-rule);
}

/* ==========================================================================
   PLOT
   Paint rules for inlined SVG artwork. The shapes live in assets/ and are
   meant to be inlined into your markup rather than loaded through <img>: an
   SVG inside an <img> is an isolated document that cannot read the page's
   custom properties, so it would have to carry its own color values and the
   single source of truth would be gone. Inlined, these rules reach it, and it
   follows a surface-register swap along with everything else.
   ========================================================================== */
.bn-plot {
  display: block;
  width: 100%;
  height: 100%;
  color: var(--bn-ink-muted);
}

/* The assets carry stroke="currentColor" so they stay legible as line art when
   opened on their own. Once these rules reach them, the shapes that are meant
   to be solid take a fill and drop that stroke, so a bar does not end up filled
   and outlined at once. */
.bn-plot .bn-art-grid {
  fill: none;
  stroke: var(--bn-border-color);
}

.bn-plot .bn-art-line {
  fill: none;
  stroke: var(--bn-primary);
}

.bn-plot .bn-art-area {
  fill: var(--bn-tint-cool);
  stroke: none;
}

.bn-plot .bn-art-bar {
  fill: var(--bn-primary);
  stroke: none;
}

.bn-plot .bn-art-bar-mute {
  fill: var(--bn-border-color);
  stroke: none;
}

.bn-plot .bn-art-mark {
  fill: var(--bn-primary);
  stroke: var(--bn-surface);
}

/* On the accent cell the primary is a mid blue sitting on a deep slate ground,
   which is where a plot would go quiet at exactly the moment it becomes the
   thing being looked at. The cell's ink carries every mark instead. */
.bn-cell-accent .bn-plot .bn-art-line {
  stroke: var(--bn-accent-ink);
}

.bn-cell-accent .bn-plot .bn-art-area {
  fill: var(--bn-accent-rule);
}

.bn-cell-accent .bn-plot .bn-art-bar {
  fill: var(--bn-accent-ink);
}

.bn-cell-accent .bn-plot .bn-art-mark {
  fill: var(--bn-accent-ink);
  stroke: var(--bn-accent);
}

/* ==========================================================================
   NAV
   A header bar with a brand block, inline links on desktop, and a disclosure
   panel on mobile. The disclosure is a <details> element, so the pattern needs
   no JavaScript and keeps working with the page's scripts disabled.
   ========================================================================== */
.bn-nav {
  background: var(--bn-ground);
  border-bottom: var(--bn-border-width) solid var(--bn-border-color);
}

.bn-nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--bn-space-4);
  max-width: var(--bn-container);
  margin: 0 auto;
  padding: var(--bn-space-3) var(--bn-space-4);
}

.bn-nav-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--bn-space-3);
  font-family: var(--bn-font-sans);
  font-size: var(--bn-text-h3);
  font-weight: var(--bn-weight-semibold);
  letter-spacing: var(--bn-tracking-tight);
  color: var(--bn-ink);
  text-decoration: none;
}

/* The brand mark is a compartment at 32px, radius and all. It is the smallest
   statement the register can make about itself. */
.bn-nav-mark {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  color: var(--bn-accent-ink);
  background: var(--bn-accent);
  border-radius: var(--bn-radius-tight);
  font-size: var(--bn-text-sm);
  font-weight: var(--bn-weight-semibold);
}

.bn-nav-links {
  display: none;
  align-items: center;
  gap: var(--bn-space-1);
  list-style: none;
  margin: 0;
  padding: 0;
}

.bn-nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: var(--bn-space-2) var(--bn-space-3);

  font-family: var(--bn-font-sans);
  font-size: var(--bn-text-sm);
  font-weight: var(--bn-weight-medium);
  color: var(--bn-ink-muted);
  text-decoration: none;
  border-radius: var(--bn-radius-tight);
}

.bn-nav-link:hover {
  color: var(--bn-ink);
  background: var(--bn-surface-sunk);
}

.bn-nav-link[aria-current="page"] {
  color: var(--bn-ink);
  background: var(--bn-surface);
  box-shadow: var(--bn-shadow-sm);
}

.bn-nav-link:focus-visible {
  outline: var(--bn-ring-width) solid var(--bn-ring);
  outline-offset: var(--bn-ring-offset);
}

.bn-nav-cta {
  display: none;
}

/* Mobile disclosure */
.bn-nav-disclosure {
  position: relative;
}

.bn-nav-disclosure > summary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--bn-space-2);
  min-width: 44px;
  min-height: 44px;
  padding: var(--bn-space-2) var(--bn-space-3);

  font-family: var(--bn-font-sans);
  font-size: var(--bn-text-sm);
  font-weight: var(--bn-weight-medium);
  color: var(--bn-ink);
  background: var(--bn-surface);

  border: var(--bn-border-width) solid var(--bn-border-color);
  border-radius: var(--bn-radius-tight);
  box-shadow: var(--bn-shadow-sm);
  cursor: pointer;
  list-style: none;
}

.bn-nav-disclosure > summary::-webkit-details-marker {
  display: none;
}

.bn-nav-disclosure > summary:focus-visible {
  outline: var(--bn-ring-width) solid var(--bn-ring);
  outline-offset: var(--bn-ring-offset);
}

.bn-nav-panel {
  position: absolute;
  right: 0;
  z-index: 20;
  min-width: 220px;
  margin-top: var(--bn-space-2);
  padding: var(--bn-space-2);

  list-style: none;
  background: var(--bn-surface);
  border: var(--bn-border-width) solid var(--bn-border-color);
  border-radius: var(--bn-radius-inner);
  box-shadow: var(--bn-shadow-lift);
}

.bn-nav-panel .bn-nav-link {
  display: flex;
  width: 100%;
}

/* At 768px the links come inline and the disclosure retires. This breakpoint
   is the nav's own and is not the grid's: a header runs out of horizontal room
   at a different width than a mosaic does. */
@media (min-width: 768px) {
  .bn-nav-inner {
    padding: var(--bn-space-3) var(--bn-space-6);
  }

  .bn-nav-links,
  .bn-nav-cta {
    display: flex;
  }

  .bn-nav-disclosure {
    display: none;
  }
}
