/* deck.css — DRIFTDECK member deck panel (/deck/panel/), the hub's "Your deck" block and the
   portal-independent sign-in form.

   NEW FILE (no repo original). Loaded by default.hbs after screen.css: the .btn / .info-block /
   .warn-block / .card-status / .pf-kind / .sys-label / .blk-label primitives come from screen.css
   and are only sized (never recoloured) here. Every colour is a tokens.css variable, so html.light
   adapts by itself — with the one documented exception at the foot of this file.

   CLASS CONTRACT — this file is aligned to the vocabulary assets/js/deck-panel.js ACTUALLY emits
   (ROUND2-FINDINGS find:theme-ghost MAJOR / find:panel-js MINOR: the CSS and the JS had been
   written to two different vocabularies). The JS header is the contract; the JS was not renamed.
   The full emitted set, in the order the JS builds it:

     article.deck-tile[data-slug]            -- + .deck-tile--stub when the slug is unlisted
       span.pf-kind                          -- "// <codename>"
       h3                                    -- display name, NO class
       p.deck-tile-tagline
       div.deck-chips                        -- listed tiles only (a stub has no chips)
         span.deck-chip.st-live|st-beta|st-staged|st-prototype|st-proposed
         span.deck-chip.deck-chip--surface
         span.deck-chip.deck-chip--vis       -- owner-only modules
       div.deck-tile-actions
         a.btn[data-action=open]             -- route / hosted / external surfaces
         span.deck-local > span.muted + small.deck-surface-note   -- local surfaces
         button.btn.ghost[data-action=details|up|down]
         button.btn.ghost.deck-remove[data-action=remove]   -- a stub carries ONLY this one
       div.deck-tile-details[hidden]         -- listed tiles only
         p                                   -- description, NO class
         p.deck-codename-status

     section.deck-dialog-group > h4
       ul.deck-dialog-rows > li.deck-dialog-row
         span.deck-dialog-name · span.pf-kind · span.deck-chip.st-* · button.btn[data-action=add]
       p.deck-dialog-empty                   -- when a group has nothing to add

     #deck-status.is-ok|is-warn|is-error  (the element also carries class="deck-status")
     #deck-dialog-status.is-ok|is-warn|is-error  (class="deck-dialog-status") -- the dialog's own
       live region: a modal <dialog> makes everything outside it inert, so #deck-status alone
       never reaches assistive technology while the add dialog is open. deck-panel.hbs renders
       it; the JS creates it only if the template ever stops doing so.
     a.deck-signin                           -- the JS "session ended" link inside #deck-status
     button.deck-retry + small.deck-hint     -- the JS "signed in, but the deck service could
       not confirm your session" state, also inside #deck-status. A 401 no longer means "you
       are signed out": the JS asks the site's member API first and only says "session ended"
       when the site agrees. When the site says the reader IS a member, that state is shown
       instead — a Retry button and one line of hint, never a sign-in prompt.
     #deck-account-status.is-ok|is-warn|is-error  (class="deck-dialog-status") -- the account
       dialog's live region, same inert-modal reason as #deck-dialog-status.
     #deck-account-body > .deck-account-row (span.deck-account-label + span.deck-account-value)
                        > label.deck-account-field (span.deck-account-label + input.deck-account-input)
                        > .deck-account-actions (button.btn[data-account=save|signout]
                          + a.btn.ghost.deck-account-portal, rendered ONLY when the site's
                          embedded account widget is detected as loaded)
     #deck-grid[aria-busy="true"], #deck-dialog-list[aria-busy="true"] and
     #deck-account-body[aria-busy="true"] -- set while a call is in flight (the action
       controls are disabled at the same time)

   NAME COLLISION, on purpose: the JS emits an ANCHOR a.deck-signin, while ROUND2-SPEC R2-A names
   the new sign-in FORM form.deck-signin. Both rule sets below are element-qualified so neither can
   reach the other. Do not drop the element qualifier.

   Mobile-first: one column by default; the tile grid widens by itself (auto-fill). */

/* ---------- panel shell ---------- */
.deck-panel { margin: 1.5rem 0 2.5rem; }
/* [hidden] must beat any display the classes below set (#deck-empty, .deck-tile-details) */
.deck-panel [hidden], form.deck-signin [hidden] { display: none !important; }

