
.board-page { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--board-space-7); align-items: start; }
.board-page:has(> .board-side) { grid-template-columns: minmax(0, 1fr) var(--board-side-w); }
.board-content { min-width: 0; }

/* The head is the board's 22px name with its count beside it in the muted 13px (C). */
.board-head { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.625rem; padding: 0 0 var(--board-space-3); }
.board-title { font-size: var(--board-size-page); font-weight: var(--board-weight-title); margin: 0; letter-spacing: -0.03em; line-height: var(--board-leading-tight); }
.board-title a:hover { text-decoration: none; }
/* A widget above the board (board-skin.md §9): the head becomes the section's 「게시판」 and the board, its count and its table step under it, ruled off by the heavier 2px line on production's own 2.9rem/2rem spacing. */
.board-section { margin-top: var(--board-space-7); }
/* Inside it the head is a section's own h2, not the page's h1. */
.board-section .board-title { font-size: var(--board-size-display); font-weight: var(--board-weight-title); line-height: 1.35; }
/* The switch's label is the head's search button on a phone only: here the form stands open at the head's foot and the button has nothing to open. */
.board-search-open { display: none; }
/* The count and the board's own description sit under the title: the count at the row's own size in the dim grey production uses, the description a step smaller and just as quiet. */
.board-count { margin: 0; color: var(--board-dim); font-size: var(--board-size-meta); font-variant-numeric: tabular-nums; }
.board-desc { flex-basis: 100%; margin: var(--board-space-1) 0 0; color: var(--board-dim); font-size: var(--board-size-meta); }
/*
 * A tag listing's head (board-skin.md §9): production sits it on the same card as the list below
 * it, not the bare ground the board's own head stands on, so `.board-card`'s surface joins
 * `.board-head` here rather than a second copy of it. The 1.1rem pad and the 11px gap to the card
 * under it are production's own measure, closer than the `--board-space` ladder gets.
 */
.board-head.tag-head { display: block; padding: 0 0 var(--board-space-3); margin: 0; }
/* The eyebrow over the title and the sentence under it, both production's 14px dim grey — the tag's own word above the name, and what the listing gathers below it, 4px and 7px off the title (board-skin.md §9). */
.board-eyebrow { margin: 0 0 0.25rem; color: var(--board-dim); font-size: var(--board-size-meta); }
.board-subtitle { margin: 0.4375rem 0 0; color: var(--board-dim); font-size: var(--board-size-meta); }
/*
 * The head's actions (`settings.writeButton: 'head'`, production's `.page-actions`): the 글쓰기 link
 * on the board name's own line, at its right. The head becomes a two-column grid — the title, the
 * count and the description keep the left column — and the actions take the title's row, centred on
 * it. On a phone the head is already that grid (the 37.5rem block below) and the search button
 * stands beside the link inside the actions.
 */
.board-head.head-write > .board-head-actions { margin-left: auto; align-self: center; }
.board-head-actions { display: flex; align-items: center; gap: var(--board-space-2); }

/* The listing: 말머리 as a row of words, then the table under the region's 2px rule, then the foot. */
.board-list { padding: 0; }
.board-list .board-grid { padding-top: var(--board-space-4); padding-bottom: var(--board-space-2); border-top: 2px solid var(--board-ink); }

/* 말머리: a row of 14px words, the current one in the text colour at 700, the rest in the secondary grey (C). */
.gb-categories ul { display: flex; flex-wrap: wrap; gap: 2px 0.875rem; list-style: none; margin: 0; padding: var(--board-space-1) 0 var(--board-space-3); border: 0; }
.gb-categories a { display: block; padding: 0; font-size: var(--board-size-ui); font-weight: var(--board-weight-normal); color: var(--board-mid); }
.gb-categories a:hover { text-decoration: none; color: var(--board-text); }
.gb-categories a[aria-current] { color: var(--board-text); font-weight: var(--board-weight-bold); }
/* With orders to offer, the 말머리 and the orders share that row, the orders at its right end (C-desktop); on a phone the orders wrap under the words. */
.board-list-bar { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--board-space-4); }
.board-list-bar > .gb-categories { flex: 1 1 auto; min-width: 0; }
.board-list-bar > .gb-listing-sorts { margin-left: auto; padding: var(--board-space-1) 0 var(--board-space-3); }

