/* ============================================================================
 * src/styles/clan-seat.css — b223, THE CLAN SEAT (backlog #10, Wave 3b)
 *
 * docs/design/clan-overhaul.md v2 §13: "the panel is a place, the modals do
 * the work." Extended by the product owner's direction of 2026-08-08: the
 * castle must read as BUILT FROM BLOCKS, every structure must be CLICKABLE, and
 * each click must open a modal themed as that room.
 *
 * ── WHAT THIS SHEET DRAWS ───────────────────────────────────────────────────
 *   1. The hold band — a dusk scene of your own castle, coursed stone and
 *      planked timber, in which each of the six Phase-A structures is a door.
 *   2. The room modal — a REUSABLE component (`.hr-room-*`, published as
 *      window.HearthriseRoomModal) whose frame, header, upgrade ladder and
 *      action row are theme-agnostic. The castle is its first consumer; the
 *      personal homestead's ROOMS are the intended second, and nothing in the
 *      `.hr-room-*` half of this file mentions a clan.
 *   3. Six room themes, which change the LIGHT and the accent of the frame, not
 *      its structure — a forge is hotter than a war room, and they are still
 *      the same castle.
 *
 * ── WHY THIS FILE EXISTS INSTEAD OF INLINE STYLE ────────────────────────────
 * The b221/b222 in-world screens (bounty board, shopfront) proved the shape: a
 * screen lit by its own picture needs a sheet that owns its whole colour story,
 * because the b174 readability blankets in theme-cozy.css force
 * `color: var(--ink) !important` across a panel and that is exactly wrong on a
 * surface with its own light. `.hr-cs` and `.hr-room` are therefore carved out
 * of those blankets (see the b223 note in theme-cozy.css) and every colour
 * below comes from a token.
 *
 * There is deliberately NO `!important` and NO stacked panel id in this file,
 * and a b223 guard test asserts both. If a declaration here ever needs one, the
 * blanket is reaching somewhere it should not and the carve-out is the fix.
 *
 * ── CONTAINMENT IS EARNED ───────────────────────────────────────────────────
 * Three things draw a box: the hold band (it is a picture, it has a frame), a
 * door (it is a block of the castle wall, and blocks have edges), and a modal
 * (it floats over the page). Everything else is separated by a hairline or by
 * space. No wall of cards.
 * ========================================================================== */

/* ── 1. The hold band ──────────────────────────────────────────────────────
 * A 9:2 crop of a 1600x300 scene. It bleeds past the card because a picture
 * with a gutter around it reads as an illustration in a document; a picture
 * that touches the frame reads as a window. (The original note here said the
 * card "carries 12px of padding". It does not — see below; believing it cost
 * the door strip's first label two pixels of its first letter.) */
/* THE BLEED, DECLARED ONCE (b227). The band and the door strip run wider than
 * the text under them, and every number that makes that happen is derived from
 * these two so they can never drift apart again:
 *   --cs-bleed  how far a full-width element hangs past the card body
 *   --cs-inset  the padding inside a door cell
 * A door's label therefore lands at exactly (bleed - inset + inset) = the card
 * body's own content edge, i.e. on the same vertical axis as the STANDING label
 * below it. It cost Tyler a bug report to learn why that matters: the strip was
 * bleeding -12px against a card body whose padding is **0** in the shipped
 * theme (14px only in Cozy Day), so the first cell's 10px inset put "The Great
 * Hall" and "TIER 1" two pixels OUTSIDE a box that hides its overflow — and the
 * b225 type floor, which took those two labels from 12.5px to 13.5px, is what
 * finally made a 2px shave read as a chopped-off T. Measured, not guessed:
 * ink.left 188 against a clip edge at 190, at every desktop width. */
.hr-cs {
  display: block;
  --cs-bleed: 12px;
  --cs-inset: 10px;
}

.hr-cs-hold {
  position: relative;
  margin: calc(-1 * var(--cs-bleed)) calc(-1 * var(--cs-bleed)) 0;
  height: 224px;
  overflow: hidden;
  border-bottom: 1px solid var(--line-soft);
  background: var(--scene-sky-0);
}
.hr-cs-hold .hrcs-svg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}
/* The plate the hold's name sits on. A gradient, not a panel: the text needs a
 * floor to stand on, not a container to live in. */
.hr-cs-plate {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 34px 16px 12px;
  background: linear-gradient(180deg, transparent, var(--scene-scrim-1), var(--scene-scrim-2));
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
  pointer-events: none;               /* the picture underneath stays clickable */
}
.hr-cs-name {
  font-family: var(--f-display, serif);
  font-size: 23px; font-weight: 800; line-height: 1.05;
  color: var(--scene-ink);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .65);
}
.hr-cs-tier {
  font-size: 13.5px; font-weight: 800;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--scene-gilt);
  text-shadow: 0 2px 8px rgba(0, 0, 0, .7);
}
.hr-cs-sub {
  font-size: 13.5px; color: var(--scene-ink-2);
  text-shadow: 0 1px 6px rgba(0, 0, 0, .7);
}
.hr-cs-plate .hr-cs-grow { flex: 1 1 auto; min-width: 0; }

/* The upkeep word. Absent when the hold is Active — a label that is always
 * there stops being read, and "Active" is the state you are meant to forget. */
.hr-cs-state {
  align-self: center;
  font-size: 13.5px; font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase;
  padding: 4px 9px; border-radius: 99px;
  border: 1px solid var(--scene-gilt);
  color: var(--scene-gilt);
  background: rgba(0, 0, 0, .45);
}
.hr-cs-state[data-state="dormant"] { border-color: var(--scene-ink-3); color: var(--scene-ink-3); }

