﻿/* ==========================================================================
   Search slice (/sok, #3021). Builds on the btj.css design tokens.
   Mobile-first: cards stack; from 40rem the cover/body/buy areas go side by side.
   ========================================================================== */

.sok-page { display: grid; gap: var(--sp-5); }

/* --- search form ------------------------------------------------------- */

/* /sok DRAWS NO SEARCH FORM ANY MORE (#3140). It had its own prefilled one —
   .sok-form, .sok-form-main, .sok-input, .sok-form-options, .sok-robots-info and
   .sok-adv-link — because the chrome's search box was a small, always-empty one in
   the brand row. #3140 moved the search out of that row to just under it, on the
   page's own grey and so directly above this page's content, which would have made
   a form here a second search box under the first. The band is the re-search form now
   (Features/Shared/_SearchBox.cshtml) and its styling lives beside it in btj.css,
   under .site-search.

   .sok-btn LEFT TOO, with the advanced form it was the button of. That form is drawn in two
   places now — as /sok/avancerad and as the panel the band drops under itself — and the panel is
   rendered on pages that do not load this sheet, so its styling had to move where the chrome's
   is: btj.css, under .sok-adv. Nothing on /sok uses it. */


/* --- media scope ------------------------------------------------------- */

/* Sits between the form and the count because it is a fact about both: it
   explains the number below and is what the box above will search next. Tonal
   band rather than a chip — it is a sentence, and the way out is part of it. */
.sok-scope {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-1) var(--sp-3);
    margin: var(--sp-3) 0 0;
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-sm);
    background: var(--c-accent-soft);
    color: var(--c-accent-soft-text);
    font-size: var(--fs-sm);
}
/* Inherits the band's ink rather than the global teal link colour, which would
   be teal on soft teal; the underline is what still says "link". */
.sok-scope-clear {
    margin-left: auto;
    white-space: nowrap;
    color: inherit;
    text-decoration: underline;
}

/* --- advanced-search criteria ------------------------------------------- */

/* Deliberately NOT the .sok-scope treatment above, though both sit here and both
   say what the search is limited to. The scope band is one accent-toned sentence
   about a thing the customer may not have chosen (the media tab they were on);
   this is a list of choices they made on a form, and a second soft-accent band
   stacked under the first reads as one two-line banner rather than as two facts.
   So: the card's tonal well (docs/DesignSystem.md — ton, inte linjer), which is
   what the buy panel and the article rail already use for "more about this". */
.sok-criteria {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: var(--sp-1) var(--sp-3);
    margin-top: var(--sp-3);
    padding: var(--sp-3);
    border-radius: var(--radius-sm);
    background: var(--c-surface-2);
}

/* The .label recipe — it annotates the list under it, exactly like .sok-sort-label. */
.sok-criteria-title {
    grid-column: 1;
    margin: 0;
    font-family: var(--font-label);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--c-text-muted);
}

/* Pairs flow inline and wrap as pairs: a dt orphaned from its dd is a label for
   nothing, so the two are kept together by making each pair one flex item's worth
   of ink and letting the row wrap between pairs. */
.sok-criteria-list {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-1) var(--sp-4);
    margin: 0;
    font-size: var(--fs-sm);
}
.sok-criteria-list dt {
    color: var(--c-text-muted);
    margin-inline-end: var(--sp-1);
}
.sok-criteria-list dt::after { content: ":"; }
.sok-criteria-list dd {
    margin: 0;
    margin-inline-end: var(--sp-3);
    font-weight: 600;
    color: var(--c-text);
}

/* Right-aligned on the title's row: it is the way back to the form those criteria
   came from, so it belongs beside the heading that names them, not after the list. */
.sok-criteria-edit {
    grid-column: 2;
    grid-row: 1;
    white-space: nowrap;
    font-size: var(--fs-sm);
}

/* --- result head: count, notices, sort --------------------------------- */

/* .sok-results is a plain section and .sok-list carries margin: 0, so nothing
   separated the head from the first card — the sort row sat straight on top of it.
   The gap is on the head rather than the list: it is what the head is spaced from,
   and it still holds on the count-only pages, where no sort row is rendered. */
.sok-head { margin-bottom: var(--sp-5); }

.sok-count { font-size: var(--fs-xl); margin: 0; }
.sok-maxcount, .sok-zero { color: var(--c-text-muted); margin: var(--sp-2) 0 0; }
.sok-suggestion-heading { font-weight: 600; margin: var(--sp-2) 0 0; }
.sok-error { color: var(--c-danger); font-weight: 600; }

/* The printable-result-list link (#3106). Top-right of the head band, where legacy's search head
   also puts it — beside the count rather than in the sort row, because it acts on the whole page
   of hits and not on how they are ordered. The gutter is reserved on the head rather than left to
   the overlap, so a long count line ("1234 titlar") wraps before it reaches the icon. */
.sok-head {
    position: relative;
    padding-right: calc(18px + 2 * var(--sp-1));
}

