/* ==========================================================================
   bento-grid-theme / tokens
   --------------------------------------------------------------------------
   This file is the single source of truth. Every literal value in the theme
   lives here exactly once. The Tailwind adapters next to it (theme.css for
   v4, preset.js for v3) hold no values of their own; they point at these
   custom properties with var().

   Two things make this token file different from a surface theme's.

   First, it carries a GRID group. Gap, cell radius, cell padding, row height
   and column counts are the values that decide whether a page reads as bento
   or as a plain card grid, and they belong in the same file as the color.

   Second, it carries two alternate SURFACE REGISTERS at the bottom, scoped to
   a data attribute. Bento is a layout archetype rather than a surface one, so
   the proof that the layout survives a change of register has to be in the
   repo rather than asserted in prose. Those two blocks are what
   demo/reskin.html swaps between.

   Each group is annotated with the creative-direction axis the choice serves.
   The four axes are tone register, aesthetic philosophy, audience
   relationship, and sensory ambition. Read them at
   https://rampstack.co/framework/creative-direction

   Contrast ratios in the comments are measured against the ground
   (--bn-ground) or the fill named, and are WCAG 2.1 relative-luminance
   figures. Every text pairing here clears AA, in all three registers below.

   Two values in this file do not clear the 3:1 floor and are not meant to:
   --bn-border-color against the surface, and --bn-accent-rule against the
   accent. Neither carries information. The compartment boundary is the gap,
   the hairline is there so a white cell still has an edge on a washed-out
   screen, and a rule that met 3:1 in this register would read as a table.
   ========================================================================== */