/* ── 2. SVG paint ──────────────────────────────────────────────────────────
 * Mirrors backdrop.js's sceneCss(): the shapes carry classes, the colours live
 * here, so the same drawing works in both themes and re-tints for free. */
.hrcs-s0 { stop-color: var(--scene-sky-0); }
.hrcs-s1 { stop-color: var(--scene-sky-1); }
.hrcs-s2 { stop-color: var(--scene-sky-2); }
.hrcs-s3 { stop-color: var(--scene-sky-3); }
.hrcs-s4 { stop-color: var(--scene-sky-4); }
.hrcs-g0 { stop-color: var(--scene-glow-1); }
.hrcs-g1 { stop-color: var(--scene-glow-2); }
.hrcs-g2 { stop-color: var(--scene-glow-0); }
.hrcs-h0 { stop-color: var(--scene-haze-0); }
.hrcs-h1 { stop-color: var(--scene-haze-1); }
.hrcs-f0 { stop-color: var(--scene-firelight); }
.hrcs-f1 { stop-color: var(--scene-fire-0); }
.hrcs-f2 { stop-color: var(--scene-litglow); }
.hrcs-q0 { stop-color: var(--scene-rim); }
.hrcs-q1 { stop-color: var(--scene-fire-0); }

.hrcs-star circle { fill: var(--scene-star); opacity: .3; }
.hrcs-ridge-far { fill: var(--scene-ridge-far); }
.hrcs-ridge-mid { fill: var(--scene-ridge-mid); }
.hrcs-ridge-near { fill: var(--scene-ridge-near); }
.hrcs-tree path { fill: var(--scene-tree); }
.hrcs-rim { stroke: var(--scene-rim); stroke-width: 2; fill: none; }
.hrcs-rim2 { stroke: var(--scene-rim); stroke-width: 1.6; fill: none; stroke-linecap: round; }
.hrcs-track { fill: var(--scene-track); }
.hrcs-smoke ellipse { fill: var(--scene-smoke); }
.hrcs-wall, .hrcs-wall path, .hrcs-wall rect, .hrcs-wall circle { fill: var(--scene-build); }
.hrcs-wall-2 { fill: var(--scene-build-2); }
.hrcs-glow { fill: url(#hrcsFire); }

/* THE BUILDING SITE (b227). Three marks, and the difference between them is
 * what makes a low tier read as a castle under construction instead of a camp:
 *   .hrcs-site   — solid site objects (posts, lean-to, cart, banner pole). Same
 *                  silhouette value as the buildings: they stand on the same
 *                  ground under the same sky.
 *   .hrcs-frame  — timber that is a FRAME, not a surface. Drawn as open stroke
 *                  so you see through it, which is the whole read of scaffold,
 *                  a lifting gin, and a wall run that is standarded but not yet
 *                  boarded. A filled scaffold is a shed.
 *   .hrcs-cord   — the mason's line. Thin, cool, and dimmer than the stone, so
 *                  it reads as string pulled between stakes rather than as
 *                  another edge of the building. */
.hrcs-site, .hrcs-site path, .hrcs-site rect, .hrcs-site circle { fill: var(--scene-build); }
.hrcs-frame {
  stroke: var(--scene-build);
  stroke-width: 3.2; fill: none;
  stroke-linecap: round; stroke-linejoin: round;
}
.hrcs-cord { stroke: var(--scene-ink-3); stroke-width: 1.4; fill: none; opacity: .5; }
/* An open trench is a cut in the ground, so it is DARKER than the ground — the
 * one place in this picture where a shape recedes instead of standing up. */
.hrcs-trench { fill: var(--scene-tree); }
/* The levelled building platform. `--scene-ridge-far` is the only ground token
 * far enough from `--scene-build` (#1a150f against #090705) to silhouette a
 * 22-unit footing course. Everything the foundation stage draws is shorter than
 * the horizon, so without this band it is dark on dark and simply not there. */
.hrcs-terrace { fill: var(--scene-ridge-far); }
/* The arris: the catch-light along the top of a cut stone. `--scene-rim` alone
 * (α .20) vanishes at the ground, where there is no sky behind it to help — the
 * top of the first course is the hero of tier 1 and it gets a real highlight. */
.hrcs-arris {
  stroke: var(--scene-ink-3); stroke-width: 2; fill: none;
  opacity: .3; stroke-linecap: round;
}
/* THE PLAN — the mason's drawing of the castle, over the ground it will stand
 * on. Not `.is-ghost`: a ghosted wing is a BUILDING that is absent, drawn in
 * the scene's own ink. This is a DRAWING, so it is gilt (the colour the tier
 * name is set in), finer, longer-dashed and quieter — it must be legible as a
 * castle silhouette without ever competing with the stone actually laid. */
.hrcs-plan, .hrcs-plan path, .hrcs-plan rect {
  fill: none;
  stroke: var(--scene-gilt); stroke-width: 1.6;
  stroke-dasharray: 10 8; stroke-linejoin: round;
  opacity: .28;
}

/* THE BLOCKS. Coursing is what turns a silhouette into masonry: a hairline of
 * catch-light along every mortar joint, at the scale of the structure. It is
 * drawn as strokes rather than as a repeating pattern so it survives the
 * viewBox scaling that `preserveAspectRatio="slice"` applies. */
.hrcs-mortar path {
  stroke: var(--scene-rim);
  /* 1.4 rather than 1: the hold band slices a 1600-unit viewBox into ~1100
   * CSS pixels, so a 1px joint arrives as 0.69px and disappears into the
   * ridge. Measured at the shipped band height, not guessed. */
  stroke-width: 1.4;
  fill: none;
  opacity: .34;
}

/* A structure has exactly three states, and each is a different KIND of mark
 * rather than a different opacity of the same one:
 *   built   — a solid silhouette with lit windows. It is there.
 *   ghost   — a dashed outline and nothing inside. It is planned, not present.
 *   dormant — the solid silhouette with its lights out. It is there and cold.
 * Opacity alone would have made "unbuilt" read as "far away". */
.hrcs-b { fill: var(--scene-build); }
.hrcs-b .hrcs-lit { fill: var(--scene-lit); }
.hrcs-b.is-ghost { fill: none; stroke: var(--scene-ink-3); stroke-width: 2; stroke-dasharray: 5 5; opacity: .42; }
.hrcs-b.is-ghost .hrcs-lit { display: none; }
.hrcs-b.is-dorm { opacity: .8; }
.hrcs-b.is-dorm .hrcs-lit { fill: var(--scene-ink-3); opacity: .35; }

/* EVERY STRUCTURE IS A DOOR. The hitbox is transparent but hit-testable, which
 * is what makes a dashed outline as clickable as a solid wall; the halo is the
 * hover state, and it is a pocket of light rather than an outline because the
 * scene is lit, not drawn. */
.hrcs-room { cursor: pointer; }
.hrcs-hitbox { fill: transparent; }
.hrcs-halo { fill: url(#hrcsHalo); opacity: 0; transition: opacity .18s ease; pointer-events: none; }
.hrcs-room:hover .hrcs-halo,
.hrcs-room:focus-visible .hrcs-halo { opacity: .85; }
.hrcs-room:focus { outline: none; }
.hrcs-room:focus-visible .hrcs-hitbox {
  stroke: var(--scene-gilt); stroke-width: 2; stroke-dasharray: 4 4;
}
@media (prefers-reduced-motion: reduce) { .hrcs-halo { transition: none; } }

/* ── 3. The doors ──────────────────────────────────────────────────────────
 * The picture is the navigation. This row is the SAME navigation for a
 * keyboard, a screen reader and a narrow phone — not a second control surface.
 * Each one is drawn as a block of the wall: a squared stone with a mortar
 * shadow, which is why they sit flush against each other. */
.hr-cs-doors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(126px, 1fr));
  gap: 2px;
  margin: 0 calc(-1 * var(--cs-bleed)) 12px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--line-soft);
  /* The mortar bleeds to the frame; the BLOCKS stop where the text does. */
  padding: 0 var(--cs-bleed) 1px;
}
.hr-cs-door {
  display: flex; flex-direction: column; gap: 2px;
  /* 11px, not 9: two lines at the 13.5px floor in a 57px cell left 2px above
   * the ascenders and 3px under the descenders, which is not breathing room —
   * it is the amount of room that makes a reader check whether it was cut. */
  padding: 11px var(--cs-inset);
  border: 0;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--scene-build-2) 82%, transparent),
    color-mix(in srgb, var(--scene-build) 92%, transparent));
  color: var(--ink-3);
  font-family: inherit; text-align: left; cursor: pointer;
  box-shadow: inset 0 1px 0 var(--scene-rim);
  transition: background .16s ease, color .16s ease;
}
.hr-cs-door:hover, .hr-cs-door:focus-visible {
  color: var(--ink);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--gold) 14%, var(--scene-build-2)),
    color-mix(in srgb, var(--gold) 6%, var(--scene-build)));
}
/* Both labels declare their own line-height. Inherited leading is how a type
 * floor turns into a clipping bug: `.hr-cs-door-nm` hides its overflow (for the
 * ellipsis), so its box is exactly one line box tall, and any leading tighter
 * than the face's own ascent+descent shears the glyphs top and bottom. */