.sok-print {
    position: absolute;
    top: 0;
    right: 0;
    display: inline-flex;
    padding: var(--sp-1);
    border-radius: var(--radius-sm);
    line-height: 0;
    text-decoration: none;
}

/* Eight columns and one of them is chosen, which is the system's "selected fill"
   case — so they are pills carrying --c-accent-soft when active, not a row of
   blue links where only weight says which one is on.

   Deliberately NOT the .chip recipe, though the shape is the same: a chip is a
   micro-label at 11px uppercase, which annotates a thing. These are eight Swedish
   words a customer reads and clicks — Utgivningsdatum, Tillgänglighet — so they
   keep sentence case at --fs-sm in the label face. Shape from .chip, type from
   the UI. */
.sok-sort {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-1) var(--sp-2);
    margin-top: var(--sp-3);
    font-size: var(--fs-sm);
}

/* The .label recipe: this one really is annotating the row after it. */
.sok-sort-label {
    font-family: var(--font-label);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-outline);
    margin-right: var(--sp-1);
}

.sok-sort-link {
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--radius-pill);
    background: var(--c-surface-2);
    color: var(--c-link);
    font-family: var(--font-label);
    text-decoration: none;
    white-space: nowrap;
}

.sok-sort-link:hover {
    background: var(--c-surface-3);
    color: var(--c-accent-dark);
}

.sok-sort-link.active {
    background: var(--c-accent-soft);
    color: var(--c-accent-soft-text);
    font-weight: 700;
}

/* The small triangles, the same pair the mediegrupp tabs and the Mina sidor
   picker draw, rather than the full-size ▲▼ — at 0.75em those read as arrowheads
   on the word, not as a second glyph beside it. */
.sok-sort-link.active.asc::after { content: " \25B4"; font-size: 0.75em; }
.sok-sort-link.active.desc::after { content: " \25BE"; font-size: 0.75em; }

/* --- result cards ------------------------------------------------------- */

.sok-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--sp-4);
}

/* The hit's position on the page. It used to sit in the card's top-right corner, which worked
   while the corner was empty — the buy well began further down. It does not now: the well is
   top-aligned (#3126), so the number was left in a twelve-pixel band between the card's border
   and the well's, reading as a digit that had fallen off something rather than as the row's
   number.

   Where it goes instead is the list's own left gutter, outside the card, level with the title:
   numbers running down the edge of a result list is what a ranked list looks like, it cannot
   collide with anything the card grows, and it costs the card no interior space. */
.sok-card-pos {
    position: absolute;
    top: var(--sp-4);
    right: var(--sp-2);
    font-size: var(--fs-sm);
    color: var(--c-text-muted);
    font-variant-numeric: tabular-nums;
}

@media (min-width: 40rem) {
    /* The gutter is the list's, not the card's, so the cards stay flush with everything else on
       the page and only the numbers hang outside them. */
    .sok-list { padding-left: 2.25rem; }

    .sok-card-pos {
        left: -2.25rem;
        right: auto;
        width: 2.25rem;
        padding-right: var(--sp-2);
        text-align: right;
        /* Level with the title, which is what the number names — not with the card's top edge,
           where it would sit above the first line of anything. */
        top: var(--sp-4);
    }
}

.sok-card {
    position: relative;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: var(--sp-4);
    display: grid;
    grid-template-columns: 5.5rem 1fr;
    gap: var(--sp-3) var(--sp-4);
    /* Each column is as tall as its own content: a grid item stretches by default, which
       made the tonal buy well a half-empty panel on the one- and no-configuration hits —
       a well drawn taller than what is in it reads as a hole, not as a boundary. The card
       is still max(cover, body, well) tall; only the well stops being padded out to it. */
    align-items: start;
}

@media (min-width: 40rem) {
    /* 20rem, not 16: the buy column now carries a name+delivery track and a price track
       side by side, and the login/utrustad prompts are long. */
    .sok-card { grid-template-columns: 5.5rem 1fr 20rem; }
}

.sok-card.lektor { border-left: 4px solid var(--c-accent); }
.sok-card.not-available .sok-card-body,
.sok-card.not-available .sok-card-cover { opacity: 0.65; }

/* No frame here: the result row does not need one. The card is a grid whose first column is a fixed
   5.5rem, so the picture can simply be its own shape — a book is portrait, a CD is square, a boxed
   game is wider than it is tall — and the row takes the height of its tallest column. In practice
   that is the body or the buy panel: measured at 390 / 768 / 1440px the cover ran 79-135px against a
   body of 115-223px and never was the tallest. It is not guaranteed, though — a cover tops out
   around 135px here and a one-line body can be shorter than that — and it does not need to be. A
   taller cover simply makes its own row taller, which is what not fixing a ratio buys.

   Fixing one bought only an even column of thumbnails, at the price of cropping a third off every
   non-book cover. (The landing shelf does keep a 2:3 box: a scroll-snap row of unequal cards has no
   other way to line its titles up — see start.css .card-cover img.) */
