@layer base {
/* =============================================================================
   @elements/style — base (inside @layer base)

   Default styling for bare HTML elements. No :where() needed for SPECIFICITY
   — the cascade layer puts these BELOW components and utilities, so any class
   or utility wins automatically.

   THAT ARGUMENT DOES NOT COVER INHERITANCE, and the difference is the reason
   these rules set almost no colors. A declaration that MATCHES an element
   beats an INHERITED value at any specificity, in any layer, and :where()
   does not change that — inheritance is only consulted when nothing matches.
   So `h2 { color: var(--ink) }` is not a harmless restatement of the default:
   it is the thing that makes a heading go invisible the moment someone writes
   a dark panel, a callout or an inverted hero that sets `color:`.

   RULE FOR THIS FILE: set `color` on a bare element only when the element
   also owns its `background` (code, pre, kbd, mark, ::selection). Those own
   both sides of the pairing and must not float with the surroundings.
   Everything else either inherits, or uses --ink-soft-flow, which is derived
   from currentColor so it stays soft AND inherits. man/style_test.go enforces
   this; see the token comment in themes/default.css.

   SPACING. The reset zeroes every margin so components can lay themselves out
   with gap. This file puts flow spacing back for ordinary document markup, so
   a page written with no classes at all reads correctly. The layout primitives
   (.stack, .cluster, .row) sit in a later layer and zero their children's
   margins again, so a gap-based layout never doubles up.

   Native widgets (progress, meter, details) live in native.css.
============================================================================= */

/* PAGE FRAME — only for markup that has not been given a class.

   A bare <main> is a document, and a document needs a measure and a gutter or
   it renders edge to edge at 130 characters a line. The moment an app puts a
   class on the element it has taken over the layout, and :not([class]) steps
   out of the way rather than fighting it. Paragraph width is capped separately
   by --measure below, so a wide main still reads well. */

main:not([class]),
body:not([class]):not(:has(main)) {
  max-width:      var(--container-shell);
  margin-inline:  auto;
  padding-inline: clamp(var(--space-4), 5vw, var(--container-padding));
  padding-block:  var(--space-8);
}

html {
  font-family:    var(--font-sans);
  line-height:    var(--leading-body);
  color:          var(--ink);
  background:     var(--bg);
}

body {
  font-family:    var(--font-sans);
  font-size:      var(--text-base);
  line-height:    var(--leading-body);
  color:          var(--ink);
  background:     var(--bg);
}

/* FOCUS — the reset kills the UA outline so components can draw their own
   ring. This is the floor underneath that: anything focusable with no ring of
   its own still gets one. Without it a custom widget, or any element carrying
   tabindex, is focusable with no visible indicator, which is the kind of defect
   a beginner ships without knowing.

   :where() keeps it at zero specificity and it is declared FIRST, so both the
   link ring below and every component ring in a later layer replace it rather
   than stacking a second outline on top. */
:where(:focus-visible) {
  outline:        2px solid var(--focus);
  outline-offset: 2px;
}

/* HEADINGS — generous, modern scale ------------------------------------ */

h1 {
  font-size:      var(--text-4xl);
  font-weight:    var(--weight-semibold);
  line-height:    var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

h2 {
  font-size:      var(--text-3xl);
  font-weight:    var(--weight-semibold);
  line-height:    var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}

h3 {
  font-size:      var(--text-2xl);
  font-weight:    var(--weight-semibold);
  line-height:    var(--leading-tight);
  letter-spacing: var(--tracking-snug);
}

h4 {
  font-size:      var(--text-xl);
  font-weight:    var(--weight-semibold);
  line-height:    var(--leading-snug);
}

h5 {
  font-size:      var(--text-lg);
  font-weight:    var(--weight-semibold);
  line-height:    var(--leading-snug);
}

h6 {
  font-size:      var(--text-base);
  font-weight:    var(--weight-semibold);
  line-height:    var(--leading-snug);
}

/* PARAGRAPH */
p { line-height: var(--leading-body); }

/* =============================================================================
   FLOW

   The reset zeroes every margin so components can space themselves with gap.
   Document content still needs vertical rhythm, and this is where it comes
   back. One rule per ROLE, not one per element:

     a block of running content opens --space-4 above and below it
     a heading opens a larger lead, so sections separate more strongly than
       the paragraphs inside one do, and closes tighter to the content it
       introduces, because a heading belongs to what follows it

   Margins collapse between siblings, so a heading's lead and the preceding
   paragraph's space resolve to the larger of the two instead of stacking.
   Element margins rather than an owl (`* + *`) on purpose: a paragraph
   followed by a plain <div> is still spaced, and a component's own children
   are left alone. .prose uses the owl over the top of this for the tighter
   editorial rhythm; see typography.css.

   --measure is the line-length cap, and it is scoped to the page frame for the
   same reason the frame itself is: it exists so a BARE document reads well, and
   outside one the app owns its layout. Capping every p on the page reaches into
   component internals, where the cost is silent and occasionally wrong — a
   paragraph in a text-align:center hero keeps its capped box flush left and
   renders visibly off-centre from the heading above it (measured at 1400px: a
   685px box in a 1088px parent, 371px of dead space on the right). A component
   would have to write max-width:none to opt out of a rule it never asked for.

   An unclassed <main> is the signal, and only that one. A classless <body> is
   not: real apps leave the body bare and class everything inside it, so using
   it as an ancestor would reach every component on the page and put us straight
   back where we started.
============================================================================= */

p, ul, ol, dl, blockquote, pre, table, figure, form, details {
  margin-block: var(--space-4);
}

h1, h2     { margin-block: var(--space-10) var(--space-4); }
h3         { margin-block: var(--space-8)  var(--space-3); }
h4, h5, h6 { margin-block: var(--space-6)  var(--space-2); }

hr { margin-block: var(--space-8); }

main:not([class]) :is(p, li, dd, blockquote, figcaption) {
  max-width: var(--measure);
}

/* Clear the outer edges. A padded container (a .card, a .callout, the page
   frame) must not gain a phantom band of space inside its own padding, and
   the reader must not gain one at the top of the page. */
:is(h1, h2, h3, h4, h5, h6, p, ul, ol, dl,
    blockquote, pre, table, figure, form, details, hr):first-child {
  margin-block-start: 0;
}

:is(h1, h2, h3, h4, h5, h6, p, ul, ol, dl,
    blockquote, pre, table, figure, form, details, hr):last-child {
  margin-block-end: 0;
}

/* LINKS — wrapped in :where() so component classes (.button, .link-action,
   etc.) can override without specificity battles inside the same layer too.

   THE COLOR ADAPTS TO ITS SURFACE. A link takes its LIGHTNESS from the text
   around it and its hue and chroma from the theme, so it is readable on a
   white page, on a dark panel and on a saturated brand panel without anyone
   writing a class. A fixed accent cannot do this: measured against a dark
   panel, --accent-deep lands at 1.21:1 in the default theme and 1.74:1 in the
   Elements theme, both invisible. Every fixed color-mix ratio was measured
   too and none clears AA on all three surfaces.

   The lightness is nudged 20% further from mid-grey than the surrounding text,
   which is what makes a link read as a link rather than as a tinted word. The
   direction is decided by the text itself: dark text means a light surface, so
   the link goes darker; light text means a dark surface, so it goes lighter,
   and there it simply clamps at white. Contrast therefore never falls below
   the surrounding text's own. Measured across four surfaces, link vs text:
     white page          15.65 vs 14.37
     dark panel          14.73 vs 16.76
     saturated brand      5.51 vs  6.27
     dark mode           17.78 vs 19.44

   --link-c and --link-h are the theme's link chroma and hue. When a theme does
   not set them the `c` and `h` fallbacks mean "keep currentColor's own", so the
   link renders as the surrounding ink, a shade deeper, plus an underline. That
   is the default theme, which is monochrome by design. A branded theme sets
   both next to --accent; see themes/elements.css.

   The plain --accent-deep declaration above it is the fallback for a browser
   without relative color syntax, which drops the second declaration. */
:where(a) {
  color:                  var(--accent-deep);
  color:                  oklch(from currentColor
                                calc(l + (l - 0.5) * 0.2)
                                var(--link-c, c)
                                var(--link-h, h));
  text-decoration:        underline;
  text-decoration-color:  color-mix(in oklab, currentColor 30%, transparent);
  text-underline-offset:  0.25em;
  transition:             var(--transition-colors);
}
:where(a:hover) { text-decoration-color: currentColor; }
:where(a:focus-visible) {
  outline:        none;
  box-shadow:     var(--focus-ring);
  border-radius:  var(--radius-xs);
}

/* LISTS — the reset strips markers so a nav or a menu built from <ul> starts
   clean. A bare list is not a nav, it is a list, so the markers come back here.
   The layout primitives strip them again for the nav case. */
ul { list-style: disc; }
ol { list-style: decimal; }
ul, ol { padding-inline-start: var(--space-6); }

li { line-height: var(--leading-body); }
li + li { margin-block-start: var(--space-1); }

li > ul, li > ol { margin-block: var(--space-1); }
ul ul { list-style: circle; }
ul ul ul { list-style: square; }
dt { font-weight: var(--weight-semibold); }
dd {
  margin-block-end:     var(--space-3);
  padding-inline-start: var(--space-4);
  color:                var(--ink-soft-flow);
}
dd:last-child { margin-block-end: 0; }

/* QUOTE / HR */
blockquote {
  padding-left: var(--space-4);
  border-left:  3px solid var(--rule);
  color:        var(--ink-soft-flow);
  font-style:   italic;
}
hr {
  border: none;
  border-top: 1px solid var(--rule);
}

/* CODE */
code {
  font-family:   var(--font-mono);
  font-size:     0.92em;
  background:    var(--bg-muted);
  color:         var(--ink);
  padding:       0.15em 0.4em;
  border-radius: var(--radius-xs);
}
pre {
  font-family:   var(--font-mono);
  font-size:     var(--text-sm);
  line-height:   var(--leading-snug);
  background:    var(--bg-inverse);
  color:         var(--ink-inverse);
  padding:       var(--space-4);
  border-radius: var(--radius-surface);
  overflow-x:    auto;
  tab-size:      2;
}
pre code {
  background:    transparent;
  padding:       0;
  font-size:     inherit;
  color:         inherit;
  border-radius: 0;
}

/* KBD */
kbd {
  display:       inline-block;
  font-family:   var(--font-mono);
  font-size:     0.85em;
  background:    var(--bg-muted);
  color:         var(--ink);
  padding:       0.15em 0.45em;
  border:        1px solid var(--rule);
  border-radius: var(--radius-xs);
  box-shadow:    0 1px 0 var(--rule);
}

/* MARK */
mark {
  background:    var(--warning-soft);
  color:         var(--warning-ink);
  padding:       0 0.1em;
  border-radius: var(--radius-xs);
}

/* TABLES */
table {
  width:           100%;
  font-size:       var(--text-sm);
  line-height:     var(--leading-snug);
  border-collapse: collapse;
}
thead { border-bottom: 1px solid var(--rule); }
tbody tr + tr { border-top: 1px solid var(--rule-soft); }
th {
  text-align:  left;
  font-weight: var(--weight-semibold);
  color:       var(--ink-soft-flow);
  padding:     var(--space-2) var(--space-3);
}
td {
  padding:        var(--space-2) var(--space-3);
  vertical-align: top;
}

figcaption {
  font-size:  var(--text-sm);
  color:      var(--ink-soft-flow);
  margin-top: var(--space-2);
}

/* FORMS — a bare form is a stack of labels and controls with no wrapper, so
   the spacing has to come from the form itself. A label sits close to the
   control it names; separate fields get a full gap.

   The spacing is a GRID GAP and not a margin, and that is the whole point.

   This used to be `form > * + * { margin-block-start: var(--space-4) }`. It
   spaced a stacked form correctly and it silently wrecked every horizontal
   one. The moment an author laid a form out themselves — `display: flex` and a
   gap, to put an input beside its button — that margin was still there, on
   every child after the first, pushing each one a full step below the control
   next to it. A search box, an email-and-subscribe, an add-a-todo: all of them
   came out visibly misaligned, and nothing in the author's own css explained
   why. CSS cannot ask whether an element is a flex container, so there was no
   condition to guard the margin with.

   A gap has no such problem. It applies only while the form owns its layout,
   and `display: flex` from the author replaces that layout wholesale — gap and
   all, with the author's own gap taking over. Nothing leaks. The naive thing
   is now the correct thing, with no class to remember. */

form {
  display:       grid;
  gap:           var(--space-4);
  align-content: start;
}

/* Grid stretches its items, which is right for a control and wrong for a
   button: a bare Save should be its own width, as it is anywhere else. */
form > :is(button, .button,
           input[type="submit"], input[type="reset"], input[type="button"]) {
  justify-self: start;
}

label { display: block; }
label:has(> input[type="checkbox"]),
label:has(> input[type="radio"]) {
  display:     flex;
  align-items: center;
  gap:         var(--space-2);
}

/* A label and its control are one thing, so they sit a tight step apart rather
   than a full one. Directly inside a form the grid gap is already between
   them, and this pulls back to the tighter step; anywhere else (inside .field,
   say) there is no gap and the step is added outright. */
form > label + :is(input, textarea, select) {
  margin-block-start: calc(var(--space-1) - var(--space-4));
}

label + input, label + textarea, label + select { margin-block-start: var(--space-1); }

/* Adjacent buttons sit side by side wherever they share a line. Directly
   inside a form they do not: the form is a grid and puts each on its own row,
   so the inline step would only indent the second one. */
button + button { margin-inline-start: var(--space-2); }
form > button + button { margin-inline-start: 0; }

::selection {
  background: color-mix(in oklab, var(--accent) 22%, transparent);
  color:      var(--ink);
}

}