:root {
  /* ----------------------------------------------------------------------
     GROUND AND INK
     Aesthetic philosophy axis. The ground sits a step below the cells and
     the cells sit a step above it, because the whole archetype depends on
     the reader seeing compartments rather than regions. A pure white ground
     under white cells would erase the gap, and the gap is the layout. The
     neutral is warmed by a few points of yellow so the surfaces read as
     paper stock rather than as screen white.
     ---------------------------------------------------------------------- */
  --bn-ground: #f4f3f0;        /* page background, one step below the cells */
  --bn-surface: #ffffff;       /* the cell face */
  --bn-surface-sunk: #ebe9e4;  /* inset panels and code blocks inside a cell */
  --bn-ink: #16181c;           /* text. 16.02:1 on ground, 17.77:1 on surface */
  --bn-ink-muted: #5c6169;     /* secondary text. 5.62:1 on ground, 6.23:1 on surface */

  /* ----------------------------------------------------------------------
     ACTION COLORS
     Tone register axis. One action color, desaturated a long way from the
     primaries a louder register would reach for. Professional buys its
     credibility by not raising its voice, and a button is the loudest thing
     on a calm page whatever color it is.
     ---------------------------------------------------------------------- */
  --bn-primary: #1d4ed8;       /* the one action color. White text: 6.70:1 */
  --bn-primary-ink: #ffffff;
  --bn-danger: #b42318;        /* White text: 6.57:1 */
  --bn-danger-ink: #ffffff;

  /* ----------------------------------------------------------------------
     THE ACCENT
     Sensory ambition axis. Exactly one cell per arrangement takes the accent
     fill. In a mosaic of calm surfaces, a single saturated cell reads as the
     thing the page wants read first, and the reader finds it without being
     told. Two accent cells and the grid has no focal point again, which is
     Considered spending its budget on nothing.
     ---------------------------------------------------------------------- */
  --bn-accent: #1a2b45;        /* deep slate. Accent ink on it: 13.39:1 */
  --bn-accent-ink: #f7f8fa;
  --bn-accent-ink-muted: #a9b6cc;  /* secondary text inside an accent cell: 6.95:1 */
  --bn-accent-rule: #33445e;       /* the hairline inside an accent cell */

  /* ----------------------------------------------------------------------
     CELL TINTS
     Aesthetic philosophy axis. Pale washes rather than saturated fills. A
     tint at this strength lets a cell be told apart from its neighbors at a
     glance without competing with the accent cell, which is the only place
     the palette raises its voice. Ink stays the text color on all three, so
     the tints are chosen for grouping rather than for legibility.
     ---------------------------------------------------------------------- */
  --bn-tint-cool: #e8eefb;     /* ink on tint: 15.28:1, ink-muted on tint: 5.36:1 */
  --bn-tint-warm: #f7ece2;     /* ink on tint: 15.28:1, ink-muted on tint: 5.36:1 */
  --bn-tint-mute: #eceeec;     /* ink on tint: 15.24:1, ink-muted on tint: 5.35:1 */

  /* ----------------------------------------------------------------------
     BORDER
     Aesthetic philosophy axis. One pixel, and a neutral rather than the ink.
     In this register the border is not carrying the compartment boundary,
     the gap is. The hairline exists so a white cell on a near-white ground
     still has an edge when a screen is bright or a projector is bad.
     ---------------------------------------------------------------------- */
  --bn-border-width: 1px;
  --bn-border-color: #dfdcd6;  /* 1.37:1 against surface, a hairline not a rule */

  /* ----------------------------------------------------------------------
     ELEVATION
     Sensory ambition axis. Soft and shallow. The cells are meant to read as
     resting on the ground rather than floating above it, so the shadow is
     doing separation work and not depth work. The lifted step belongs to
     hover on a cell that is a link, and to nothing else.
     ---------------------------------------------------------------------- */
  --bn-shadow-sm: 0 1px 2px 0 rgba(22, 24, 28, 0.05);
  --bn-shadow: 0 1px 3px 0 rgba(22, 24, 28, 0.07), 0 1px 2px -1px rgba(22, 24, 28, 0.05);
  --bn-shadow-lift: 0 8px 20px -6px rgba(22, 24, 28, 0.14), 0 2px 6px -2px rgba(22, 24, 28, 0.07);

  /* ----------------------------------------------------------------------
     RADIUS
     Audience relationship axis, and the single largest lever on whether a
     grid reads as bento. Below about 12px a mosaic reads as a table; above
     about 28px it reads as a toy. The cell radius is generous enough that
     the corner is visible from across the room, which is what makes the gap
     legible as a gap rather than as a ruled line.

     The inner radius is the cell radius less the cell padding, so a media
     panel inset inside a cell stays concentric with the corner around it.
     ---------------------------------------------------------------------- */
  --bn-radius-cell: 20px;   /* the compartment */
  --bn-radius-inner: 12px;  /* anything nested inside a cell */
  --bn-radius-tight: 8px;   /* chips, small controls */
  --bn-radius-pill: 999px;  /* badges and avatars only */

  /* ----------------------------------------------------------------------
     GRID
     Aesthetic philosophy axis. These are the values grid.css consumes, and
     they are the ones that decide whether the page reads as bento.

     The gap is the glue. It has to be wide enough to read as deliberate
     space between separate objects and narrow enough that the objects still
     read as one composition. Below about 12px the cells fuse into a table;
     above about 32px they scatter into unrelated boxes.

     Row height matters as much as column count, because the vertical span
     utilities are meaningless without a row to span. A fixed row means a 1x2
     cell is exactly twice a 1x1 plus one gap, which is the arithmetic that
     makes a mosaic look composed rather than assembled.
     ---------------------------------------------------------------------- */
  --bn-gap: 20px;        /* desktop and tablet */
  --bn-gap-sm: 14px;     /* single column, where a wide gap wastes the fold */

  --bn-cell-pad: 24px;
  --bn-cell-pad-sm: 20px;

  --bn-row: 176px;       /* desktop track height */
  --bn-row-md: 152px;    /* two-column track height */

  --bn-cols: 4;          /* desktop columns, the mosaic */
  --bn-cols-md: 2;       /* tablet columns */
  --bn-cols-sm: 1;       /* phone columns, the stack */

  /* ----------------------------------------------------------------------
     TYPE
     Tone register axis. System stack, so the theme loads no webfont and
     makes no network request. The display weight is 600 rather than the 800
     a louder register would use: in a bento the composition is carrying the
     emphasis, and a heavy heading inside a cell fights the grid for it.

     The stat size is its own token because a bento's most common cell is one
     number and one label, and that number has to be large enough to read as
     the cell's whole content rather than as a heading with a caption.
     ---------------------------------------------------------------------- */
  --bn-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --bn-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  --bn-weight-body: 400;
  --bn-weight-medium: 500;
  --bn-weight-semibold: 600;
  --bn-weight-bold: 700;

  --bn-text-display: 2.75rem;  /* 44px */
  --bn-text-h1: 2.125rem;      /* 34px */
  --bn-text-h2: 1.625rem;      /* 26px */
  --bn-text-h3: 1.1875rem;     /* 19px */
  --bn-text-stat: 2.5rem;      /* 40px, the number that is a whole cell */
  --bn-text-lead: 1.125rem;    /* 18px */
  --bn-text-body: 1rem;        /* 16px, the floor for form inputs on iOS */
  --bn-text-sm: 0.875rem;      /* 14px, the floor for any body content */
  --bn-text-xs: 0.75rem;       /* 12px, labels and badges only, never prose */

  --bn-leading-tight: 1.1;
  --bn-leading-snug: 1.3;
  --bn-leading-body: 1.6;

  --bn-tracking-tight: -0.02em;
  --bn-tracking-wide: 0.06em;

  /* ----------------------------------------------------------------------
     SPACE
     Aesthetic philosophy axis. The scale inside a cell is deliberately short.
     A compartment has room for a label, a value and a line of context, and a
     spacing scale with ten steps in it invites a cell to hold more than that.
     ---------------------------------------------------------------------- */
  --bn-space-1: 4px;
  --bn-space-2: 8px;
  --bn-space-3: 12px;
  --bn-space-4: 16px;
  --bn-space-6: 24px;
  --bn-space-8: 32px;
  --bn-space-12: 48px;
  --bn-space-16: 64px;
  --bn-space-24: 96px;

  --bn-measure: 66ch;      /* prose measure */
  --bn-container: 1160px;  /* page max width */

  /* ----------------------------------------------------------------------
     MOTION
     Sensory ambition axis. One gesture: a cell that is a link rises by a
     couple of pixels and takes the lifted shadow. Nothing else in the theme
     moves. In a grid of twelve cells, anything that animates on load turns
     the composition into a performance, and Considered is the position that
     declines to perform.
     ---------------------------------------------------------------------- */
  --bn-lift: 2px;
  --bn-duration: 140ms;
  --bn-ease: cubic-bezier(0.2, 0, 0.2, 1);

  /* ----------------------------------------------------------------------
     FOCUS
     Audience relationship axis. The ring is offset outside the cell so it
     traces the radius rather than cutting across it, and it uses the primary
     rather than the ink so a keyboard user can tell focus from a border at a
     glance.
     ---------------------------------------------------------------------- */
  --bn-ring: var(--bn-primary);  /* 6.04:1 against ground, clears the 3:1 UI floor */
  --bn-ring-width: 3px;
  --bn-ring-offset: 2px;
}