.board-table { width: 100%; border-collapse: collapse; table-layout: auto; border-top: 2px solid var(--board-ink); }
.board-table th { padding: 0.625rem var(--board-space-1); border-bottom: 1px solid var(--board-line); background: none; color: var(--board-dim); font-size: var(--board-size-caption); font-weight: var(--board-weight-normal); text-align: center; white-space: nowrap; }
.board-table td { padding: 0.625rem var(--board-space-1); border-bottom: 1px solid var(--board-hair); text-align: center; white-space: nowrap; vertical-align: middle; font-size: var(--board-size-meta); font-variant-numeric: tabular-nums; }
.board-table .col-title { text-align: left; white-space: normal; width: 100%; color: var(--board-text); font-size: calc(var(--board-size-ui) + var(--board-text-step)); font-weight: var(--board-weight-normal); }
/* C's 제목 head sits on the title's left edge like the titles under it; the others are centred. */
.board-table th.col-title { text-align: left; color: var(--board-dim); font-size: var(--board-size-caption); font-weight: var(--board-weight-normal); }
/* These are the data cells' own faces; scoped to td so a column's header stays the uniform th every other header is — one size, one dim grey, centred (production draws it so). */
.board-table td.col-no, .board-table td.col-views, .board-table td.col-score, .board-table td.col-date { color: var(--board-dim); font-size: var(--board-size-meta); font-variant-numeric: tabular-nums; }
/* 조회 and 추천 are the column heads' words; the table already carries them, so the cells keep their numbers here and the label is the phone's own (§2). */
.board-table .col-label { display: none; }
.board-table td.col-category, .board-table td.col-category a { color: var(--board-dim); font-size: var(--board-size-meta); }
.board-table td.col-board a { color: var(--board-mid); font-size: var(--board-size-meta); font-weight: var(--board-weight-normal); }
/* `listBoard: 'number'`: the board name stands in the number cell, in the column cell's own face (the legacy /all row did the same). */
.board-table td.col-no a.row-board { color: var(--board-mid); font-size: var(--board-size-meta); font-weight: var(--board-weight-normal); }
/* …and on a phone it moves above the title; on a wide screen the number cell already says it. */
.board-table a.row-board-tag { display: none; }
.board-table td.col-author { max-width: 9rem; overflow: hidden; text-overflow: ellipsis; color: var(--board-text); font-size: var(--board-size-meta); }
.board-table tr.row:hover td { background: var(--board-tint); }
/* The post a listing is drawn under (tr.is-current, skin-api.md §3s): a deeper tint that reads as the current row. The row:hover rule above outranks a bare tr.is-current td, so hover repeats the same tint rather than wiping it. */
.board-table tr.is-current td, .board-table tr.is-current.row:hover td { background: var(--board-tint-2); }
.board-list .board-table tr:last-child td { border-bottom-color: var(--board-line); }
/* A 공지 row sits on the panel fill with its title at 600 (C). */
.row-notice td { background: var(--board-notice); }
.row-notice .row-title { font-weight: 600; }
.row-title { display: inline; }
/* A list row's cover, when the board asked for one (schema/spaces.ts): a small box beside the title, so a row without one is exactly the row it was. */
.title-row { display: flex; align-items: center; gap: var(--board-space-2); min-width: 0; }
.title-main { min-width: 0; }
.title-row .gb-row-thumb { margin-left: auto; }
.gb-row-thumb { display: block; width: 42px; height: 30px; flex: 0 0 42px; overflow: hidden; background: var(--board-tint); border: 0; border-radius: var(--board-radius-s); }
.gb-row-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* The comment count rides the title as [n] in the accent, 13px at 600 (C). */
.row-comments { color: var(--board-count); font-size: var(--board-size-meta); font-weight: 600; margin-left: var(--board-space-1); }
.row-comments:hover { text-decoration: none; }
/* The 공지 mark is the word in the accent at 700, no pill (C's 공지 column). */
.mark-notice { display: inline-block; padding: 0; color: var(--board-accent-text); font-size: var(--board-size-meta); font-weight: var(--board-weight-bold); line-height: var(--board-leading-ui); margin-right: var(--board-space-2); }
/* 해결: a question that has settled on an answer (`item.solved`). The notice mark's frame, but quiet — the informational blue rather than the alert ink, normal weight — so the two never read as one (board-skin.md §2). */
.mark-solved { display: inline-block; padding: 0 var(--board-space-2); border: 1px solid var(--board-rule); border-radius: var(--board-radius-s); color: var(--board-mid); font-size: var(--board-size-caption); font-weight: var(--board-weight-normal); line-height: var(--board-leading-ui); vertical-align: 1px; margin-right: var(--board-space-2); }
.mark-new { color: var(--board-new); font-size: var(--board-size-caption); font-weight: var(--board-weight-bold); margin-left: var(--board-space-1); vertical-align: 2px; }
.row-snippet { margin: var(--board-space-1) 0 0; color: var(--board-dim); font-size: var(--board-size-meta); white-space: normal; }
.board-table .row-empty td { padding: var(--board-empty-pad); color: var(--board-dim); text-align: center; }
.gb-badge { display: inline-block; margin-right: var(--board-space-1); padding: 0 var(--board-space-2); border: 1px solid var(--board-rule); border-radius: var(--board-radius-s); color: var(--board-mid); font-size: var(--board-size-caption); font-weight: var(--board-weight-normal); line-height: var(--board-leading-ui); vertical-align: 1px; }
.gb-badge.tone-info { border-color: var(--board-ink); color: var(--board-text); }
.gb-badge.tone-warning, .gb-badge.tone-danger { border-color: var(--board-danger); color: var(--board-danger); }
/* 공지 is one mark wherever it is drawn: the board list writes it as `.mark-notice`, Core's badge path as `.gb-badge-notice`. The member's list carries no tone class, so the filled accent pill is repeated here (board-skin.md §2). */
.gb-badge.gb-badge-notice { border-color: transparent; padding: 0; background: none; color: var(--board-accent-text); font-weight: var(--board-weight-bold); }
/* A plugin's short fact on a row (`listing.row.meta`): a small hairline badge after the title and its count, monochrome like the board's own badges and quieter than them — dim words on a light rule, never a filled pill (board-skin.md §2). */
.row-meta { margin-left: var(--board-space-1); }
.row-meta > .gb-slot { display: inline-block; margin-left: var(--board-space-1); padding: 0 var(--board-space-1); border: 1px solid var(--board-line); border-radius: var(--board-radius-s); color: var(--board-dim); font-size: var(--board-size-caption); font-weight: var(--board-weight-normal); line-height: var(--board-leading-ui); vertical-align: 1px; white-space: nowrap; }
.row-meta > .gb-slot:first-child { margin-left: 0; }
.row-meta a { color: inherit; }
/* A pinned widget's `notice` display (site-composition.md §2, board-skin.md §9): the notices as one slim strip of rows in a card, the 공지 mark leading each title. The mark keeps its `.mark-notice` face above; the row is the link, so the whole line is clickable. */
.notice-strip { list-style: none; margin: 0; padding: 0; border-bottom: 1px solid var(--board-line); }
.notice-strip li + li { border-top: 1px solid var(--board-hair); }
.notice-strip a { display: flex; align-items: center; gap: 0.75rem; min-height: 2.75rem; padding: 0.5rem 0; color: var(--board-text); font-size: var(--board-size-ui); text-decoration: none; }
.notice-strip span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--board-weight-bold); line-height: 1.6; }
.notice-strip a:hover span { text-decoration: underline; }
/* In the strip the mark leads the row in the accent; the row's gap spaces it, so the list's trailing margin goes. */
.notice-strip .mark-notice { flex-shrink: 0; margin-right: 0; line-height: 1.6; }