.hr-cs-door-nm {
  font-size: 13.5px; font-weight: 700; line-height: 1.45; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hr-cs-door-lv {
  font-size: 13.5px; line-height: 1.45;
  letter-spacing: .06em; text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.hr-cs-door.is-built .hr-cs-door-nm { color: var(--gold-2); }
.hr-cs-door.is-dorm .hr-cs-door-nm { color: var(--ink-3); }
@media (prefers-reduced-motion: reduce) { .hr-cs-door { transition: none; } }

/* ── 4. Lines, values and bars ─────────────────────────────────────────────*/
.hr-cs-line {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 4px;
}
.hr-cs-label {
  font-size: 13.5px; font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-3);
}
.hr-cs-val { font-size: 13.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.hr-cs-val b { color: var(--gold-2); font-weight: 800; }

.hr-cs-bar {
  height: 9px; border-radius: 99px; overflow: hidden;
  background: rgba(0, 0, 0, .35);
  border: 1px solid var(--line-soft);
}
.hr-cs-bar > i {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--gold-2), var(--gold));
}
.hr-cs-bar.is-supply > i { background: linear-gradient(90deg, var(--ink-3), var(--ink-2)); }
.hr-cs-bar.is-feast > i { background: linear-gradient(90deg, var(--scene-lit), var(--gold)); }
.hr-cs-foot { font-size: 13.5px; color: var(--ink-3); margin: 3px 0 12px; }
.hr-cs-foot b { color: var(--ink-2); font-weight: 700; }

/* The "this week" strip: three bars, one glance — what does my hold need from
 * me right now. Three columns on a wide card, one on a narrow one. */
.hr-cs-week {
  display: grid; gap: 12px 18px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  margin-bottom: 12px;
}
.hr-cs-week .hr-cs-foot { margin-bottom: 0; }

/* ── 4b. THE WORK ORDER BLOCK — the panel's lead story ─────────────────────
 * An open Work Order is what the whole hold is doing, so it is the largest,
 * highest-contrast object on the panel below the picture itself.
 *
 * THE COST-TEXT LAW. Every material is a NAMED row — "Timber Beams", not a log
 * icon beside a number — and no cost text in this block drops below 14.5px.
 * The rest of the panel runs at 13.5px because it is commentary; these numbers
 * are the instruction, and an instruction you have to lean in to read is an
 * instruction most players will not follow. */