/* Anyone who has asked the operating system to stop animating gets a theme
   with no lift at all. The shadow still changes on hover, so the cell still
   answers; it just stops moving. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --bn-lift: 0px;
    --bn-duration: 1ms;
  }
}

/* ==========================================================================
   SURFACE REGISTERS
   --------------------------------------------------------------------------
   Two alternate surface treatments, scoped to a data attribute so a single
   subtree can be re-skinned without touching anything outside it. They exist
   for one reason: bento is a layout archetype, and the claim that the layout
   is independent of the surface is only worth making if the repo can show it.
   demo/reskin.html renders the same arrangement three times, once per
   register, and nothing structural differs between the three.

   These blocks redefine surface tokens only. Gap, radius, row height, column
   count and every span utility are untouched, which is the point being made.

   PROVENANCE. Both sibling repositories are public now, and both blocks below
   have been diffed against their real token files:

     hard   rampstackco/neobrutalism-theme  tokens/tokens.css  (--nb-*)
     quiet  rampstackco/swiss-style-theme   tokens/tokens.css  (--sw-*)

   Every value names the sibling token it came from. The hard block needed no
   correction: all twenty values already matched neobrutalism exactly. The
   quiet block needed it in six places, and those are marked below. The worst
   was the cell border, ink here and a mid grey rule there, so this repo had
   been drawing a Swiss register with a boundary the real one does not use.

   These stay declared rather than imported, and the reason is not laziness.
   An @import of a sibling's Pages URL puts a network fetch behind a demo that
   is supposed to open from a file URL with nothing installed. A relative
   import assumes the reader cloned all four repositories into sibling
   directories, which is not true of someone who cloned this one.

   The other half is that an import alone would re-skin nothing. The siblings
   declare --nb-* and --sw-*, this repo consumes --bn-*, so a mapping layer is
   needed either way. If you do have both checkouts and want the live binding
   rather than the copy, that mapping is the whole job:

     @import "../../neobrutalism-theme/tokens/tokens.css";
     [data-surface="hard"] {
       --bn-ground: var(--nb-ground);
       --bn-ink: var(--nb-ink);
       ...
     }

   Re-diff at any sibling release. Values copied by hand go stale quietly,
   which is the honest cost of the choice above.

   If you only want the default register, delete everything from here to the
   end of the file. Nothing else in the repo references it.
   ========================================================================== */