/*
 * 사진 게시판 (board-skin.md §8): the same board, arranged as a grid, for the two layouts a table
 * cannot hold. Four columns of 4:3 thumbnails, two on a phone with the summary dropped — the shape
 * the Korean gallery boards this was measured against have. No card chrome: the page is hairlines
 * on white, and a border around every cell lays a second grid over the one the images already make.
 */
.board-grid { display: grid; gap: var(--board-space-6) var(--board-space-4); list-style: none; margin: 0; padding: var(--board-space-3) 0 0; }
.grid-gallery { grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); }
.grid-cards { grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); }
.board-grid .cell { display: flex; flex-direction: column; gap: var(--board-space-1); min-width: 0; }
/* The box is there before the bytes are: a grid that reflows row by row as its images land is worse than a plain square. */
.cell-cover { display: block; width: 100%; background: var(--board-tint); border-radius: var(--board-radius-s); overflow: hidden; }
.grid-gallery .cell-cover { aspect-ratio: 4 / 3; }
.grid-cards .cell-cover { aspect-ratio: 16 / 9; }
.cell-cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
.cell-head { margin: 2px 0 0; font-size: var(--board-size-ui); line-height: var(--board-leading-tight); }
.cell-title { font-weight: var(--board-weight-bold); }
.cell-notice .cell-title { font-weight: var(--board-weight-bold); }
.cell-summary { margin: 0; color: var(--board-dim); font-size: var(--board-size-meta); line-height: var(--board-leading-ui); }
/* A card's excerpt stops at two lines, so a long post does not stretch its card past the rest of the row. */
.grid-cards .cell-summary { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
/* Cards in one widget row share their title, excerpt and meta baselines (noriter-186). */
.grid-cards .cell-head { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; min-height: calc(2em * var(--board-leading-tight)); }
.grid-cards .cell-summary { min-height: calc(2em * var(--board-leading-ui)); }
.grid-cards .cell-meta { margin-top: auto; }
.grid-cards .cell-counts { flex-basis: 100%; margin-left: 0; }
.cell-meta { display: flex; flex-wrap: wrap; gap: 0 var(--board-space-2); margin: 2px 0 0; color: var(--board-dim); font-size: var(--board-size-meta); font-variant-numeric: tabular-nums; }
.cell-author { color: var(--board-mid); max-width: 8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cell-counts { margin-left: auto; }
/* The current card in a grid, where a listing is drawn under a post: the table paints its whole row, and a grid has no row, so the same deeper tint goes on the cell and bleeds by a pad through the shadow the phone's table row also uses — no width taken, so no phone overflows. */
.board-grid .cell.is-current { background: var(--board-tint-2); border-radius: var(--board-radius-s); box-shadow: 0 0 0 var(--board-space-2) var(--board-tint-2); }
.grid-empty { padding: var(--board-empty-pad); text-align: center; color: var(--board-dim); }
/*
 * 사진 게시판 as framed cards (`settings.gridCard: framed`, board-skin.md §9): production's photo
 * boards put the same cell on a bordered card with the words under the picture rather than beside
 * it. Four across, the cover flush to the card's top corners, and the current post's tint a
 * background on the card — the plain cell's bleached shadow would spill over the border here.
 */
.grid-framed { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.grid-framed .cell { gap: 0; background: var(--board-bg); border: 1px solid var(--board-line); border-radius: var(--board-radius); overflow: hidden; }
.grid-framed .cell-cover { aspect-ratio: 4 / 3; border-radius: 0; }
.grid-framed .cell-body { display: flex; flex: 1 1 auto; flex-direction: column; padding: 0.45rem 0.6rem 0.6rem; }
.grid-framed .cell-author { color: var(--board-dim); font-size: var(--board-size-meta); }
.grid-framed .cell-head { margin: 2px 0; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--board-ink); font-size: calc(1rem + var(--board-text-step)); font-weight: 500; }
.grid-framed .cell-title { font-weight: 500; }
/* The notice card's excerpt (production's gallery-card > p): the muted meta line the plain cell's summary already is, clamped to three lines on its own spacing. The phone's 47.5rem block drops it with every other summary. */
.grid-framed .cell-summary { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; margin: 0.35rem 0; line-height: 1.45; }
.grid-framed .cell-stats { display: flex; gap: 0.5rem; margin: auto 0 0; padding-top: 0.5rem; color: var(--board-dim); font-size: var(--board-size-meta); font-variant-numeric: tabular-nums; }
.grid-framed .cell-stats .cell-stat { display: inline-flex; align-items: center; gap: 0.2rem; }
.grid-framed .cell-stats svg { flex: none; width: 0.8125rem; height: 0.8125rem; }
.grid-framed .cell.is-current { background: var(--board-tint-2); border-radius: 0.4rem; box-shadow: none; }
/* A home widget's cards are a strip of small thumbnails, not a board's page: six across the 1140px column, three on a phone. */
.gb-widget .grid-cards { grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); gap: var(--board-space-4) var(--board-space-3); }
.gb-widget .grid-cards .cell-cover { aspect-ratio: 4 / 3; }
/* The gallery and card grids go two across at production's tablet line (760px), not the phone one — a 761px tablet keeps four. */
@media (max-width: 47.5rem) {
  .grid-gallery, .grid-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--board-space-5) var(--board-space-3); }
  .gb-widget .grid-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--board-space-4) var(--board-space-2); }
  /* A framed gallery is two across there too, at production's own 8.8px gap. A half-width card cuts most titles at a few words, so there the title takes two lines, and the icon row sits on the card's floor so a row of cards ends level. */
  .grid-framed { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.55rem; }
  .grid-framed .cell-head { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal; line-height: var(--board-leading-tight); min-height: calc(2em * var(--board-leading-tight)); }
  /* Production's below(tablet) also steps the card body in to .5rem and the stat row to .4rem. */
  .grid-framed .cell-body { padding-inline: 0.5rem; }
  .grid-framed .cell-stats { gap: 0.4rem; }
  .cell-head { font-size: var(--board-size-ui); }
  .cell-summary, .grid-framed .cell-summary { display: none; }
}
/* Under 400px (production's xs) the framed grid tightens further: a 6.4px gap, a closer stat row, smaller icons. */
@media (max-width: 25rem) {
  .grid-framed { gap: 0.4rem; }
  .grid-framed .cell-stats { gap: 0.3rem; }
  .grid-framed .cell-stats svg { width: 0.75rem; height: 0.75rem; }
}