.deck-toolbar {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.6rem 0.8rem; margin: 0 0 1rem;
}
.deck-toolbar h2 { margin: 0; font-size: 1.25rem; }
.deck-toolbar-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; width: 100%; }
@media (min-width: 640px) {
  .deck-toolbar-actions { width: auto; margin-left: auto; }
}

/* button/anchor .btn parity (find:theme-ghost MINOR). screen.css has no button reset and .btn
   sets neither line-height, font-weight nor cursor, so <button class="btn"> and <a class="btn">
   sitting side by side in .deck-toolbar / .deck-tile-actions / .deck-dialog-row render at
   different heights and the buttons keep the arrow cursor. One rule gives them one box. */
.deck-panel .btn, form.deck-signin .btn {
  line-height: 1.7; font-weight: 300; cursor: pointer;
}
.deck-panel button.btn, form.deck-signin button.btn {
  -webkit-appearance: none; appearance: none; border-radius: 0;
}

/* live region — one line of mono status. #deck-status carries class="deck-status" as well. */
.deck-status {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.08em;
  color: var(--muted); margin: 0 0 1rem;
}
.deck-status.is-ok    { color: var(--muted); }
.deck-status.is-warn  { color: var(--warn); }
.deck-status.is-error { color: var(--warn); }
.deck-status:empty { display: none; }

/* the JS appends this anchor to #deck-status in the "session ended" state */
a.deck-signin {
  font-family: var(--font-mono); letter-spacing: 0.08em;
  color: var(--accent); text-decoration: underline;
}
a.deck-signin:hover { color: var(--text-bright); }

/* "signed in, but the deck service could not confirm your session" — a Retry button and one
   line of hint, both appended to #deck-status. The button is a real .btn so it is the same
   box as every other control; the hint wraps onto its own line on a narrow screen. */
button.deck-retry {
  font-size: 0.6rem; letter-spacing: 0.14em; padding: 0.5em 1em;
  vertical-align: middle;
}
small.deck-hint {
  display: block; margin-top: 0.4rem;
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.06em;
  line-height: 1.6; color: var(--muted); text-transform: none;
}

.deck-empty { margin-top: 1.25rem; }

/* ---------- tiles ---------- */
.deck-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
  gap: 1.1rem; margin: 0 0 1.25rem;
}
/* the JS sets aria-busy while a mutation is in flight, alongside disabling the controls */
.deck-grid[aria-busy="true"], .deck-dialog-list[aria-busy="true"] { opacity: 0.6; }

article.deck-tile {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border);
  padding: 1.25rem 1.4rem; color: inherit;
  transition: border-color 0.2s;
}
article.deck-tile:hover, article.deck-tile:focus-within { border-color: var(--accent); }
/* a deck entry whose slug is no longer in the caller's catalogue view: Remove and nothing else */
article.deck-tile.deck-tile--stub {
  border-style: dashed; border-color: var(--border-bright); background: transparent;
}
article.deck-tile.deck-tile--stub > .pf-kind { color: var(--muted); }
article.deck-tile.deck-tile--stub > h3 { color: var(--muted); }

/* the codename eyebrow — screen.css styles .pf-item .pf-kind, not this one */
.deck-tile > .pf-kind, .deck-dialog-row > .pf-kind {
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--accent);
}
.deck-tile > .pf-kind { display: block; margin-bottom: 0.4rem; }

/* the display name is a class-less <h3>: screen.css gives h3 a 1.5rem top margin — undo it */
.deck-tile > h3 { margin: 0 0 0.35rem; font-size: 1.05rem; color: var(--text-bright); }
.deck-tile-tagline { font-size: 0.88rem; margin: 0 0 0.7rem; color: var(--text); }

/* chips row — status / surface / owner-only */
.deck-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.9rem; }
.deck-chip {
  font-family: var(--font-mono); font-size: 0.55rem; letter-spacing: 0.12em;
  text-transform: uppercase; padding: 0.15em 0.55em; white-space: nowrap;
  color: var(--muted); border: 1px solid var(--border-bright);
}
.deck-chip.st-live      { color: var(--green);   border-color: var(--green); }
.deck-chip.st-beta      { color: var(--warn);    border-color: var(--warn); }
.deck-chip.st-staged    { color: var(--warn);    border-color: var(--warn); }
.deck-chip.st-prototype { color: var(--accent2); border-color: var(--accent2); }
.deck-chip.st-proposed  { color: var(--muted);   border-color: var(--border-bright); }
.deck-chip.deck-chip--surface { color: var(--text); border-color: var(--border-bright); }
.deck-chip.deck-chip--vis     { color: var(--accent); border-color: var(--accent); }