/* --------------------------------------------------------------------------
   HARD: the neobrutalism reading.
   Ink borders at two pixels, a hard offset shadow with no blur, a saturated
   fill, and the radius pulled in hard. The gap stays exactly where it was.
   -------------------------------------------------------------------------- */
[data-surface="hard"] {
  /* Diffed against neobrutalism-theme tokens/tokens.css. Every value matched;
     nothing in this block was corrected. The sibling token is named after
     each one so the next diff is a lookup rather than a guess. */
  --bn-ground: #fbf5ea;         /* --nb-ground */
  --bn-surface: #ffffff;        /* --nb-surface */
  --bn-surface-sunk: #f2e9d9;   /* --nb-surface-muted */
  --bn-ink: #141210;            /* --nb-ink. 17.22:1 on this ground */
  --bn-ink-muted: #57503f;      /* --nb-ink-muted. 7.37:1 on this ground */

  --bn-primary: #3d3bf0;        /* --nb-primary. White text: 6.81:1 */
  --bn-accent: #f0620f;         /* --nb-accent. Ink text: 5.75:1 */
  --bn-accent-ink: #141210;     /* --nb-accent-ink */

  /* This register has no legible muted step on a saturated fill. The darkest
     warm grey that still reads as muted against the orange lands at 4.01:1,
     under AA, so the muted role collapses into the ink rather than shipping a
     value that fails. Losing the muting is the honest trade; a register that
     paints ink on every fill was never going to have a second tier on one. */
  --bn-accent-ink-muted: var(--bn-accent-ink);
  --bn-accent-rule: #141210;

  --bn-tint-cool: #7fd4f5;      /* --nb-fill-info.    ink on tint: 11.25:1 */
  --bn-tint-warm: #ffd84d;      /* --nb-fill-warning. ink on tint: 13.51:1 */
  --bn-tint-mute: #c6f24e;      /* --nb-fill-success. ink on tint: 14.43:1 */

  --bn-border-width: 2px;       /* --nb-border-width */
  --bn-border-color: #141210;   /* --nb-border-color, which is var(--nb-ink) */

  /* --nb-shadow-sm / --nb-shadow / --nb-shadow-lg, resolved. The sibling
     composes these from --nb-shadow-offset-* at 2, 4 and 6 pixels. */
  --bn-shadow-sm: 2px 2px 0 0 #141210;
  --bn-shadow: 4px 4px 0 0 #141210;
  --bn-shadow-lift: 6px 6px 0 0 #141210;

  --bn-radius-cell: 8px;        /* --nb-radius */
  --bn-radius-inner: 4px;       /* --nb-radius-tight */
  --bn-radius-tight: 4px;       /* --nb-radius-tight */

  --bn-weight-semibold: 800;    /* --nb-weight-display */
}