.sok-card-cover img {
    width: 5.5rem;
    height: auto;
    border-radius: var(--radius-sm);
    background: var(--c-badge-bg);
}

.sok-card-title { font-size: var(--fs-lg); margin: 0; }
.sok-card-title a { text-decoration: none; color: var(--c-text); }
.sok-card-title a:hover { color: var(--c-accent-dark); text-decoration: underline; }

.sok-card-author { margin: var(--sp-1) 0 0; font-size: var(--fs-sm); }

/* The facts line is .title-facts in btj.css now — the same one the article page renders,
   from the same partial. Only its spacing inside the card belongs here. */
.sok-card-body .title-facts { margin-top: var(--sp-2); }

/* The .badge vocabulary is btj.css's, pill shape and all: a hit card carries a .chip for the
   media type, and a squarer badge beside a pill reads as two systems. Only the row's layout
   is the card's business. sok.js appends .badge-incart into this container after an add, so
   the class name is a JS contract as well as a style hook. */
.sok-card-badges { margin-top: var(--sp-2); display: flex; flex-wrap: wrap; gap: var(--sp-1); }

/* --- per-card buy info --------------------------------------------------- */

/* A tonal well rather than a rule — the boundary is a change of background
   (docs/DesignSystem.md: ton, inte linjer). */
.sok-card-buy {
    grid-column: 1 / -1;
    background: var(--c-surface-2);
    border-radius: var(--radius-sm);
    padding: var(--sp-3);
}
@media (min-width: 40rem) {
    /* align-self, so the well is the height of the prices it holds and not of the card. A grid
       item stretches by default, which was fine while the body column was a title and a facts
       line; now that it carries the whole article body, a stretched well is a tinted column of
       empty beside it, and the amounts it exists to show sit alone at the top of it (#3126). */
    .sok-card-buy { grid-column: auto; align-self: start; }
}

/* --- the buy row, one arrangement at every width ---------------------------

   The rows are .buy-rows in btj.css, shared with the article page; how a row is arranged
   inside the card is the card's business, and the card uses ONE arrangement rather than one
   per breakpoint. The name takes the first line, whatever the price cell holds sits in the
   second column across both bands, and the button takes the space under the name — which is
   empty on all but the longest configuration names.

   What that buys is not height but legibility. A card can MIX price states — one binding
   priced, the next behind a "Logga in för att se ditt pris" — and every per-state or
   per-breakpoint placement this file had drew those two rows differently: the button was at
   the end of the name's line for a prompt and on a band of its own for an amount, in the
   third track above 56rem and full-width below it. Same well, no edge to read down. Now every
   button in the well is at the same offset, at every width, whatever the row shows.

   Each configuration is its OWN grid, which is what makes that expressible: with the shared
   grid btj.css sets up (display: contents on .buy-row), cells are placed in document order —
   ident, price, button — and the auto-placement cursor never moves backwards, so a button
   that follows a full-width sentence can only land BELOW it. (grid-auto-flow: dense moves it
   back and places the button correctly, then backfills the NEXT configuration's name into the
   hole beside the previous one's.) What the shared grid bought was one price track wide enough
   for every row at once; the prices are right-aligned against the well's own edge, so they
   still line up without it.

   Track sizing, all three parts measured rather than reasoned:

   The 45% cap is what lets a sentence share a column with an amount. At max-content the second
   track is sized by "Lägg till i kundvagn för att se ditt pris" and pushed the page 114px past
   a 320px viewport. Capped, the sentence wraps, and amounts — shorter than the cap — still take
   only what they need.

   The name track has NO min-content floor, which is the opposite of what a name track usually
   wants (see .sok-card at 56rem, where the floor is what stops "Bibliot/eksba/nd" splitting).
   The reason is the phone card's floated cover: a float contributes its own width to the card's
   min-content, so a row whose name and price sit side by side makes the card ask for both at
   once where the old arrangement asked for the wider of the two — 13px past a 320px viewport,
   and the overflow lands on the PAGE rather than in the well, which is why measuring the well
   reports nothing wrong. Dropping the floor costs nothing visible: the track is 1fr and only
   reaches its floor at a width where the row could not fit anyway.

   The price track keeps its floor, because a track that may collapse below min-content does —
   floored at 0 the amounts wrap to four lines and the well grows past what it started at. */
.sok-card-buy .buy-rows {
    grid-template-columns: 1fr;
    row-gap: var(--sp-2);
}

/* EACH CONFIGURATION SITS ON THE WELL'S OWN TONE (2026-09-11, drawn from the designer's
   screenshots): the well is one --c-surface-2 block and its rows carry no tone of their own. The
   padding stays, so the rows sit where they would inside a box and a row's name, amount and antal
   box keep their inset from the well's edge; what separates two configurations is the row gap.
   What it costs: "which antal box belongs to which utförande" is answered by vertical distance
   again, on a card that may carry a priced row and a login prompt with different heights. */