.board-foot { position: relative; display: flex; align-items: center; justify-content: center; min-height: 2.5rem; padding: var(--board-space-4) 0 0; }
.board-foot .btn-write { position: absolute; right: 0; top: var(--board-space-4); }
/*
 * The phone's write FAB (`settings.writeFab`, production's MobileWriteButton): nothing on a wide
 * screen; under production's desktop line (60rem, its `below(desktop)`) whatever carries the inline
 * 글쓰기 — the `has-write-fab` page or card — drops it, and one fixed 56px pencil takes its place at
 * the lower right: the accent at 72% over a 5px blur, production's own border, shadow and safe-area
 * insets. z-index 35 is production's `--z-float-action`, under the header's 40 so the sticky band
 * still wins where they could meet.
 */
.write-fab { display: none; }
@media (max-width: 60rem) {
  .has-write-fab .btn-write { display: none; }
  .write-fab { position: fixed; z-index: 35; right: max(1.125rem, env(safe-area-inset-right)); bottom: calc(5rem + env(safe-area-inset-bottom)); display: grid; place-items: center; width: 3rem; height: 3rem; color: var(--board-on-primary); background: var(--board-primary); border: 0; border-radius: 999px; box-shadow: 0 0.25rem 0.75rem rgb(0 0 0 / 0.18); transition: background 0.15s ease, transform 0.15s ease; }
  .write-fab:hover, .write-fab:focus-visible { background: var(--board-primary-hover); }
  .write-fab:active { transform: translateY(1px); }
  .write-fab:focus-visible { outline: 2px solid var(--board-ink); outline-offset: 3px; }
}
/* The pager: one nav holding the desktop strip and the phone's step bar, of which the media query at the foot shows one. The strip is a row of 37.6px cells — 16px type, a 0.2rem gap, a tint on hover, the accent square under the reader at the same weight as the numbers — with the arrows beside the numbers, greyed where they lead nowhere. (docs/skin-api.md §3w) */
.gb-pagination { display: flex; justify-content: center; margin: 0; }
.gb-pagination-strip { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 2px; }
.gb-pagination-step { display: none; }
.gb-pagination-strip > a, .gb-pagination-strip > span { display: inline-flex; align-items: center; justify-content: center; min-width: 2rem; height: 2rem; border: 1px solid transparent; border-radius: var(--board-radius-s); color: var(--board-text); font-size: var(--board-size-ui); font-weight: var(--board-weight-normal); font-variant-numeric: tabular-nums; }
.gb-pagination-strip a:hover { text-decoration: none; background: var(--board-tint); }
/* An arrow carries a word beside its icon, so the two sit a hair apart; the whole cell tints on hover, like a button. */
.gb-pagination-strip > .gb-pagination-nav { gap: var(--board-space-1); padding: 0 var(--board-space-2); color: var(--board-mid); }
.gb-pagination-nav .gb-icon { flex: none; }
.gb-pagination-strip a.gb-pagination-nav:hover { background: var(--board-tint); }
.gb-pagination-strip span[aria-current] { border-color: var(--board-ink); color: var(--board-text); font-weight: var(--board-weight-bold); }
/* An arrow at the end of the walk is drawn but dead: dim, and no hover the span never had anyway. */
.gb-pagination-strip span[aria-disabled] { color: var(--board-dim); opacity: 0.6; }
.gb-pagination.gb-more a { border: 0; }
/* Not dead CSS: .gb-pagination above is display: flex, which outranks the browser's own [hidden], and more's island hides the numbered strip with it — so a site on more shows the numbers and the link together without this (skin-api.md §3s). */
.gb-pagination[hidden] { display: none; }
/* The more cell: one hairline, wider than a number and a little taller. Not the accent button — that is 글쓰기, beside it. */
.gb-pagination.gb-more a.gb-more { display: inline-flex; align-items: center; justify-content: center; width: 12rem; height: 2.25rem; border: 1px solid var(--board-rule); border-radius: var(--board-radius); color: var(--board-text); font-size: var(--board-size-meta); }
@media (pointer: coarse) {
  .gb-pagination-strip > a,
  .gb-pagination.gb-more a.gb-more,
  .gb-pagination-next,
  .gb-pagination-line a,
  .gb-pagination-jump input {
    min-height: 2.75rem;
  }
  .gb-pagination-strip > a,
  .gb-pagination-line a {
    min-width: 2.75rem;
  }
}