.hr-cs-wo {
  margin: 0 0 16px;
  padding: 14px 16px 12px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--gold-2);
  border-radius: 10px;
  background: rgba(0, 0, 0, .22);
}
.hr-cs-wo.is-vote { border-left-color: var(--ink-3); }

.hr-cs-wo-head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px;
  margin-bottom: 12px;
}
.hr-cs-wo-eyebrow {
  flex: 0 0 100%;
  font-size: 13.5px; font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-3);
}
.hr-cs-wo-title {
  font-family: var(--f-display, serif);
  font-size: 21px; font-weight: 800; line-height: 1.25;
  color: var(--gold-2);
}
.hr-cs-wo-phase {
  font-size: 14.5px; color: var(--ink-2);
  padding: 2px 9px; border-radius: 99px;
  border: 1px solid var(--line-soft);
  background: rgba(0, 0, 0, .25);
}

/* Two columns on a wide panel, one on a narrow one. A material list that runs
 * the full 1,240px puts the name and its number a screen apart. */
.hr-cs-wo-mats {
  display: grid; gap: 12px 22px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.hr-cs-wo-mat-top {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 4px;
}
.hr-cs-wo-mat-nm {
  font-size: 14.5px; font-weight: 700; line-height: 1.4;
  color: var(--ink);
}
.hr-cs-wo-mat-qty {
  font-size: 14.5px; font-weight: 800; line-height: 1.4;
  color: var(--gold-2);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.hr-cs-wo-mat.is-full .hr-cs-wo-mat-qty { color: var(--ink-3); }
.hr-cs-wo-mat-foot { font-size: 14.5px; line-height: 1.45; color: var(--ink-3); margin-top: 4px; }
.hr-cs-wo-mat-foot b { color: var(--ink-2); font-weight: 700; }

.hr-cs-wo-labour {
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
.hr-cs-wo-acts {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
  margin-top: 12px;
}
.hr-cs-wo-hint { font-size: 14.5px; line-height: 1.45; color: var(--ink-3); }
.hr-cs-wo-acts select {
  background: rgba(0, 0, 0, .3);
  border: 1px solid var(--line-soft); border-radius: 8px;
  padding: 5px 8px; color: var(--ink);
  font-family: inherit; font-size: 14.5px;
}
.hr-cs-wo-acts select:focus { outline: none; border-color: var(--gold-2); }

/* ── 4c. The vote ─────────────────────────────────────────────────────────*/
.hr-cs-vote-row.is-mine .hr-cs-wo-mat-nm { color: var(--gold-2); }
.hr-cs-vote-act { margin-top: 6px; }
.hr-cs-vote-open { margin-top: 10px; }
.hr-cs-vote-picks {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin: 10px 0 2px;
}
.hr-cs-vote-pick {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 9px 12px; text-align: left;
  border: 1px solid var(--line-soft); border-radius: 8px;
  background: rgba(0, 0, 0, .2);
  color: inherit; font-family: inherit; cursor: pointer;
}
.hr-cs-vote-pick:hover { border-color: var(--gold-2); }
.hr-cs-vote-pick.is-on {
  border-color: var(--gold-2);
  background: rgba(0, 0, 0, .38);
  box-shadow: inset 3px 0 0 var(--gold-2);
}
.hr-cs-vote-pick.is-on .hr-cs-wo-mat-nm { color: var(--gold-2); }

.hr-cs-acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.hr-cs-note { font-size: 13.5px; color: var(--ink-3); margin: 10px 0 0; line-height: 1.5; }
.hr-cs-note b { color: var(--ink-2); font-weight: 700; }

/* ── 5. THE ROOM MODAL — the reusable half ─────────────────────────────────
 * Nothing below this line mentions a clan. `.hr-room-*` is the component the
 * homestead's rooms are expected to adopt unchanged: same scrim, same frame,
 * same header-with-a-scene, same upgrade ladder, same action row.
 *
 * The scrim is the third copy of the `hr-rn-scrim` pattern (renown, daily
 * login, muster). Deliberately not a fourth shape: a player who has closed the
 * Renown ladder already knows how to close this. */
.hr-room-scrim {
  position: fixed; inset: 0; z-index: 100000;
  background: rgba(0, 0, 0, .74);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center;
  padding: 18px;
}
.hr-room-wrap {
  position: relative;
  width: 100%; max-width: 640px; max-height: 90vh;
  display: flex; flex-direction: column;
  overflow: hidden;
  color: var(--ink);
  font-family: var(--f-ui, system-ui, sans-serif);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 24px 64px -18px rgba(0, 0, 0, .86);
  /* THE WALL. A room you walk into has walls made of something, so the frame
   * itself is coursed masonry: two repeating gradients for the bed and head
   * joints over the panel surface, at a scale that reads as block rather than
   * as tile. Every value is a token or a transparency of one. */
  background:
    repeating-linear-gradient(180deg,
      transparent 0 33px,
      color-mix(in srgb, var(--scene-rim) 46%, transparent) 33px 34px),
    repeating-linear-gradient(90deg,
      transparent 0 76px,
      color-mix(in srgb, var(--scene-rim) 30%, transparent) 76px 77px),
    linear-gradient(180deg, var(--bg-1), var(--bg-0));
}
/* Alternate courses need their head joints offset by half a block or the wall
 * reads as a grid. One overlay band does it without doubling the gradients. */
.hr-room-wrap::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(90deg,
    transparent 0 76px,
    color-mix(in srgb, var(--scene-rim) 26%, transparent) 76px 77px);
  transform: translateX(38px);
  -webkit-mask-image: repeating-linear-gradient(180deg, #000 0 34px, transparent 34px 68px);
  mask-image: repeating-linear-gradient(180deg, #000 0 34px, transparent 34px 68px);
}
.hr-room-wrap > * { position: relative; }

.hr-room-head {
  position: relative;
  flex: 0 0 auto;
  border-bottom: 1px solid var(--line);
}
/* The vignette is a WINDOW INTO THE ROOM, and the caption sits under it on the
 * wall. An overlaid plate (the idiom the hold band uses, correctly, because a
 * castle skyline is tall) would have covered the floor of every interior —
 * which is exactly where a room keeps its furniture. */
.hr-room-scene {
  position: relative;
  height: 168px;
  overflow: hidden;
  background: var(--scene-sky-0);
  border-bottom: 1px solid var(--line-soft);
}
.hr-room-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.hr-room-title { padding: 11px 54px 11px 16px; }
.hr-room-title h3 {
  margin: 0;
  font-family: var(--f-display, serif);
  font-size: 20px; font-weight: 800; line-height: 1.15;
  color: var(--gold);
}
.hr-room-sub { font-size: 13.5px; color: var(--ink-3); margin-top: 2px; }
.hr-room-x {
  position: absolute; top: 10px; right: 10px;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 8px;
  background: rgba(0, 0, 0, .5);
  color: var(--scene-ink-2);
  cursor: pointer; line-height: 1;
}
.hr-room-x:hover { color: var(--scene-ink); border-color: var(--scene-gilt); }

/* ── THE BUILD BAR (b354) ──────────────────────────────────────────────────
 * The one control a room modal exists for, ABOVE the scrolling body.
 *
 * It used to be the last thing in `.hr-room-body`, under the flavour, the
 * current bonuses and a five-rung ladder — which on a phone, and on a desktop
 * card whose header is a 168px scene inside a 90vh frame, put Build below the
 * fold. A player could open the Kitchen and see nothing they could press.
 *
 * `flex: 0 0 auto` in the wrap's column, so it takes its height out of the
 * body's share rather than overlaying anything: the ladder simply scrolls
 * under it. No `position: sticky` — the body is the scroll container and a
 * sticky sibling of it would not stick to anything.
 *
 * Every colour is a token. The plate is the panel surface lifted by a whisper
 * of the gilt already used for the title, so the bar reads as part of the frame
 * in both themes rather than as a light strip pasted on a dark wall. */
.hr-room-build {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--gold) 6%, var(--bg-1));
}
.hr-room-build .hr-cs-grow { min-width: 0; }
.hr-room-build-lv {
  font-family: var(--f-display, serif);
  font-size: 13px; font-weight: 800; letter-spacing: .06em;
  color: var(--gold);
  margin-right: 8px;
}
.hr-room-build-cost { font-size: 13px; color: var(--ink-2); }
.hr-room-build-cost.is-free { color: var(--ink-3); }
.hr-room-build-why { font-size: 12.5px; color: var(--ink-3); margin-top: 2px; }

/* ── ITEM GATES (b355) ─────────────────────────────────────────────────────
 * The third requirement class — a blueprint or key you either hold or must go
 * somewhere specific for. Deliberately NOT shaped like a cost chip: a chip
 * reads as "one more of a number" and an item gate is "you cannot start". So
 * it is a stacked line, indented behind a status rule, with the source in the
 * quiet second row.
 *
 * Colour is carried by the RULE, not by the item's name — a name in red at
 * body size fights the button for attention, and the player still has to read
 * the words either way. Every value is a token; `--red`/`--green` fall back to
 * the ink ramp so a theme that has not defined them degrades to legible grey
 * rather than to black-on-black. */
.hr-room-gates { margin-top: 6px; display: flex; flex-direction: column; gap: 5px; }
.hr-room-gate {
  min-width: 0;
  padding-left: 8px;
  border-left: 2px solid var(--line);
}
.hr-room-gate.is-need  { border-left-color: var(--red, var(--ink-3)); }
.hr-room-gate.is-met   { border-left-color: var(--green, var(--gold-2)); }
.hr-room-gate.is-spent { border-left-color: var(--line-soft, var(--line)); opacity: .72; }
.hr-room-gate-hd {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
  font-size: 13px; line-height: 1.35;
}
.hr-room-gate-nm { color: var(--ink); font-weight: 700; }
.hr-room-gate-st { font-size: 12px; letter-spacing: .02em; color: var(--ink-3); }
.hr-room-gate.is-need .hr-room-gate-st { color: var(--red, var(--ink-2)); }
.hr-room-gate.is-met  .hr-room-gate-st { color: var(--green, var(--gold-2)); }
/* "Where do I get one" — the answer, from the reverse index. It wraps rather
 * than ellipsing: a truncated source line is the original bug in a new place. */
.hr-room-gate-src {
  display: block;
  font-size: 12px; line-height: 1.35;
  color: var(--ink-3);
  overflow-wrap: anywhere;
}
/* A landscape phone (922x423) gives the pinned bar very little height, and the
 * bar must never grow enough to push the ladder out of the body. One gate is
 * two short lines; if a rung ever needs several, they scroll inside the bar
 * instead of stretching it. */
@media (max-height: 540px) {
  .hr-room-gates { max-height: 4.6em; overflow-y: auto; }
  .hr-room-gate-src { font-size: 11.5px; }
}
/* The button must not be squeezed to an ellipsis by a long cost list — the
 * label is what says whether this is a Build or an Upgrade. */
.hr-room-build > .btn { flex: 0 0 auto; }

.hr-room-body {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto;
  padding: 14px 18px 20px;
}
.hr-room-note {
  font-size: 13.5px; color: var(--ink-3); line-height: 1.55;
  margin: 10px 0 0;
  padding-left: 10px;
  border-left: 2px solid var(--line-soft);
}
.hr-room-note b { color: var(--ink-2); font-weight: 700; }
.hr-room-note em { color: var(--ink-2); font-style: italic; }

/* THE UPGRADE LADDER. The rung you can act on is lit; the ones the castle tier
 * has not unlocked yet are dimmed AND say why. A greyed row with no reason is
 * the most common lie a progression screen tells. */
.hr-room-ladder { margin-top: 4px; }
.hr-room-rung {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line-soft);
}
.hr-room-rung:last-child { border-bottom: 0; }
.hr-room-rung-lv {
  flex: 0 0 auto; min-width: 46px;
  font-family: var(--f-display, serif);
  font-size: 13.5px; font-weight: 800; letter-spacing: .06em;
  color: var(--ink-3);
  padding-top: 1px;
}
.hr-room-rung.is-next .hr-room-rung-lv { color: var(--gold); }
.hr-room-rung.is-locked { opacity: .55; }

/* ── 6. Room themes ────────────────────────────────────────────────────────
 * A theme changes the LIGHT in the frame and the accent on its title — not the
 * layout, not the type, not the spacing. A forge is hotter than a war room and
 * they are still the same castle. Each is one radial wash from the tokens the
 * scene already uses. */
.hr-room-wrap[data-room-theme="hall"]    { box-shadow: 0 24px 64px -18px rgba(0,0,0,.86), inset 0 60px 90px -60px var(--scene-glow-2); }
.hr-room-wrap[data-room-theme="vault"]   { box-shadow: 0 24px 64px -18px rgba(0,0,0,.86), inset 0 60px 90px -60px var(--scene-glow-2); }
.hr-room-wrap[data-room-theme="tavern"]  { box-shadow: 0 24px 64px -18px rgba(0,0,0,.86), inset 0 70px 110px -60px var(--scene-litglow); }
.hr-room-wrap[data-room-theme="forge"]   { box-shadow: 0 24px 64px -18px rgba(0,0,0,.86), inset 0 80px 120px -60px var(--scene-litglow); }
.hr-room-wrap[data-room-theme="mill"]    { box-shadow: 0 24px 64px -18px rgba(0,0,0,.86), inset 0 50px 80px -60px var(--scene-glow-2); }
.hr-room-wrap[data-room-theme="warroom"] { box-shadow: 0 24px 64px -18px rgba(0,0,0,.86); }
/* The mill and the tavern are timber rooms, so their frame is boarded rather
 * than coursed: long horizontal joints, no head joints at all. */
.hr-room-wrap[data-room-theme="mill"],
.hr-room-wrap[data-room-theme="tavern"] {
  background:
    repeating-linear-gradient(180deg,
      transparent 0 27px,
      color-mix(in srgb, var(--scene-rim) 40%, transparent) 27px 28px),
    linear-gradient(180deg, var(--bg-1), var(--bg-0));
}
.hr-room-wrap[data-room-theme="mill"]::before,
.hr-room-wrap[data-room-theme="tavern"]::before { display: none; }

/* ── 7. Room interior paint ────────────────────────────────────────────────
 * INSIDE a room there is no sky. The hold band gets its legibility for free —
 * black silhouettes against an ember horizon — and an interior drawn with the
 * same two values is black on black, which is what the first pass produced.
 *
 * So the interiors invert the relationship: the WALL is the lighter surface
 * (it is the thing catching the firelight) and the furniture is the silhouette
 * in front of it. The one real light source in each room is also pushed a stop
 * warmer than the outdoor firelight, because indoors it is doing all the work. */
.hr-room-svg .hrcs-wall-2 { fill: var(--scene-ridge-far); }
.hr-room-svg .hrcs-f0 { stop-color: var(--scene-litglow); }
.hr-room-svg .hrcs-mortar path { opacity: .26; }
.hr-room-svg .hrcs-arch path { fill: var(--scene-ridge-mid); }
.hrcs-floor { fill: var(--scene-ridge-near); }
.hrcs-furn, .hrcs-furn path, .hrcs-furn rect, .hrcs-furn circle, .hrcs-furn ellipse { fill: var(--scene-build); }
.hrcs-arch path { fill: var(--scene-ridge-far); }
.hrcs-iron, .hrcs-iron path, .hrcs-iron rect, .hrcs-iron circle { fill: var(--scene-ridge-near); }
.hrcs-gilt rect, .hrcs-gilt ellipse { fill: var(--scene-gilt); opacity: .82; }
.hrcs-lit, .hrcs-lit path, .hrcs-lit rect, .hrcs-lit ellipse { fill: var(--scene-lit); }
.hrcs-litglass path, .hrcs-litglass rect { fill: var(--scene-lit); opacity: .5; }
.hrcs-hearthmouth path { fill: var(--scene-lit); opacity: .34; }
.hrcs-banner rect { fill: var(--scene-ridge-near); }
.hrcs-banner path { fill: var(--scene-build-2); }
.hrcs-slate rect { fill: var(--scene-ridge-far); }
.hrcs-chalk path { stroke: var(--scene-ink-3); stroke-width: 2.4; fill: none; opacity: .6; stroke-linecap: round; }
.hrcs-blade circle { fill: var(--scene-ridge-near); }
.hrcs-blade-teeth path { stroke: var(--scene-rim); stroke-width: 2.4; fill: none; }
.hrcs-sawdust path { fill: var(--scene-gilt); opacity: .18; }
.hrcs-spark circle { fill: var(--scene-lit); }
.hrcs-parch path { fill: var(--scene-ink-3); opacity: .34; }
.hrcs-marker path { stroke: var(--scene-gilt); stroke-width: 2.6; fill: none; stroke-linejoin: round; }
.hrcs-trophy path { fill: var(--scene-gilt); opacity: .9; }

/* ── 8. Rows, ladders and fields shared by the panel and the rooms ─────────*/
.hr-cs-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line-soft);
}
.hr-cs-row:last-child { border-bottom: 0; }
.hr-cs-row .hr-cs-grow, .hr-room-rung .hr-cs-grow { flex: 1; min-width: 0; }
.hr-cs-nm { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.hr-cs-nm .hr-cs-lv, .hr-cs-lv { color: var(--gold-2); font-weight: 700; }
.hr-cs-meta { font-size: 13.5px; color: var(--ink-3); margin-top: 2px; line-height: 1.5; }
.hr-cs-amt { font-variant-numeric: tabular-nums; font-size: 13.5px; color: var(--ink-2); white-space: nowrap; }
/* A bundle line the Storehouse can already cover reads gold; one it cannot
 * stays muted. The colour IS the answer to "can we afford this yet". */
.hr-cs-qty { white-space: nowrap; }
.hr-cs-qty.is-full { color: var(--gold-2); }

.hr-cs-eyebrow {
  font-family: var(--f-display, serif);
  font-size: 13.5px; font-weight: 800;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold-2);
  margin: 18px 0 4px;
}
.hr-cs-eyebrow:first-child { margin-top: 0; }