.sok-card-buy .buy-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(min-content, 45%);
    column-gap: var(--sp-3);
    row-gap: var(--sp-1);
    align-items: baseline;
    padding: var(--sp-2);
}

.sok-card-buy .buy-ident { grid-area: 1 / 1; }

/* Both selectors, because the rule this has to outrank — .buy-price:has(.price-prompt) in
   btj.css, written for the shared three-track grid — carries a :has and therefore one more
   class of specificity than .sok-card-buy .buy-price does. Source order alone would not win. */
.sok-card-buy .buy-price,
.sok-card-buy .buy-row:has(.price-prompt) .buy-price {
    grid-area: 1 / 2;
    text-align: right;
    /* NO LEADING RULE HERE, and that is a finding rather than an omission. It was tried on the cell
       first, so that "Pris:" over "Ditt pris:" would tighten with the wrapped prompt — and those
       amounts are two separate facts about the row where the prompt is one broken sentence, so at
       0.6 the pair read as one crushed block and was asked to be put back. The amounts keep the
       page's own leading; only the sentence is tightened, below. */
}

/* WHY THE LEADING ALONE DID NOTHING. The distance between "…kundvagn för" and "att se ditt pris ⓘ"
   is not set by the cell's line-height at all: the mark is .price-info-wrap, an INLINE-BLOCK, and an
   inline-block contributes its own box height to the line box it sits on. At 1em of svg plus the
   button's -0.15em baseline shift it is ~18px against a 15.4px strut, so it — not the strut — was
   deciding how tall the second line is, and tightening 1.55 to 1.1 moved nothing a reader could see.
   (Reported three times as "no change", which is what a rule that applies and does not govern looks
   like from the outside.)

   So the mark is made to fit INSIDE the strut instead of setting it: `line-height: 0` on the wrapper
   drops its internal leading, `display: block` on the glyph removes the baseline descender space an
   inline svg reserves under itself, and 0.85em puts the box at ~12px — under the 15.4px the text
   already needs, which hands the line back to the cell's own line-height.

   The mark still reads at 0.85em: it is a hint beside a sentence, not a control the eye must find,
   and it keeps its full hit area because the BUTTON is what is clicked and its padding is unchanged.
   Scoped to the card — /artikel draws this cell in a page-wide panel where the sentence does not
   wrap and there is no second line to pull up. */
/* 1.05. The range was found from both ends rather than guessed: 1.55 (inherited) reads as two
   lines, 1.25 was still too open, 0.6 crushed them. This is about as tight as the face goes with
   both lines still clear of each other — "Lägg" has a descender and the line under it has ascenders,
   and at 1.0 they meet. It is on .price-prompt and not on the cell, because the cell also holds the
   two-amount pair, which is not a sentence and keeps the page's own spacing. */
/* THE MARK STANDS BESIDE THE SENTENCE, NOT AT THE END OF ITS LAST LINE (asked for 2026-09-01).
   Trailing the text, the ⓘ landed wherever the wrap happened to break — on a short last line it sat
   in the middle of the cell with nothing under it — and it was in the line box, which is what made
   the leading unfixable for several rounds.

   A flex row settles both at once: the text is one item (it still wraps inside itself, and keeps
   its own tight leading) and the mark is a second, centred against the whole block. The sentence
   therefore moves LEFT by exactly the mark's width plus the gap, which is the nudge asked for — it
   is not a margin, it is the mark no longer sharing a line with the words.

   justify-content, because the cell is right-aligned: the pair sits against the same edge the
   amounts on the other rows do. */
.sok-card-buy .price-prompt {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--sp-1);
    line-height: 1.05;
}

/* THE MARK'S BOX IS STATED, NOT DERIVED. Shrinking the glyph and zeroing the wrapper's leading was
   not enough: the wrapper is an inline-block whose height still came from its content — the button,
   itself inline-block, plus btj.css's -0.15em baseline shift on it — which landed a hair OVER the
   strut and went on governing the line. Every line-height tried on the sentence (1.55, 1.25, 1.05)
   therefore changed nothing a reader could see, which is what a rule that applies and does not
   govern looks like from the outside.

   So the height is declared and the alignment is centred: an explicit 0.9em box, middled on the
   text rather than sat on the baseline, contributes ~12.6px against the sentence's ~14.7px strut
   with its overhang split evenly above and below. The strut wins, and the sentence's own leading
   finally decides where its second line sits.

   The glyph keeps 0.9em and the BUTTON keeps its padding, so the hit area is unchanged — what
   shrank is the drawing, not the target. */