/* The board's search: scope, query and 검색 at 36px, outlined like every control but the screen's one filled button (C). */
.board-search { display: flex; align-items: center; justify-content: flex-start; gap: 0.375rem; margin: 0 0 var(--board-space-4); padding: 0; }
.board-search select { flex: none; width: 8.5rem; }
.board-search input[type="search"] { flex: 0 1 13.75rem; min-width: 0; width: auto; }
.board-search button[type="submit"]:not(.gb-link):not(.gb-reaction):not(.gb-danger) { background: var(--board-surface); border-color: var(--board-rule); color: var(--board-text); font-size: var(--board-size-ui); font-weight: var(--board-weight-normal); }
.board-search button[type="submit"]:not(.gb-link):not(.gb-reaction):not(.gb-danger):hover { background: var(--board-tint); border-color: var(--board-rule); color: var(--board-text); }

/* The child-board tabs (board-skin.md §9): production's chips under the search card — 전체 for the group and one chip per child — 45px on the search controls' own 0.4rem radius, off the skin's scale, so literals like theirs. The card gives up most of its foot when the chips follow it, so the two read as one block. */
.board-chips { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0 0 var(--board-space-5); }
.board-search:has(+ .board-chips) { margin-bottom: var(--board-space-3); }
.board-chips .chip { display: inline-flex; align-items: center; min-height: 2.125rem; padding: 0 0.75rem; border: 1px solid var(--board-rule); border-radius: var(--board-radius); background: var(--board-surface); color: var(--board-mid); font-size: var(--board-size-meta); font-weight: var(--board-weight-normal); line-height: 1.4; text-decoration: none; }
.board-chips .chip:hover { background: var(--board-tint); }
/* The chip whose board the reader is on: production fills it, so it reads as the state rather than as a link — the whole group's edge when no child is current. */
.board-chips .chip[aria-current="page"] { border-color: var(--board-ink); color: var(--board-text); font-weight: var(--board-weight-bold); }

