
.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 name over its count, on production's 36px at weight 600 — a weight the scale does not carry, so a literal, as the menu link already is (board-skin.md §9). */
.board-head { padding: 0 0 var(--board-space-4); }
.board-title { font-size: var(--board-size-title); 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: 2.9rem; padding-top: 2rem; border-top: 2px solid var(--board-line); }
/* Inside it the head is a section's own h2, not the page's h1: production drops it to 1.25rem. */
.board-section .board-title { font-size: 1.25rem; 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: var(--board-space-2) 0 0; color: var(--board-dim); font-size: var(--board-size-ui); font-variant-numeric: tabular-nums; }
.board-desc { 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 { padding: 1.1rem; margin: 0 0 0.6875rem; }
/* 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 { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: var(--board-space-3); }
.board-head.head-write > * { grid-column: 1; }
.board-head.head-write > .board-head-actions { grid-column: 2; grid-row: 1; align-self: center; }
.board-head-actions { display: flex; align-items: center; gap: var(--board-space-2); }

/* The card the listing sits on: 말머리 tabs, the table or grid, and the foot, all inside one surface. */
.board-list { padding-top: 0; padding-bottom: var(--board-space-2); }
.board-list .gb-categories ul { border-bottom: 0; }
.board-list .board-grid { padding-top: var(--board-card-pad); padding-bottom: var(--board-space-2); }

/* 말머리: text tabs on a hairline, the current one underlined — the menu's idiom, one size down. */
.gb-categories ul { display: flex; flex-wrap: wrap; gap: 0 var(--board-space-4); list-style: none; margin: 0; padding: 0; border-bottom: 1px solid var(--board-line); }
.gb-categories a { display: block; padding: var(--board-space-3) 0 var(--board-space-2); margin-bottom: -1px; border-bottom: 2px solid transparent; font-size: var(--board-size-ui); font-weight: var(--board-weight-normal); color: var(--board-dim); }
.gb-categories a:hover { text-decoration: none; color: var(--board-text); }
.gb-categories a[aria-current] { color: var(--board-accent-text); font-weight: var(--board-weight-bold); border-bottom-color: var(--board-accent); }

.board-table { width: 100%; border-collapse: collapse; table-layout: auto; }
.board-table th { padding: var(--board-space-2) var(--board-space-2); border-bottom: 1px solid var(--board-line); background: var(--board-surface); color: var(--board-dim); font-size: var(--board-size-caption); font-weight: 600; text-align: center; white-space: nowrap; }
.board-table td { padding: var(--board-space-3) var(--board-space-2); border-bottom: 1px solid var(--board-line); text-align: center; white-space: nowrap; vertical-align: middle; font-size: var(--board-size-ui); }
.board-table .col-title { text-align: left; white-space: normal; width: 100%; color: var(--board-text); font-size: var(--board-size-ui); font-weight: var(--board-weight-normal); }
/* The header cell is not a title cell: its word is centred — production centres 제목 with every other column — and keeps a th's own size, dim colour and weight (board-skin.md §9). */
.board-table th.col-title { text-align: center; color: var(--board-dim); font-size: var(--board-size-caption); font-weight: 600; }
/* 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 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-mid); 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: 0; }
/* A 공지 row is tinted with its own accent tint, not the hover tint, and its title keeps the row's normal weight — the mark already says what the row is (production draws it so). */
.row-notice td { background: var(--board-notice); }
.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; }
.gb-row-thumb { display: block; width: 42px; height: 30px; flex: 0 0 42px; overflow: hidden; background: var(--board-tint); border: 1px solid var(--board-line); 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 in the accent, at the title's own 16px and production's bold, in parentheses — (15), not the bracket idiom. */
.row-comments { color: var(--board-accent-text); font-size: var(--board-size-ui); font-weight: var(--board-weight-bold); margin-left: var(--board-space-1); }
.row-comments:hover { text-decoration: none; }
/* The 공지 mark is a small filled accent pill — white words on the accent (production: rgb(20, 108, 90), 4px radius, 1.6px/5.6px pad) — at normal weight, so it never reads as a title's emphasis (board-skin.md §2). */
.mark-notice { display: inline-block; padding: 0.1rem 0.35rem; border-radius: 4px; background: var(--board-accent); color: var(--board-on-accent); 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); }
/* 해결: 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-count); border-radius: var(--board-radius-s); color: var(--board-count); 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; background: var(--board-accent); color: var(--board-on-accent); }
/* 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; background: var(--board-surface); border: 1px solid var(--board-line); border-radius: 0.75rem; overflow: hidden; }
.notice-strip li + li { border-top: 1px solid var(--board-line); }
.notice-strip a { display: flex; align-items: center; gap: 0.5rem; min-height: 2.625rem; padding: 0.5rem 1.1rem; color: var(--board-text); font-size: 1rem; text-decoration: none; }
.notice-strip span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; line-height: 1.6; }
.notice-strip a:hover span { text-decoration: underline; }
/* In the strip the mark is production's warm notice pill (rgb(192, 86, 33), bold): above a tool it announces rather than labels a row, so it does not borrow the list's quiet accent. The row's gap spaces it, so the list's trailing margin goes. */
.notice-strip .mark-notice { flex-shrink: 0; margin-right: 0; background: rgb(192, 86, 33); font-weight: var(--board-weight-bold); 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); }
.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-surface); border: 1px solid var(--board-line); border-radius: 0.4rem; 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: 0.8125rem; }
.grid-framed .cell-head { margin: 2px 0; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--board-ink); font-size: 1rem; 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: 0.8125rem; 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; }
/* 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); }
  /* 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-3) 0; }
.board-foot .btn-write { position: absolute; right: 0; top: 50%; transform: translateY(-50%); }
/*
 * 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: 3.5rem; height: 3.5rem; color: var(--board-on-accent); background: color-mix(in srgb, var(--board-accent) 72%, transparent); border: 1px solid color-mix(in srgb, #fff 22%, transparent); border-radius: 50%; box-shadow: 0 0.35rem 1rem #0003; backdrop-filter: blur(5px); transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease; }
  .write-fab:hover, .write-fab:focus-visible { background: color-mix(in srgb, var(--board-accent) 88%, transparent); box-shadow: 0 0.45rem 1.1rem #0004; }
  .write-fab:active { transform: translateY(1px); background: var(--board-accent); box-shadow: 0 0.2rem 0.65rem #0003; }
  .write-fab:focus-visible { outline: 3px solid color-mix(in srgb, var(--board-accent) 35%, transparent); 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: 0.2rem; }
.gb-pagination-step { display: none; }
.gb-pagination-strip > a, .gb-pagination-strip > span { display: inline-flex; align-items: center; justify-content: center; min-width: 2.35rem; height: 2.35rem; border-radius: 0.4rem; color: var(--board-dim); font-size: var(--board-size-ui); font-weight: var(--board-weight-normal); font-variant-numeric: tabular-nums; }
.gb-pagination-strip a:hover { color: var(--board-text); }
/* 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-nav { gap: var(--board-space-1); padding: 0 0.55rem; }
.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] { background: var(--board-accent); color: var(--board-on-accent); font-weight: var(--board-weight-normal); }
/* 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); }
.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.4rem; border: 1px solid var(--board-line); color: var(--board-text); font-weight: var(--board-weight-bold); }
@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 is a toolbar under the heading: scope, query, submit. Its controls provide
 * their own boundaries; the results below are the surface that needs a card. */