/* b330: `flex-wrap` so a field that carries a select AND a text box AND a
   button (the invite row) stacks instead of squeezing on a 922x423 landscape
   phone, where the modal is full-bleed and the body is ~890px wide minus
   padding. The 44px tap floor is honoured by the button's own rule. */
.hr-cs-field { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; }
.hr-cs-field input, .hr-cs-field select {
  flex: 1 1 160px; min-width: 0;
  background: var(--field-sunk);
  border: 1px solid var(--line-soft); border-radius: 8px;
  padding: 8px 10px; color: var(--ink);
  font-family: inherit; font-size: 13.5px;
}
.hr-cs-field input:focus, .hr-cs-field select:focus { outline: none; border-color: var(--gold-2); }

/* b330 — THE MEMBERSHIP CONTROLS. A roster row can now carry two buttons
   ("Make vice leader" and "Remove"), and on a short landscape phone the row is
   ~500px of name + two numbers before them. Let the cluster wrap under the
   numbers rather than shrinking the name to nothing. */
.hr-cs-rowacts { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }

.hr-cs-preview { font-size: 13.5px; color: var(--ink-2); margin-top: 8px; }
.hr-cs-preview b { color: var(--gold-2); }
.hr-cs-preview [data-demand="capped"] b { color: var(--ink-3); }
.hr-cs-warn { font-size: 13.5px; color: var(--gold-2); margin-top: 4px; }