.board-side { min-width: 0; }
.box-rows { list-style: none; margin: 0; padding: 0; }
.box-rows li { display: flex; align-items: baseline; gap: var(--board-space-2); padding: 0.5625rem 0; border-bottom: 1px solid var(--board-hair); font-size: var(--board-size-ui); }
.box-row { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: var(--board-space-1); }
/* A row title is a list title: `large` gives it the listing's extra step (noriter-174). */
.box-row-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: calc(1em + var(--board-text-step)); }
.box-row .row-comments { margin-left: 0; flex-shrink: 0; }
.box-row .mark-new, .box-row .mark-notice { flex-shrink: 0; }
.box-row-date { flex-shrink: 0; color: var(--board-dim); font-size: var(--board-size-byline); font-variant-numeric: tabular-nums; }
.box-empty { margin: 0; padding: var(--board-space-3) 0 var(--board-space-4); color: var(--board-dim); font-size: var(--board-size-meta); }
.box-more { flex: none; margin: 0 0 0 auto; padding: 0; max-width: 100%; font-size: var(--board-size-caption); }
.box-more a { color: var(--board-dim); }

.gb-search .board-title { margin: 0 0 var(--board-space-4); }
.gb-search .gb-search-form { display: flex; gap: var(--board-space-2); margin: 0 0 var(--board-space-2); }
.gb-search .gb-search-form input[type="search"] { flex: 1; min-width: 0; max-width: 26rem; }
.gb-search .gb-sort { color: var(--board-dim); font-size: var(--board-size-meta); margin: 0 0 var(--board-space-3); }
.gb-search .gb-sort a { color: var(--board-text); text-decoration: underline; text-underline-offset: 0.15em; }
.gb-search .gb-empty { padding: var(--board-space-8) 0; color: var(--board-dim); text-align: center; }

@media (max-width: 60rem) {
  .board-page:has(> .board-side) { grid-template-columns: 1fr; }
}
/* The list head and its collapsible search drop at production's mobile line (600px); the table and the pager keep their own, wider one below. */
@media (max-width: 37.5rem) {
  /* The head is one row — the title and its count at the left, the search button at the right, centred on them both (production puts it there) — and the description falls to a line of its own under it. */
  .board-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: var(--board-space-3); }
  .board-title, .board-count { grid-column: 1; }
  .board-desc { grid-column: 1 / -1; }
  /* The tag head draws no search button to make room for, so it keeps the three-line stack the wide screen gives it instead of the button's row. */
  .board-head.tag-head { display: block; }
  /* The head's search button: the header's round 40px idiom, before its own phone rule halves it (the shell's parts, above). */
  .board-search-open { display: inline-flex; grid-column: 2; grid-row: 1 / span 2; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; border: 0; border-radius: var(--board-radius); background: none; color: var(--board-ink); cursor: pointer; }
  .board-search-open:hover { background: var(--board-tint); color: var(--board-text); }
  /* The keyboard's focus lands on the switch; the ring has to land on the button it stands for. */
  .board-search-switch:focus-visible ~ .board-head .board-search-open { outline: 2px solid var(--board-ink); outline-offset: 2px; }
  /* The form belongs to the button: it stays shut until the button is tapped, and the sibling selector reads the switch with no script. */
  .board-search-switch:not(:checked) ~ .board-search { display: none; }
  /* Keep the query readable: the scope occupies its own row rather than leaving the input a few characters wide. */
  .board-search { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
  .board-search select { grid-column: 1 / -1; width: 100%; }
  .board-search input[type="search"] { width: 100%; min-width: 0; }
}