.board-search { display: flex; align-items: center; gap: var(--board-space-2); margin: 0 0 var(--board-space-6); padding: 0; }
.board-search select { flex: none; width: 10rem; }
.board-search input[type="search"] { flex: 1 1 0; min-width: 0; width: auto; }
.board-search button { background: var(--board-accent); border-color: var(--board-accent); color: var(--board-on-accent); }
.board-search button:hover { background: var(--board-accent-hover); border-color: var(--board-accent-hover); color: var(--board-on-accent); }

/* 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; padding: 0.55rem 0.85rem; border: 1px solid var(--board-line); border-radius: 0.4rem; background: var(--board-surface); color: var(--board-ink); font-size: 1rem; font-weight: 700; line-height: 1.6; 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"] { background: var(--board-accent); border-color: var(--board-accent); color: var(--board-on-accent); }

.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: var(--board-space-2) 0; border-bottom: 1px solid var(--board-line); font-size: var(--board-size-ui); }
.box-row { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: var(--board-space-1); }
.box-row-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.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-meta); 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-meta); }
.box-more a { color: var(--board-dim); }
.box-more a::after { content: " ›"; }

.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.5rem; height: 2.5rem; border: 1px solid var(--board-line); border-radius: 50%; 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-accent); 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.6rem; row-gap: 2px; padding: var(--board-space-3) 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. */
  .board-table tr.row-notice { background: var(--board-notice); box-shadow: calc(-1 * var(--board-card-pad)) 0 0 var(--board-notice), var(--board-card-pad) 0 0 var(--board-notice); }
  .board-table tr.is-current { background: var(--board-tint-2); box-shadow: calc(-1 * var(--board-card-pad)) 0 0 var(--board-tint-2), var(--board-card-pad) 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; }
  /* 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-caption); }
  /* 글쓴이 reads in the accent, not the meta grey (production's dark green); td-scoped so it outranks the desktop rule's own --board-mid instead of losing to it by specificity. */
  .board-table td.col-author { color: var(--board-accent-text); font-size: var(--board-size-caption); }
  /* 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-accent-text); 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-accent-text); 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 is two columns: the picture steps out of flow into the row's left padding, so the title line opens level with the picture's top and the meta line follows it at the same edge, 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-left: calc(54px + var(--board-space-3)); }
  .board-table tr:has(.gb-row-thumb) .gb-row-thumb { position: absolute; top: var(--board-space-3); left: 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: 0; }
  .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.5rem; padding: var(--board-space-1) var(--board-space-4); border: 0; border-radius: 0.4rem; background: var(--board-accent); color: var(--board-on-accent); font-size: var(--board-size-ui); font-weight: var(--board-weight-bold); }
  .gb-pagination-next:hover { background: color-mix(in srgb, var(--board-accent) 88%, black); color: var(--board-on-accent); }
  .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; }
}