/* actions — Open / Details / Up / Down / Remove, small buttons, pinned to the tile foot */
.deck-tile-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: auto;
}
.btn--sm, .deck-tile-actions .btn {
  font-size: 0.6rem; letter-spacing: 0.14em; padding: 0.5em 1em;
}
.btn--sm:disabled, .deck-tile-actions .btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.deck-tile-actions a.btn[data-action="open"] { text-decoration: none; }
/* Remove is the destructive control: same box as its neighbours, warn colour on hover only */
.deck-tile-actions button.deck-remove:hover:not(:disabled) {
  color: var(--warn); border-color: var(--warn);
}

/* local surfaces have no Open link — "Runs on your machine — <note>" instead.
   .muted is NOT defined in screen.css; the JS emits it, so it is defined here. */
.deck-local {
  display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem;
  font-size: 0.72rem; margin-right: 0.2rem;
}
.deck-local > .muted {
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted);
}
.deck-local > .muted + small.deck-surface-note {
  font-size: 0.72rem; line-height: 1.5; color: var(--text);
}

/* details — description + codename status, folded until "Details" unfolds it ([hidden]) */
.deck-tile-details {
  font-size: 0.88rem; line-height: 1.6; color: var(--text);
  margin: 0.9rem 0 0; padding-top: 0.7rem; border-top: 1px solid var(--border);
}
.deck-tile-details p { margin: 0 0 0.5rem; }
.deck-tile-details p:last-child { margin: 0; }
.deck-codename-status {
  font-family: var(--font-mono); font-size: 0.62rem; color: var(--muted); letter-spacing: 0.06em;
}

/* ---------- "Add a module" dialog ---------- */
.deck-dialog {
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border-bright); border-left: 3px solid var(--accent);
  max-width: 640px; width: 92vw; max-height: 85vh; overflow-y: auto;
  padding: 1.25rem 1.4rem; margin: auto;
}
.deck-dialog::backdrop { background: rgba(0, 0, 0, 0.6); }
.deck-dialog > h3 { margin: 0 0 1rem; font-size: 1.1rem; color: var(--text-bright); }
.deck-dialog-list { margin: 0; }

section.deck-dialog-group { margin: 0 0 1.1rem; }
section.deck-dialog-group > h4 {
  font-family: var(--font-mono); font-size: 0.6rem; font-weight: 400;
  letter-spacing: 0.22em; text-transform: uppercase; color: var(--muted);
  margin: 0 0 0.4rem;
}
ul.deck-dialog-rows { list-style: none; margin: 0; padding: 0; }
li.deck-dialog-row {
  display: flex; flex-wrap: wrap; justify-content: flex-start; align-items: center;
  gap: 0.5rem 0.8rem; padding: 0.6rem 0.2rem; border-bottom: 1px solid var(--border);
}
li.deck-dialog-row:last-child { border-bottom: 0; }
.deck-dialog-name {
  flex: 1 1 12rem; min-width: 0;
  font-size: 0.95rem; color: var(--text-bright);
  overflow-wrap: break-word;
}
li.deck-dialog-row .btn { flex: 0 0 auto; margin-left: auto; font-size: 0.6rem; padding: 0.5em 1em; }
p.deck-dialog-empty {
  font-family: var(--font-mono); font-size: 0.65rem; color: var(--muted);
  letter-spacing: 0.06em; margin: 0.4rem 0 0;
}
/* the dialog's own live region sits in the actions row; when it is empty it collapses and
   the margin-left:auto below keeps Close on the right exactly as before */
.deck-dialog-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin-top: 1rem;
}
.deck-dialog-actions .btn { margin-left: auto; }
.deck-dialog-status {
  flex: 1 1 14rem; min-width: 0; margin: 0;
  font-family: var(--font-mono); font-size: 0.65rem; letter-spacing: 0.06em;
  line-height: 1.6; color: var(--muted);
}
.deck-dialog-status.is-ok    { color: var(--muted); }
.deck-dialog-status.is-warn  { color: var(--warn); }
.deck-dialog-status.is-error { color: var(--warn); }
.deck-dialog-status:empty { display: none; }