.hr-cs-empty { font-size: 13.5px; color: var(--ink-3); padding: 12px 0; }

/* b230 mobile: landscape phones (short but wide) never hit max-width:640px, so
 * the room modal stayed a floating card on a phone held sideways. Add the
 * landscape phone query so it fullscreens there too. */
@media (max-width: 640px), (max-height: 540px) and (max-width: 1024px) {
  /* b330: a roster row on a 922x423 phone is a name, two figures and up to two
     buttons. Let it wrap so the buttons drop under the name instead of the name
     being squeezed to an ellipsis — the name is the thing being acted on. */
  .hr-cs-row { flex-wrap: wrap; }
  .hr-cs-row .hr-cs-grow { flex: 1 1 100%; }
  .hr-cs-rowacts { flex: 1 1 100%; }
  .hr-cs-hold { height: 168px; }
  .hr-cs-name { font-size: 19px; }
  .hr-room-scrim { padding: 0; align-items: stretch; }
  .hr-room-wrap { max-width: none; max-height: none; border-radius: 0; border-width: 0; }
  .hr-room-scene { height: 128px; }
  /* 30x30 close button was under the 44px tap floor on touch. */
  .hr-room-x { width: 40px; height: 40px; }
  /* b354: on a phone the cost list and the label together are wider than the
   * screen, so the bar wraps into two rows and the button spans the second at
   * full width — a 44px tap target instead of a squeezed one. It stays ABOVE
   * the body either way, which is the property that matters. */
  .hr-room-build { flex-wrap: wrap; padding: 9px 12px; }
  .hr-room-build .hr-cs-grow { flex: 1 1 100%; }
  .hr-room-build > .btn { flex: 1 1 100%; min-height: 40px; }
}
/* Short viewports: shrink the scene so the body/ladder is not pushed off. */
@media (max-height: 540px) {
  .hr-room-scene { height: 96px; }
  /* A landscape phone is ~420px tall: the scene, the title and the bar are the
   * whole visible frame, so the bar gets the tightest form it has. */
  .hr-room-build { padding: 7px 12px; }
  .hr-room-scrim { padding: 0; align-items: stretch; }
  .hr-room-wrap { max-width: none; max-height: none; border-radius: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
 * b225 (#18) — THE CLAN SEAT'S OWN SCREEN
 *
 * The hold used to be a card at the bottom of Social, under the leaderboards.
 * It is a top-level destination now, so it needs the layout an owned screen
 * gets rather than the one a passenger gets. These rules live in this sheet
 * (which loads last) instead of legacy.css/theme-cozy.css so that everything
 * #18 touches in CSS is in one place and no stacked panel id is needed.
 * ═══════════════════════════════════════════════════════════════════════ */

/* A vertical stack of sections scrolls AS A PAGE — one scrollbar, at the
 * panel — which is the same rule Social, House and the Shop follow. `.panel`
 * is display:grid with overflow:hidden by default; a picture-led screen in a
 * fixed grid row is exactly what collapsed the raid card in b220. */
#panel-clan.active {
  display: block;
  overflow-y: auto;
  overflow-x: hidden;
  padding-bottom: 78px;          /* clear of the floating utility buttons */
}
#panel-clan.active .card { overflow: visible; max-height: none; }
#panel-clan.active #clan-activity-card { margin-top: var(--gap, 12px); }

/* MEASURE. Inside Social this screen was a ~330px column, so a label pushed
 * against its value by space-between read as a pair. Given the full width of a
 * panel the same rule puts "Treasury" and "42,500 gold" 1,200px apart, and a
 * pair that far apart is not a pair — the eye stops associating them. The
 * picture, the doors and the three-column week strip still want every pixel;
 * the stacked label/value lines under them want a column. */
#panel-clan .hr-cs > .hr-cs-line,
#panel-clan .hr-cs > .hr-cs-bar,
#panel-clan .hr-cs > .hr-cs-foot,
#panel-clan .hr-cs > .hr-cs-note,
#panel-clan .hr-cs > .hr-cs-acts { max-width: 760px; }
/* The Work Order block runs wider than the stacked lines — it is a two-column
 * material grid, not a label/value pair — but not the full 1,240px, or the
 * "Contribute" button ends up a screen away from the list it acts on. */
#panel-clan .hr-cs > .hr-cs-wo { max-width: 940px; }

/* Clan Activity exists only for a player who has a hold. syncClanActivity()
 * stamps the panel; nothing here is injected-then-hidden, the section is in
 * the markup and its VISIBILITY tracks membership. */
#panel-clan #clan-activity-card { display: none; }
#panel-clan[data-inclan="1"] #clan-activity-card { display: flex; }

/* The find-or-found state. No card head sits above the hold band, so this
 * state supplies its own heading — otherwise a player with no clan lands on an
 * unlabelled list. */
/* Same measure as the castle's stacked lines: a recruitment list stretched to
 * 1,240px puts "Emberfall Watch" a thousand pixels from its Join button. */
#panel-clan .clan-empty,
#panel-clan .shop-row,
#panel-clan .clan-found { max-width: 760px; }
.clan-empty { padding: 2px 0 12px; }
.clan-empty h4 {
  margin: 0 0 6px;
  font-family: var(--f-display, serif);
  font-size: 19px; font-weight: 800; letter-spacing: .01em;
  color: var(--gold-2);
}
.clan-empty p { margin: 0 0 12px; font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }

/* ── BETA: the Clans "Coming after launch" roadmap card ────────────────────
   Clans ship as a visible-but-gated roadmap feature for the beta. This is the
   only surface the panel draws while gated, so it must read as an intentional,
   designed feature — not a placeholder or an outage. Tokens only: gilt hairline
   + gold wash like the invitation inbox, so cozy-light is unchanged and
   Hearthlight goes dark from the same variables. */
#panel-clan .clan-soon { max-width: 760px; }
.clan-soon {
  margin: 6px 0 0; padding: 22px 24px 20px;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--gold-bg);
}
.clan-soon-badge {
  display: inline-block; margin: 0 0 12px;
  padding: 3px 11px; border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--field-sunk);
  font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--gold-2);
}
.clan-soon h3 {
  margin: 0 0 10px;
  font-family: var(--f-display, serif);
  font-size: 24px; font-weight: 800; letter-spacing: .01em;
  color: var(--gold-2);
}
.clan-soon p {
  margin: 0; max-width: 60ch;
  font-size: 14px; line-height: 1.6; color: var(--ink-2);
}
/* b330: the founding row gained the DOOR select, so it wraps rather than
   crushing the name box on a landscape phone. The colour is a token now
   (--field-sunk) — the value is unchanged, so cozy-light is untouched. */