.sok-card-buy .price-info-wrap {
    display: inline-block;
    height: 0.9em;
    line-height: 0;
    /* IT IS LIFTED BY `top`, NOT BY `vertical-align`, AND THAT IS THE WHOLE POINT. Raising the box
       with vertical-align was tried and put the leading straight back: moving an inline-block up
       moves its TOP up too, so its contribution above the baseline grows and it goes back to
       out-measuring the strut — the sentence re-opened by exactly what the mark gained. The two
       things were fighting because they were the same declaration.

       `middle` is therefore kept — it is the alignment that makes the box smallest against this
       strut — and the lift is a relative offset, which paints the element elsewhere without
       changing the line box it was measured into. The wrapper is already `position: relative` in
       btj.css (it anchors the hover note), so this costs nothing new and the note travels with it.

       -0.1em ≈ 1.4px: `middle` centres on baseline plus half the x-height, which is right beside
       ordinary lower-case and a touch low beside "…pris", whose last glyphs are all x-height with
       no descender to balance against. One number to tune, and tuning it cannot affect the text. */
    /* Both moot now that the wrapper is a flex ITEM — a flex container's children are blockified and
       aligned by align-items, so neither the baseline it sat on nor the lift off that baseline
       applies. `flex: 0 0 auto` is what matters: the mark never shrinks and never absorbs slack, so
       the text takes every pixel the cell has left. */
    flex: 0 0 auto;
    /* Lifted off the optical centre. align-items already centres the mark on the block; this is a
       relative offset on top of that, which paints it higher without changing the box the flex
       layout measured — the same separation of concerns the line-height rounds arrived at, where
       moving the box and moving the picture kept undoing each other.

       0.25em ≈ 3.5px, up from a first cut at 0.1em that was reported as no change: 1.4px is inside
       the range where a reader cannot tell a move from a memory. `position` is restated rather than
       inherited from btj.css, because a relative offset silently does nothing on a statically
       positioned box and that is exactly the failure that would look like "stuck" again. */
    position: relative;
    top: -0.25em;
}

.sok-card-buy .price-info {
    vertical-align: middle;
    line-height: 0;
}

/* BIGGER. It was shrunk to 0.9em for a reason that no longer holds: at the time the mark shared the
   sentence's line box and had to fit inside its strut or it set the leading. As a flex ITEM beside
   the text it is measured on its own, so the size is free again and can be chosen for legibility —
   this is a hint the eye has to find beside small italic grey text, and 0.9em of hairline ring was
   under the threshold at which anyone looks for it.

   1.15em, and the stroke comes back DOWN with it: 3 was chosen to darken a tiny glyph, and the same
   weight on a larger ring reads as a blob rather than as a ⓘ. 2.25 keeps the ink roughly where 3
   put it while the shape stays a ring with two marks inside.

   The BUTTON's padding is untouched, so the hit area did not change with the drawing — it was
   already the larger of the two. */
.sok-card-buy .price-info svg {
    display: block;
    width: 1.15em;
    height: 1.15em;
    stroke-width: 2.25;
}

/* display: contents so the add line and the "Byt kundvagn" link sok.js inserts after it are
   placed independently: the link is as long as the cart's name, and inside the line's own
   track it would set that track's width and starve the name. */
.sok-card-buy .buy-action { display: contents; }

/* The antal box and the button are one gesture — type a number, click — so they share a line
   (#3196). It WRAPS rather than letting either shrink: from 56rem the well is a 23rem column
   and "Lägg i kundvagn" beside a box does not fit the name track there, so the box takes the
   line and the button drops under it. Nothing in §4.4's track measurements moves, because a
   wrapping line's min-content is still the widest of its two items, which is the button — what
   the track was already sized to. */
/* ONE EDGE DOWN THE WELL (asked for 2026-09-01). The price was right-aligned at the top and the
   add line sat at the leading edge underneath it — a diagonal with the block's whole middle empty,
   and two edges to read a well of four rows down. The line now spans the row and is pushed to the
   same edge the amount is on, so what a configuration COSTS and what you press to buy it are one
   column.

   THE PRICE THEREFORE STOPS SPANNING. It held rows 1-2 of column 2 because the add line was in
   column 1 beneath the name; with the line spanning the full width of row 2 the two would collide,
   so the amount is row 1 alone. Nothing about the 45% cap changes — it is the track's, and the
   track is still what a wrapping login prompt is measured against. */
.sok-card-buy .sok-add-line {
    grid-area: 2 / 1 / auto / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--sp-2);
    /* --sp-4 (16px), up from --sp-1 (asked for, in that number). The line is now the last thing in
       a tinted block rather than the third item of a shared grid, and at 4px the antal box sat
       against the price above it closely enough to read as part of the same statement. What
       separates "this is what it costs" from "this is how many you want" is the only gap in the
       block, so it is the one that has to be legible.

       A margin rather than the grid's row-gap because only THIS row needs it — the gap is the
       grid's and would move the name and the price apart with it. */
    margin-top: var(--sp-4);
}
.sok-card-buy .sok-add-btn { margin-top: 0; }