/* ---------- the account dialog (round 3) ----------
   Same <dialog class="deck-dialog"> shell as "Add a module", so the box, the backdrop, the
   heading and the actions row are already styled above. Only the body needs rules. The whole
   section exists because the site's embedded account widget is loaded from a CDN the live
   policy header forbids: every data-portal control is inert, so the panel does the three
   account jobs itself over the same-origin member API. The widget link (a.deck-account-portal)
   is appended by the JS only when it detects the widget actually loaded, and inherits .btn. */
.deck-account-body { margin: 0; }
.deck-account-body[aria-busy="true"] { opacity: 0.6; }

.deck-account-row {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.8rem;
  padding: 0 0 0.9rem;
}
.deck-account-label {
  display: block; flex: 0 0 auto;
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted);
}
.deck-account-value {
  flex: 1 1 14rem; min-width: 0;
  font-size: 0.95rem; color: var(--text-bright); overflow-wrap: break-word;
}

.deck-account-field { display: block; margin: 0 0 1rem; max-width: 28rem; }
.deck-account-field > .deck-account-label { margin-bottom: 0.35rem; }
.deck-account-input {
  display: block; width: 100%;
  font-family: var(--font-body); font-size: 0.95rem; line-height: 1.6;
  padding: 0.55em 0.75em;
  color: var(--text-bright); background: var(--code-bg);
  border: 1px solid var(--border-bright); border-radius: 0;
  -webkit-appearance: none; appearance: none;
}
.deck-account-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.deck-account-input:disabled { opacity: 0.6; }

.deck-account-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }
.deck-account-actions .btn { font-size: 0.6rem; letter-spacing: 0.14em; padding: 0.5em 1em; }
.deck-account-actions .btn:disabled { opacity: 0.45; cursor: not-allowed; }
.deck-account-actions a.deck-account-portal { text-decoration: none; margin-left: auto; }

/* ---------- portal-independent sign-in form (ROUND2-SPEC R2-A, RULINGS DK-16) ----------
   Rendered by partials/deck-signin.hbs in the non-member branch of deck-panel.hbs,
   deck-members.hbs and the generated deck-hub.hbs. Element-qualified so it cannot collide
   with the JS-built a.deck-signin above. */
form.deck-signin { margin: 0 0 1rem; }
form.deck-signin .sys-label { display: block; margin-bottom: 0.5rem; }
.deck-signin-lead { font-size: 0.9rem; color: var(--text); margin: 0 0 0.9rem; }

.deck-signin-field { display: block; margin: 0 0 0.8rem; max-width: 28rem; }
.deck-signin-label {
  display: block; margin-bottom: 0.35rem;
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted);
}
.deck-signin-input {
  display: block; width: 100%;
  font-family: var(--font-body); font-size: 0.95rem; line-height: 1.6;
  padding: 0.55em 0.75em;
  color: var(--text-bright); background: var(--code-bg);
  border: 1px solid var(--border-bright); border-radius: 0;
  -webkit-appearance: none; appearance: none;
}
.deck-signin-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.deck-signin-input::placeholder { color: var(--muted); opacity: 1; }
.deck-signin-input:disabled { opacity: 0.6; }

.deck-signin-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin: 0 0 0.8rem; }
.deck-signin-actions .btn:disabled { opacity: 0.45; cursor: not-allowed; }

.deck-signin-status {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.06em;
  line-height: 1.6; color: var(--text); margin: 0 0 0.8rem;
}
.deck-signin-status:empty { display: none; }

.deck-signin-alt {
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.06em;
  color: var(--muted); margin: 0;
}
.deck-signin-alt .muted { color: var(--muted); }
.deck-signin-alt a { color: var(--accent); }

/* ---------- html.light: the one colour this file must state explicitly ----------
   /deck/panel/ reuses the .deck-hero--members + .deck-brand pattern, and screen.css hard-codes
   .deck-brand { color: #fff } with no html.light override (its only light rule targets h1/h2,
   which the inner span overrides). White on a light hero is unreadable. One rule fixes /deck/,
   /deck/members/ and /deck/panel/ together without touching screen.css.
   (find:theme-ghost MINOR — the hero title is white on white under html.light.) */
html.light .deck-brand { color: var(--text-bright); }

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  article.deck-tile, .deck-tile-actions .btn, .btn--sm, .deck-chip { transition: none !important; }
}