/* --------------------------------------------------------------------------
   QUIET: the Swiss reading.
   No shadow at all, no radius at all, a rule instead of a hairline, and one
   red doing every job the accent and the primary were doing separately. The
   gap stays exactly where it was here too.
   -------------------------------------------------------------------------- */
[data-surface="quiet"] {
  /* Diffed against swiss-style-theme tokens/tokens.css. Six values were this
     repo's approximation rather than the sibling's, and are corrected here.
     Each correction is marked "was". Ratios recomputed against the corrected
     values rather than carried over. */
  --bn-ground: #ffffff;         /* --sw-ground */
  --bn-surface: #f2f2f0;        /* --sw-ground-shade */

  /* No sibling source. Swiss ships two neutral steps, ground and shade, and
     bento's cells need a third for a sunk surface. This is the one value in
     the block that stays this repo's own. Ink on it: 15.10:1. */
  --bn-surface-sunk: #e6e6e3;

  --bn-ink: #111111;            /* --sw-ink. was #0a0a0a. 18.88:1 on ground, 16.85:1 on surface */
  --bn-ink-muted: #565654;      /* --sw-ink-muted. was #4f4f4f. 7.36:1 on ground, 6.56:1 on surface, 5.88:1 on sunk */

  --bn-primary: #c8102e;        /* --sw-accent. was #d62828. White text: 5.88:1 */
  --bn-accent: #111111;         /* --sw-ink. was #0a0a0a. White text: 18.88:1 */
  --bn-accent-ink: #ffffff;     /* --sw-accent-ink, which is var(--sw-ground) */
  --bn-accent-ink-muted: #bdbdbd;  /* on the corrected accent: 10.05:1, was quoted 10.54:1 against the old one */
  --bn-accent-rule: #ffffff;

  /* No sibling source. Swiss ships no tint scale, because a register with one
     accent and one rule has nothing to tint with. Bento's cells need the role
     filled, so all three collapse to one neutral. Ink on it: 15.39:1. */
  --bn-tint-cool: #e8e8e6;
  --bn-tint-warm: #e8e8e6;
  --bn-tint-mute: #e8e8e6;

  --bn-border-width: 1px;       /* --sw-rule-hair */

  /* --sw-rule. was #0a0a0a, which drew this register with an ink boundary it
     does not use: the Swiss cell edge is a mid grey rule, sized to sit under
     the type rather than compete with it. 3.38:1 on ground and 3.01:1 on
     surface, both clearing the 3:1 floor for a non-text boundary. This was
     the largest of the six corrections and the most visible. */
  --bn-border-color: #8c8c88;

  --bn-shadow-sm: none;         /* the sibling declares no shadow token at all */
  --bn-shadow: none;
  --bn-shadow-lift: none;

  --bn-radius-cell: 0px;        /* --sw-radius */
  --bn-radius-inner: 0px;       /* --sw-radius */
  --bn-radius-tight: 0px;       /* --sw-radius */
  --bn-radius-pill: 0px;        /* --sw-radius */

  --bn-tracking-tight: -0.022em;  /* --sw-tracking-display. was -0.01em */
}