/* "Byt kundvagn" follows the control it changes, on the same edge. */
.sok-card-buy .sok-add-change {
    grid-area: 3 / 1 / auto / -1;
    justify-self: end;
    margin-top: 0;
}

/* The card's own three columns from 56rem — the well is a 26rem column beside the body, not a
   band under it. At 40rem the whole card is 640px and a 26rem well would starve the body.

   min-content, not 0, on the name track here: the page sets overflow-wrap: break-word, so a
   track allowed to shrink below its longest word splits it — "Outrust/ad" — rather than letting
   the grid be the thing that gives. */
@media (min-width: 56rem) {
    .sok-card { grid-template-columns: 5.5rem 1fr 23rem; }

    /* 23rem rather than the 26 the three-track layout needed: that layout had to fit a name, a
       price and a button on ONE line, and this one stacks the button under the name, so the well
       can give the article body 48px back. It stops there because the well is sized by its
       CONTENT and not by taste — at 20rem the configuration names start wrapping ("Bibliotekband
       (5-8 dgr)"), which costs 21px on every row that does it and undoes the saving twice over.

       The price cap stays 45% and the login prompt therefore takes two lines here. Widening it
       to 55% does put the prompt back on one line — and takes the width out of the name track,
       which is 1fr, so the names wrap instead and the well is 36px taller than it is at 45%. A
       sentence broken over two lines is the cheaper of the two.

       More air, because the well is narrower and its rows are two bands rather than one line:
       between configurations sp-4 (they read as separate offers, and the change link now ends
       one where the next begins), and inside a row sp-2 so the button is not welded to the name
       above it. Left at the phone's sp-3/sp-1 the narrower column reads as a denser one, which
       is the opposite of what taking the width off was for. */
    .sok-card-buy { padding: var(--sp-4); }
    /* sp-3, not the sp-4 this had before the configurations became blocks: a tinted box already
       says where one offer ends, so the gap is only keeping them apart and no longer doing the
       separating on its own. */
    .sok-card-buy .buy-rows { row-gap: var(--sp-3); }
    .sok-card-buy .buy-row { row-gap: var(--sp-2); }
}

.sok-card-notavailable, .sok-card-offer { font-size: var(--fs-sm); color: var(--c-text-muted); margin: 0; }

/* The antal box is .antal-field from btj.css, whole (#3198) — the control, its "st", its
   stepper and its placeholder all belong to it. What is the card's business is only that the
   field is ONE flex item on the add line, so the gap between box and button is the line's and
   not the two put together. That is the class's whole job here. */
.sok-card-buy .sok-qty { flex: 0 0 auto; }

/* One compact button per orderable configuration row. Adds what the antal box says — an empty
   box being 1 st — to the remembered cart; the article page keeps the full buy options. */
.sok-add-btn {
    margin-top: var(--sp-1);
    padding: var(--sp-1) var(--sp-3);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: #fff;
    background: var(--c-accent);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
}
.sok-add-btn:hover:not(:disabled) { background: var(--c-accent-dark); }
.sok-add-btn:disabled { opacity: 0.7; cursor: default; }

/* "Byt kundvagn (…)" — the change-cart affordance, shown once a cart is remembered. A quiet
   text link under the add button so the common path (add to the remembered cart) stays primary. */
.sok-add-change {
    display: block;
    margin-top: var(--sp-1);
    padding: 0;
    font-size: var(--fs-sm);
    background: none;
    border: 0;
    color: var(--c-text-muted);
    text-decoration: underline;
    cursor: pointer;
}
.sok-add-change:hover { color: var(--c-text); }

/* REQUIRED, and its absence was a 56px hole. sok.js creates this button for every multi-cart
   caller and hands it out `hidden`, revealing it only once a cart is remembered — but an author
   `display` beats the user-agent sheet's `[hidden] { display: none }` whatever the specificity,
   because author origin wins over UA origin. So `display: block` above left a ghost grid item on
   the block's third row; and since `@media (pointer: coarse)` gives every `button` a
   `min-height: var(--control-min)`, the ghost was exactly 44px tall — a button-shaped hole under
   the button, on a touch device, for every caller with more than one cart. Twelve other controls
   in this codebase already carry this restatement (.copy-btn, .site-cart-menu, .site-adv-panel,
   .kv-saveall, .dh-card-flags > li …); this one did not. */
.sok-add-change[hidden] { display: none; }

/* Cart chooser — a small popup of the caller's carts, anchored under the clicked add
   button (built on <body> by sok.js, positioned in document coordinates). Only shown to
   callers with more than one cart; the choice is deliberate, nothing pre-selected. */