/* The list table and the foot's pager drop at production's tablet-narrow line (700px): the head row hides, each row becomes a card, and the numbered strip gives way to the step bar. */
@media (max-width: 43.75rem) {
  .board-table, .board-table tbody { display: block; }
  .board-table thead { display: none; }
  /* A row is no longer a grid of named areas: the title takes its own line, the rest reads as one meta line under it. */
  /* The meta line's own words sit closer than the row's other gaps (production's 9~10px); no token lands there, so a literal narrows just this one. */
  .board-table tr { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.375rem; row-gap: 2px; min-height: 3.375rem; padding: var(--board-space-2) 0; border-bottom: 1px solid var(--board-line); overflow: hidden; }
  .board-table td { display: block; padding: 0; border: 0; text-align: left; white-space: normal; }
  /* A tinted row is tinted as a row: on a phone its cells are separate boxes, so a cell's own tint patches the row. Two side shadows carry the row's tint out to the card's edges, where the desktop cell padding took it. */
  /* A tinted row is tinted as a row, carried out to the window's edges by two side shadows the width of the shell's gutter. */
  .board-table tr.row-notice { min-height: 2.75rem; background: var(--board-notice); box-shadow: calc(-1 * var(--board-gap)) 0 0 var(--board-notice), var(--board-gap) 0 0 var(--board-notice); }
  .board-table tr.is-current { background: var(--board-tint-2); box-shadow: calc(-1 * var(--board-gap)) 0 0 var(--board-tint-2), var(--board-gap) 0 0 var(--board-tint-2); }
  .board-table tr.row-notice td, .board-table tr.is-current td, .board-table tr.is-current.row:hover td { background: none; }
  .board-table .col-title { order: 1; flex-basis: 100%; width: auto; font-size: var(--board-size-head); }
  /* The order the meta line reads in: 말머리, 글쓴이, 날짜, 조회, 추천 — the table's own column order is not it (the header keeps the table's). 게시판 no longer rides this line; its own order: -1 rule below stands it over the title instead (production's own layout). */
  .board-table .col-no { order: 2; }
  .board-table .col-category { order: 2; }
  .board-table .col-author { order: 4; }
  .board-table .col-date { order: 5; }
  .board-table .col-views { order: 6; }
  .board-table .col-score { order: 7; }
  .row:not(.row-notice) .col-no { display: none; }
  .board-table .col-no, .board-table .col-category, .board-table .col-score { color: var(--board-dim); font-size: var(--board-size-caption); }
  .board-table .col-category a { font-size: var(--board-size-caption); }
  /* 날짜·조회 keep the meta grey but drop to production's 13px; td-scoped like col-author below, since the desktop rule (board-skin.md §9) is td-scoped too and would otherwise outrank a bare .col-date/.col-views here. */
  .board-table td.col-date, .board-table td.col-views { font-size: var(--board-size-byline); }
  /* 글쓴이 reads in the meta grey with the rest of the line (C); td-scoped so it outranks the desktop rule. */
  .board-table td.col-author { color: var(--board-dim); font-size: var(--board-size-byline); }
  /* The meta line's words part by a dot, the line's own separator (C's mobile row). */
  .board-table tr:not(.row-notice) td:is(.col-category, .col-author, .col-date, .col-views, .col-score):not(:empty) ~ td:is(.col-author, .col-date, .col-views, .col-score)::before { content: "·"; margin-right: 0.375rem; color: var(--board-dim); }
  /* Production stands the board name over the title as its own bold accent line, not a fourth meta word — order: -1 pulls it ahead of even the title, and flex-basis: 100% gives it the line to itself. td-scoped to outrank the desktop td.col-board a rule below (its anchor keeps its own colour there, board-skin.md §9), so the anchor inherits here instead. */
  .board-table .col-board { order: -1; flex-basis: 100%; width: auto; color: var(--board-mid); font-size: var(--board-size-caption); font-weight: var(--board-weight-bold); }
  .board-table td.col-board a { color: inherit; font-size: inherit; font-weight: inherit; }
  /* With `listBoard: 'number'` there is no 게시판 cell to lift: the tag inside the title takes the same bold accent line over it (production's mobile board tag). */
  .board-table a.row-board-tag { display: block; margin-bottom: 0.05rem; color: var(--board-mid); font-size: var(--board-size-caption); font-weight: var(--board-weight-bold); }
  /* 조회 and 추천 are the table's own column heads; on a phone the line has none, so each cell says its word — a step in from its number, and the gap between the two is the row's own column gap. */
  .board-table .col-label { display: inline; margin-right: var(--board-space-1); }
  /* A 추천 0 on the phone's meta line is noise beside the views; the desktop column keeps its 0 so the column reads straight down. */
  .board-table .col-score.is-zero { display: none; }
  /* The thumbnail grows on a phone, where the fixed columns are gone and the row has the width for it (the legacy row did the same). */
  .gb-row-thumb { width: 54px; height: 54px; flex-basis: 54px; }
  /* A row with a thumbnail keeps the same left edge as one without: the picture steps out of flow into the row's right padding, level with the title line, and the row keeps at least the picture's height. */
  .board-table tr:has(.gb-row-thumb) { position: relative; min-height: calc(54px + 2 * var(--board-space-3)); padding-right: calc(54px + var(--board-space-3)); }
  .board-table tr:has(.gb-row-thumb) .gb-row-thumb { position: absolute; top: var(--board-space-3); right: 0; margin: 0; }
  /* The pinned row's badge is Core's number cell. A flex item can neither sit before the title nor leave the title's own box, so this row drops to a block: the badge floats at the title's edge, and the title, the meta line and the snippet stack as ordinary blocks and inlines. */
  .board-table tr.row-notice { display: block; }
  .board-table tr.row-notice .col-no, .board-table tr.row-notice .col-title, .board-table tr.row-notice .title-row { display: contents; }
  .board-table tr.row-notice .mark-notice { float: left; margin: 0 var(--board-space-2) 0 0; }
  .board-table tr.row-notice .title-main { display: block; }
  .board-table tr.row-notice .col-category, .board-table tr.row-notice .col-board, .board-table tr.row-notice .col-author, .board-table tr.row-notice .col-date, .board-table tr.row-notice .col-views, .board-table tr.row-notice .col-score { display: inline-block; margin-right: var(--board-space-3); }
  .board-table .row-empty td { flex-basis: 100%; text-align: center; }
  /* On a phone the rule rides the row, not its cells: the card's own edge closes the last one. */
  .board-list .board-table tr:last-child { border-bottom-color: var(--board-line); }
  .board-foot { flex-direction: column; gap: var(--board-space-3); }
  .board-foot .btn-write { position: static; transform: none; }
  /* On a phone the strip's eleven cells no longer fit: the step bar takes its place — one full-width accent button on to the next page, and under it a right-aligned row of 처음 · 이전 · a number box · 다음, the same two steps shrunk to 13px icons. Same two addresses, laid for a thumb. */
  /* The foot centres its column, which would shrink the pager to its text: stretched, the button can fill the card. */
  nav.gb-pagination { align-self: stretch; }
  nav.gb-pagination .gb-pagination-strip { display: none; }
  nav.gb-pagination .gb-pagination-step { display: flex; width: 100%; flex-direction: column; gap: 0.7rem; }
  .gb-pagination-next { display: inline-flex; align-items: center; justify-content: center; width: 100%; min-height: 2.75rem; padding: var(--board-space-1) var(--board-space-4); border: 1px solid var(--board-rule); border-radius: var(--board-radius); background: var(--board-surface); color: var(--board-text); font-size: var(--board-size-ui); font-weight: var(--board-weight-bold); }
  .gb-pagination-next:hover { background: var(--board-tint); color: var(--board-text); text-decoration: none; }
  .gb-pagination-line { display: flex; align-items: center; justify-content: flex-end; gap: 0.35rem; margin: 0; font-size: var(--board-size-caption); font-variant-numeric: tabular-nums; }
  .gb-pagination-line a, .gb-pagination-line span { display: inline-flex; align-items: center; gap: 0.15rem; height: 2rem; padding: 0 0.4rem; border-radius: 0.3rem; color: var(--board-dim); }
  .gb-pagination-line .gb-icon { flex: none; width: 0.8125rem; height: 0.8125rem; }
  .gb-pagination-line a:hover { color: var(--board-text); }
  /* The number box the reader types a page into: production's 3.8rem, on the caption size's own 2rem height. */
  .gb-pagination-jump input { --board-control-h: 2rem; --board-control-pad-y: 0; --board-input-pad-x: 0.3rem; --board-control-radius: 0.3rem; width: 3.8rem; color: var(--board-text); font-size: var(--board-size-ui); text-align: center; }
  /* No stepper: a phone's spinner sits over the digits, and the box is for typing a number. */
  .gb-pagination-jump input[type="number"] { appearance: textfield; }
  .gb-pagination-jump input[type="number"]::-webkit-outer-spin-button, .gb-pagination-jump input[type="number"]::-webkit-inner-spin-button { appearance: none; margin: 0; }
  /* The block as well as its link: in the foot's column the block is only as wide as its text, so a width on the link alone has nothing to fill. */
  .gb-pagination.gb-more, .gb-pagination.gb-more a.gb-more { width: 100%; }
}

/* No production line names this one, so it keeps the skin's own 47.99rem: a notice strip steps in by a phone's pad, as the search card does. */
@media (max-width: 47.99rem) {
  .notice-strip a { padding: 0.5rem 0.8rem; }
}