.clan-found { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.clan-found input, .clan-found select {
  flex: 1 1 160px; min-width: 0;
  background: var(--field-sunk);
  border: 1px solid var(--line-soft); border-radius: 8px;
  padding: 8px 10px; color: var(--ink);
  font-family: inherit; font-size: 13.5px;
}
.clan-found select { flex: 0 1 auto; }
.clan-found input:focus, .clan-found select:focus { outline: none; border-color: var(--gold-2); }

/* b330 — THE INVITATION INBOX. An invitation is the one clan surface that
   arrives unbidden, so it sits above "Find a hold" and is bordered rather than
   merely listed: a player who has been invited must not have to scroll a
   recruitment list to discover it. Colours are tokens; the gilt hairline is the
   same one the signpost uses. */
#panel-clan .clan-invites { max-width: 760px; }
.clan-invites {
  margin: 0 0 16px; padding: 10px 14px 6px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--gold-bg);
}
.clan-invites h4 {
  margin: 0 0 4px;
  font-family: var(--f-display, serif);
  font-size: 19px; font-weight: 800; color: var(--gold-2);
}
.clan-invites .shop-row { max-width: none; }

/* The signpost left behind in Social. One row, one sentence, one button — it
 * points at the hold, it does not redraw it. */
.soc-signpost {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
/* The sentence and its button sit together at the left. Letting the text take
 * flex:1 threw the button to the far edge of a 1,240px panel, a thousand pixels
 * from the words that explain it. */
.soc-signpost-txt { flex: 0 1 auto; max-width: 640px; font-size: 13.5px; line-height: 1.45; color: var(--ink-2); }
.soc-signpost-txt b { color: var(--gold-2); }

/* The clan tag in the topbar became a button so it can carry the second route
 * to the hold. It must still read as the quiet tag it has always been. */
button.clan-tag {
  cursor: pointer;
  line-height: 1.35;
  -webkit-appearance: none; appearance: none;
  font-family: inherit;        /* body[data-theme] .clan-tag still sets --f-label */
}
button.clan-tag:hover { border-color: rgba(201, 162, 74, .55); }
button.clan-tag:focus-visible { outline: 2px solid var(--gold-2); outline-offset: 2px; }