.sok-cart-menu {
    position: absolute;
    z-index: 50;
    /* Wide enough for the search box to be a search box; the panel still grows to the width of
       the button it hangs under (sok.js positionMenu). */
    min-width: 15rem;
    max-width: 22rem;
    background: var(--c-surface);
    border: 1px solid var(--c-border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    padding: var(--sp-1);
}
/* The cap is on the list, not on the panel: the carts scroll while the heading, the search box
   and the match count stay put — a search box that scrolls away is one a long list hides. */
.sok-cart-menu-list {
    max-height: 16rem;
    overflow-y: auto;
}
.sok-cart-menu-head {
    margin: 0;
    padding: var(--sp-1) var(--sp-2);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--c-text-muted);
}
.sok-cart-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: var(--sp-1) var(--sp-2);
    font-size: var(--fs-sm);
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    cursor: pointer;
    color: var(--c-text);
}
.sok-cart-menu-item:hover, .sok-cart-menu-item:focus { background: var(--c-badge-bg); outline: none; }
.sok-cart-menu-item[hidden] { display: none; }

/* The shared search box (btj.css) sits inside the panel's own --sp-1 padding, so it takes the
   same inline breathing room the heading and the items get. */
.sok-cart-menu .cart-search { margin: var(--sp-1); width: calc(100% - 2 * var(--sp-1)); }
.sok-cart-menu .cart-search-status { margin: 0 var(--sp-2) var(--sp-1); }

/* --- pager --------------------------------------------------------------- */

/* Set off from the last card rather than trailing it. The list's own gap separates cards from
   each other, and the pager is not another card — it ends the list, so it gets more room than
   the cards get between them. */
.sok-pager { margin-top: var(--sp-6); }

.sok-pager ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-1);
    justify-content: center;
}
.sok-pager a, .sok-pager span {
    display: inline-block;
    min-width: 2.2rem;
    text-align: center;
    padding: var(--sp-1) var(--sp-2);
    border-radius: var(--radius-pill);
    text-decoration: none;
}
.sok-pager a:hover { background: var(--c-surface-2); }
.sok-pager .current span { background: var(--c-accent); color: #fff; font-weight: 700; }
.sok-pager .inactive span { color: var(--c-text-muted); }


/* --- advanced search (#3031) --------------------------------------------- */

/* .sok-adv* MOVED TO btj.css (#3140). The advanced form has two homes now: this
   slice's /sok/avancerad page, and the panel the chrome's search band drops under
   itself on every shop page — one partial, _AdvancedForm.cshtml, so there is one
   form and not two free to disagree. The panel renders where this sheet is not
   loaded, so the rules had to follow it to the sheet that always is. */


/* --- The article body inside a result card (#3126) ---------------------------

   Legacy drew this as the row's second TAB, beside Snabbfakta: picking it swapped the whole
   row's contents for the article body. Here the card keeps what it had and the body is added
   to it — the two are not alternatives, since the card already shows what Snabbfakta showed,
   and hiding the title and its buy rows to read a lektörsomdöme is a swap nobody asked for.
   That is also why the body needs no second copy of the cover, the title or the price rows.

   It sits in the card's BODY column, under the badges — where /artikel draws its own strip
   (the hero card's middle column) and where legacy draws it too (ArticleDetail.ascx's
   DetailBody). As a full-width band below the three columns it read as a second thing under
   the card rather than as more of the title it belongs to.

   And it is not behind a disclosure: the strip states its own contents — Beskrivning, Mer
   info, Detaljer are visible words, where a "Detaljerad information" summary was a closed
   door with nothing written on it. */
.sok-card-detail {
    margin-top: var(--sp-2);
    font-size: var(--fs-sm);
}

.sok-card-detail-status { margin: var(--sp-2) 0 0; color: var(--c-text-muted); }

/* The strip is drawn the same here as on the article page, and that is the point (#3153).
   It used to be tighter — smaller padding, and the first tab pulled flush left so an
   underlined label lined up with the body text beneath it. Both of those were about tabs:
   a chip is a filled shape, so a fill with no left padding is a clipped chip, and one
   control drawn two ways is the thing the shared partial exists to prevent. What stays
   card-specific below is the space around the strip and how far a pane may run, which is
   about the row this sits in rather than about the control. */

/* The strip keeps the card's own surface, as it does on the article page: what separates the
   body from the card above it is the strip's own rule, not a fill. */
.sok-card-detail .article-tabs {
    margin-top: 0;
    /* The article page gives its panes room to be the page; here they are a band inside a
       result row, so the clamp is tighter and the padding smaller. */
    --tabpanel-clamp: 5.5rem;
}

.sok-card-detail .tabpanel { padding: var(--sp-2) 0 0; }

/* A single pane draws no strip, and in a card it has no headline above it either — so the
   rule that separated the two on the article page has nothing to separate. */
.sok-card-detail .article-pane-heading { padding-top: 0; border-top: none; }

/* The bibliographic list is a PANE here rather than the article page's tinted rail
   (ArticleDetailBodyView.InfoAsPane), so it drops the well: a tinted block inside an open
   panel would be a second surface for the one pane that has no more claim to it than the
   others. Two columns where the column is wide enough — the rows are short. */
.sok-card-detail .article-info-list {
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    column-gap: var(--sp-5);
}

/* --- The card on a phone --------------------------------------------------

   Below 40rem the card's two tracks are a 5.5rem cover and everything else, and "everything
   else" is 220 of the card's 326 interior pixels. That is a fine measure for a title and a
   facts line and a poor one for the article body the card now carries (#3126): the tab strip
   and its panes read as a narrow column beside the picture rather than as the card's own
   text, while the space under the picture is left empty for them to do it in.

   So on a phone the picture is a FLOAT and the body wraps around it. That is the one
   arrangement in which "beside the cover" and "under the cover" are the same layout — the
   title, the facts line and the badges take the short lines beside the picture, and the strip
   CLEARS it and takes the full width, wherever the two happen to end. A grid cannot say that:
   a nested child of a grid item cannot leave its track, and pulling it out with a negative
   margin would collide with the cover on any card whose text is shorter than its picture —
   already 1 of the 25 hits for "mess" (text ending at 140px against a 143px cover).

   A max-width query, against this file's mobile-first habit, because these rules UNDO the
   shared layout rather than parameterise it: the card stops being a grid here. It is the card
   only — the buy row inside it is one arrangement at every width, above. */
@media (max-width: 39.999rem) {
    /* flow-root so the card contains its own float: the buy well below clears it, but a card
       with neither text nor body would otherwise end above its own picture. */
    .sok-card { display: flow-root; }

    /* No bottom margin: whichever band clears the picture brings its own top margin, and on a
       card whose picture is the taller side the two would add up to a hole. */
    .sok-card-cover {
        float: left;
        margin-right: var(--sp-4);
    }

    /* Clearance, not a column. The card's grid gap is gone with the grid, so the two bands
       below carry their own. */
    .sok-card-detail,
    .sok-card-buy {
        clear: left;
        margin-top: var(--sp-3);
    }
}


/* --- the configuration block when its controls are a stack (asked for 2026-09-04) -----------

   THE TRIGGER IS THE POINTER, NOT THE WIDTH, and getting that wrong is why this was first
   written as a phone rule. On a coarse pointer antal.js draws its own -/+ at --control-min
   (#3198, because type="number" renders NO spinner on iOS Safari or Android Chrome), so
   .antal-stepper is 44 + 4 + 56 + 4 + 44 = 152px and the field with its "st" is 165; on a fine
   pointer the same field is 77. Against a 129px button that is 302px of line versus 214, so the
   line wraps for a thumb and never for a mouse — measured at 640, 800, 896 and 1280, where the
   fine-pointer block is 99-103px at every one of them and the coarse-pointer block is 164px
   until 56rem. The condition below is therefore exactly the set where the block is two controls
   tall: a phone (which is what was asked for), a tablet, and a touch laptop under 56rem — and
   NOT a mouse user at 500px, who has no stack to tighten, nor a thumb at 1280px, where the well
   is 23rem and the line fits with 18px to spare.

   NOTHING ABOUT THE GAPS CAN REACH THE STACK ITSELF. 302 against 284 is 18px short at 390px and
   worse at 360, and every candidate saving comes off a touch target or the gap between two of
   them — the floor #3198 states for the DH buy panel, "the stepper's 152px is a FLOOR no
   redistribution can reach". So the arrangement is untouched (it is still one arrangement at
   every width) and what goes is the dead space around it:

   HALF THE RUN-UP. The line's margin is --sp-4 everywhere else and --sp-2 here. That 16px was
   asked for, in that number, and the reason it was given — an antal box close enough to the
   amount above it to read as part of the same statement — is a reason about a block whose
   control is ONE line ending level with the price. Here the controls are a 96px stack that no
   reader mistakes for part of a price, and 16px was the widest gap in the card.

   THE BOTTOM PADDING STAYS, which this rule set briefly removed and #3269 explains. The block was
   reported as having "a huge empty space below the button" and the first reading of that was the
   8px floor, so the button was made to end the tint the way a card's image ends a card. It was
   the wrong 8px: the reported space was a 44px GHOST — sok.js's hidden "Byt kundvagn" button,
   which `[hidden]` did not hide and a coarse pointer sized like any other button. With that gone
   there is nothing to buy by taking the floor off, and a filled control flush to one edge of a
   tinted box while inset 8px from the other three was never the better drawing — it read as a
   button escaping its box. So the block keeps 8px on all four sides and only the run-up moves.

   156px against 164, twice per card, which is ~400px off a 25-hit page at 390px. The rest of
   what was reported was #3269, and it was 56px per block.

   With scripting off there is no stepper and no stack, so this rule tightens a block that did
   not need it. Left unscoped deliberately: the result is a one-line control 8px under its price,
   which is what every fine-pointer block already is, and a (scripting: enabled) query here would
   be a third condition guarding a spacing difference nobody can see. */
@media (pointer: coarse) and (max-width: 55.99rem) {
    .sok-card-buy .sok-add-line { margin-top: var(--sp-2); }
}
