/* =====================================================================
   Subnetris - block subnetting the way the lecture draws it.

   Theme is token-only, following ENE: one :root block declares every
   colour, font and layout dimension, and ONE body.dark block re-declares
   those same properties. Every rule below is written against the tokens
   and is therefore theme-agnostic by construction. High-Visibility and the
   responsive breakpoints re-declare tokens too, rather than restating the
   layout.

   No em dashes or en dashes anywhere.
   ===================================================================== */

:root {
  /* Brand */
  --green:        #00694E;   /* Cutler Green */
  --green-dark:   #024230;   /* Under the Elms */
  --white:        #FFFFFF;   /* Cupola White */
  --putnam:       #756E65;
  --sycamore:     #E7ECC3;
  --marigold:     #AA8A00;
  --black:        #000000;

  /* Surfaces. Semantic, not literal: use --surface when the intent is
     "panel", not "white". */
  --bg:           #F5F5F0;
  --bg-alt:       #FAFAF7;
  --panel:        #FFFFFF;
  --panel-edge:   #E0E3CA;
  --hairline:     #C8CDB0;
  --surface:      #FFFFFF;
  --surface-2:    #F8F8F2;
  --ink:          #16181A;
  --ink-muted:    #756E65;
  --hover:        #E7ECC3;

  /* State */
  --warn-bg:      #FFF3CD;
  --warn-fg:      #5A4000;
  --error-bg:     #FCE6E6;
  --error-fg:     #C00000;
  --ok-bg:        #E4F3EA;
  --ok-fg:        #1F6F43;

  /* Diagram. The blue and red are the lecture's own edge colours: blue is
     the network number on the left, red the broadcast on the right. */
  --net-blue:     #1F5FBF;
  --bcast-red:    #C0202A;
  --block-fill:   #FFFFFF;
  --block-assigned: #E7ECC3;
  --block-stroke: #024230;
  --prefix-ink:   #024230;
  --bar:          #024230;
  --bar-ghost:    #AA8A00;
  --bar-ghost-raw: rgba(170, 138, 0, 0.45);
  --parent-grey:  #9A9A94;
  --hatch:        #B9BEA8;
  --select:       #AA8A00;
  --drill-mask:   #8A8F86;
  --band-h:       64px;
  --leaf-min-w:   18px;

  /* Type */
  --font-body:  'Segoe UI', Arial, sans-serif;
  --font-mono:  Consolas, 'Courier New', monospace;
  --fs:         14px;
  --fs-small:   12px;
  --fs-brand:   18px;

  /* Layout */
  --toolbar-h:   48px;
  --ctl-h:       35px;   /* every toolbar control shares this height */
  --palette-w:   280px;
  --bottom-h:    260px;
  --resizer-w:   5px;
  --bottom-collapsed-h: 34px;
  --palette-collapsed-w: 28px;

  /* Easings */
  --t-fast: 0.15s ease;
}

/* ── Dark mode ───────────────────────────────────────────────
   Toggled by theme.js as body.dark, computed from the light / dark / auto
   preference. Only tokens change here: the brand greens lift for contrast
   on a dark ground, the blue and red lighten so the edges still read, and
   every surface flips. */
body.dark {
  --green:        #4FC3A1;
  --green-dark:   #2C8264;
  --putnam:       #9DA39B;
  --sycamore:     #2A352A;
  --marigold:     #E3B341;

  --bg:           #161916;
  --bg-alt:       #1B1F1B;
  --panel:        #22272A;
  --panel-edge:   #2C3236;
  --hairline:     #3A4046;
  --surface:      #22272A;
  --surface-2:    #1B1F22;
  --ink:          #D8DAD2;
  --ink-muted:    #A4A89E;
  --hover:        #2A352A;

  --warn-bg:      #3A2F12;
  --warn-fg:      #F0C674;
  --error-bg:     #3A1F1F;
  --error-fg:     #FF8181;
  --ok-bg:        #1E3325;
  --ok-fg:        #57C98A;

  --net-blue:     #6FA8FF;
  --bcast-red:    #FF7B7B;
  --block-fill:   #22272A;
  --block-assigned: #2A352A;
  --block-stroke: #D8DAD2;
  --prefix-ink:   #D8DAD2;
  --bar:          #D8DAD2;
  --bar-ghost:    #E3B341;
  --bar-ghost-raw: rgba(227, 179, 65, 0.45);
  --parent-grey:  #7C817B;
  --hatch:        #3A4046;
  --select:       #E3B341;
  --drill-mask:   #A4A89E;
}

/* ── High-Visibility ─────────────────────────────────────────
   Sizes and contrast only, scaled through the tokens rather than by
   restyling each rule. For vision-impaired users and for projection. */
html.sn-hivis {
  --ctl-h:     42px;
  --fs:        17px;
  --fs-small:  14px;
  --fs-brand:  22px;
  --band-h:    88px;
  --leaf-min-w: 24px;
  --ink:       #000000;
  --ink-muted: #26292C;
  --hairline:  #000000;
  --net-blue:  #0033CC;
  --bcast-red: #B00000;
}
html.sn-hivis body.dark {
  --ink:       #FFFFFF;
  --ink-muted: #E2E6E8;
  --hairline:  #FFFFFF;
  --net-blue:  #8CC0FF;
  --bcast-red: #FF9E9E;
}
html.sn-hivis body { font-weight: 600; }
html.sn-hivis .sn-table th, html.sn-hivis .sn-table td { border-width: 2px; }

/* ── Base ────────────────────────────────────────────────────── */
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
button, input, select { font-family: inherit; font-size: inherit; color: inherit; }
.hidden { display: none !important; }
.sn-muted { color: var(--ink-muted); }
.kbd {
  display: inline-block; padding: 1px 6px;
  border: 1px solid var(--green); border-radius: 4px;
  font-family: var(--font-mono); font-size: 11px;
  background: var(--surface); color: var(--green-dark);
}
body.dark .kbd { color: var(--green); }

/* ── Toolbar ─────────────────────────────────────────────────
   Matched to ENE's #toolbar: a 24px brand mark at 4px radius, 18px bold
   brand text in Under the Elms, a 2px green rule underneath, outlined
   green buttons at 6px radius on the right, and a Putnam-bordered
   hamburger so the menu reads as chrome rather than one more action. */
.sn-toolbar {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 0 16px; min-height: var(--toolbar-h);
  background: var(--surface);
  border-bottom: 2px solid var(--green);
  position: relative; z-index: 30;
}
.sn-toolbar .brand { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 0 1 auto; overflow: hidden; }
.sn-toolbar .brand-mark { width: 24px; height: 24px; border-radius: 4px; object-fit: contain; flex: 0 0 auto; }
.sn-toolbar .brand-text {
  color: var(--green-dark); font-weight: bold; font-size: var(--fs-brand); white-space: nowrap;
}
body.dark .sn-toolbar .brand-text { color: var(--green); }
.sn-toolbar .brand-text-short { display: none; }
.sn-toolbar .tools { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.sn-toolbar button { white-space: nowrap; }

.sn-mode {
  font-size: 11px; font-weight: bold; text-transform: uppercase; letter-spacing: 0.4px;
  padding: 3px 9px; border-radius: 8px;
  background: var(--hairline); color: var(--putnam);
  white-space: nowrap;
}
.sn-mode.is-exercise { background: var(--green); color: var(--white); }
.sn-mode.is-drill { background: var(--marigold); color: var(--white); }

/* ENE's .btn-secondary: outlined green on the surface, bold, 6px radius.
   These are outlined, so the accent is their TEXT colour: without the
   dark-mode rule below they paint near black on a dark panel. */
.sn-btn {
  background: transparent; color: var(--green);
  border: 2px solid var(--green); border-radius: 6px;
  padding: 6px 14px; font-weight: bold; cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
/* The buttons, the network box and the hamburger are one row of controls
   and read as one only if they are the same height. Setting it explicitly
   beats hoping three different paddings land on the same number. */
.sn-toolbar .sn-btn,
.sn-toolbar .ect-hamburger-btn,
.sn-toolbar .sn-net-box { height: var(--ctl-h); }
.sn-toolbar .sn-btn { padding: 0 14px; display: inline-flex; align-items: center; }
.sn-btn:hover { background: var(--sycamore); color: var(--green-dark); }
body.dark .sn-btn { color: var(--green); }
body.dark .sn-btn:hover { background: var(--green); color: #06120E; }
.sn-btn[disabled] { opacity: 0.45; cursor: default; }
.sn-btn[disabled]:hover { background: transparent; color: var(--green); }

.sn-btn-small {
  background: var(--surface); color: var(--green);
  border: 1px solid var(--green); border-radius: 4px;
  padding: 3px 9px; font-size: var(--fs-small); cursor: pointer;
}
.sn-btn-small:hover { background: var(--sycamore); color: var(--green-dark); }
body.dark .sn-btn-small:hover { background: var(--green); color: #06120E; }
.sn-btn-small[disabled] { opacity: 0.4; cursor: default; }
.sn-btn-quiet { color: var(--putnam); border-color: var(--hairline); }

.btn-primary {
  background: var(--green); color: var(--white);
  border: none; padding: 8px 18px; border-radius: 6px; font-weight: bold; cursor: pointer;
}
.btn-primary:hover { background: var(--green-dark); }
body.dark .btn-primary { color: #06120E; }
.btn-secondary {
  background: var(--surface); color: var(--green);
  border: 2px solid var(--green); padding: 6px 14px; border-radius: 6px; font-weight: bold; cursor: pointer;
}
.btn-secondary:hover { background: var(--sycamore); color: var(--green-dark); }
.btn-icon {
  background: transparent; color: var(--green-dark); border: none;
  padding: 6px 10px; font-size: 16px; border-radius: 6px; cursor: pointer;
}

.sn-toolbar .ect-hamburger-btn {
  background: transparent; color: var(--putnam);
  border: 2px solid var(--putnam); border-radius: 6px;
  padding: 0 14px; font-weight: normal; font-size: 1.25rem; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.sn-toolbar .ect-hamburger-btn:hover {
  background: var(--sycamore); color: var(--marigold); border-color: var(--marigold);
}
body.dark .sn-toolbar .ect-hamburger-btn { color: var(--ink-muted); border-color: var(--ink-muted); }
body.dark .sn-toolbar .ect-hamburger-btn:hover { background: var(--surface-2); color: var(--marigold); border-color: var(--marigold); }

/* A label beside a field, not a button. The box used to carry the same
   2px green outline as the buttons either side of it, with a borderless
   input inside, so the address read as a caption on one more button. The
   field now wears the panel inputs' look, with the hamburger's Putnam
   border because the hairline is too faint on the toolbar's own surface. */
.sn-net-box { display: inline-flex; align-items: center; gap: 7px; }
.sn-net-label { font-size: var(--fs-small); font-weight: bold; color: var(--green); white-space: nowrap; }
body.dark .sn-net-label { color: var(--green); }
.sn-net-input {
  font-family: var(--font-mono); font-size: var(--fs-small);
  width: 20ch; height: 100%; box-sizing: border-box; padding: 0 8px;
  border: 1px solid var(--ink-muted); border-radius: 4px;
  background: var(--surface); color: var(--ink);
}
.sn-net-input::placeholder { color: var(--ink-muted); }
.sn-net-input:focus { outline: 2px solid var(--green); outline-offset: -1px; }

/* ── Hamburger drawer ────────────────────────────────────────
   THE SPECIFICITY TRAP: iz.css styles the drawer as a dark green panel
   with white rows via `.ect-nav-menu a` (0,1,1). A bare `.sn-menu-row`
   (0,1,0) loses to it whatever the load order, so every rule below is
   written as `.ect-nav-menu .sn-menu-row` (0,2,0), which wins. Do not
   simplify these selectors. iz.css is shared with six other applications
   and must not change, so the whole match lives here as an override.

   iz.css is also not border-box, so the panel and its rows would come out
   inflated by their own padding; that is what the box-sizing rule is for. */
.ect-nav-menu, .ect-nav-menu * { box-sizing: border-box; }
.ect-nav-menu {
  background: var(--surface);
  color: var(--ink);
  border: 2px solid var(--green);
  border-radius: 8px;
  padding: 8px;
  min-width: 280px;
  font-size: var(--fs);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
  max-height: calc(100vh - 72px);
  overflow-y: auto;
}
.ect-nav-menu .sn-menu-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; text-align: left;
  background: transparent; border: none; border-bottom: none;
  padding: 8px 10px; border-radius: 4px;
  color: var(--green-dark); font-weight: bold; font-size: var(--fs);
  text-decoration: none; cursor: pointer;
}
body.dark .ect-nav-menu .sn-menu-row { color: var(--green); }
.ect-nav-menu .sn-menu-row:hover { background: var(--hover); color: var(--green-dark); }
body.dark .ect-nav-menu .sn-menu-row:hover { color: var(--green); }
.ect-nav-menu .sn-menu-row:focus-visible { outline: 2px solid var(--green); outline-offset: -2px; }
.ect-nav-menu .sn-menu-state {
  font-weight: bold; font-size: 12px; padding: 2px 8px; border-radius: 999px;
  background: var(--hairline); color: var(--putnam); border: 1px solid var(--hairline);
}
.ect-nav-menu .sn-menu-sub .sn-menu-state {
  background: none; border: none; padding: 0; font-size: 11px; line-height: 1;
  color: var(--putnam); display: inline-block; transition: transform var(--t-fast);
}
.ect-nav-menu .sn-menu-sub.is-open .sn-menu-state { transform: rotate(180deg); }
/* ENE's .drawer-section: a labelled rule, not a bare line. */
.ect-nav-menu .sn-menu-section {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--putnam); font-weight: bold;
  padding: 8px 10px 4px; margin-top: 4px;
  border-top: 1px solid var(--hairline);
}
.ect-nav-menu .sn-menu-section:first-child { border-top: none; margin-top: 0; }
.ect-nav-menu .sn-menu-danger { color: var(--error-fg); }
.ect-nav-menu .sn-menu-danger:hover { background: var(--error-bg); color: var(--error-fg); }

/* Flyouts open to the LEFT of the drawer and downward from their row.
   `position: fixed` is load-bearing, not a style choice: the drawer
   scrolls, and a scrolling box clips overflow on both axes, so an
   absolutely positioned child would be cut off exactly where the flyout
   needs to be. The cost is that top and left come from JS. */
.ect-nav-menu .sn-submenu {
  position: fixed; margin: 0; padding: 6px;
  min-width: 220px; max-height: calc(100vh - 72px); overflow-y: auto;
  background: var(--surface);
  border: 2px solid var(--green); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
  z-index: 1001;   /* iz.css puts the drawer at 1000 */
}
.ect-nav-menu .sn-submenu[hidden] { display: none; }

/* ── Workspace grid ──────────────────────────────────────────
   ENE's shape: a left panel, the diagram, a bottom panel, and two
   resizers that are grid tracks. Collapsing rewrites a track to 0 rather
   than hiding an element, so nothing reflows out of the grid. */
#workspace {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: var(--palette-w) var(--resizer-w) 1fr;
  grid-template-rows: 1fr var(--resizer-w) var(--bottom-h);
  min-height: 0;
}
body.palette-collapsed #workspace { grid-template-columns: var(--palette-collapsed-w) 0 1fr; }
body.bottom-collapsed #workspace { grid-template-rows: 1fr 0 var(--bottom-collapsed-h); }

.resizer {
  background: var(--hairline); position: relative; z-index: 5;
  user-select: none; transition: background var(--t-fast);
}
.resizer:hover, .resizer.dragging { background: var(--green); }
.resizer-v { grid-column: 2; grid-row: 1 / span 3; cursor: col-resize; }
.resizer-h { grid-column: 3; grid-row: 2; cursor: row-resize; }
/* Widen the hit area without changing the visual width. */
.resizer-v::before { content: ""; position: absolute; top: 0; bottom: 0; left: -4px; right: -4px; }
.resizer-h::before { content: ""; position: absolute; left: 0; right: 0; top: -4px; bottom: -4px; }
body.palette-collapsed #sn-side-resizer, body.bottom-collapsed #sn-bottom-resizer { display: none; }
body.dragging-col, body.dragging-col * { cursor: col-resize !important; user-select: none; }
body.dragging-row, body.dragging-row * { cursor: row-resize !important; user-select: none; }

.sn-panel-toggle {
  background: var(--surface); color: var(--green-dark);
  border: 1px solid var(--hairline); border-radius: 4px;
  width: 22px; height: 22px; padding: 0; line-height: 1; cursor: pointer; flex: 0 0 auto;
}
.sn-panel-toggle:hover { border-color: var(--green); color: var(--green); }
body.dark .sn-panel-toggle { color: var(--green); }
.sn-panel-title { font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--putnam); font-weight: bold; }

/* ── Side panel ──────────────────────────────────────────────── */
#sn-side {
  grid-column: 1; grid-row: 1 / span 3;
  background: var(--bg-alt);
  border-right: 1px solid var(--hairline);
  overflow-y: auto; overflow-x: hidden; min-width: 0;
  display: flex; flex-direction: column;
}
#sn-side h2 { display: flex; align-items: center; gap: 8px; margin: 0; padding: 10px 12px; }
.sn-side-body { padding: 0 12px 16px; }
body.palette-collapsed .sn-side-body,
body.palette-collapsed #sn-side .sn-panel-title { display: none; }
body.palette-collapsed #sn-side h2 { padding: 10px 2px; justify-content: center; }

.sn-ex-title { font-weight: bold; color: var(--green-dark); margin-bottom: 4px; }
body.dark .sn-ex-title { color: var(--green); }
.sn-ex-text p { margin: 6px 0; line-height: 1.45; }

.sn-reqs { list-style: none; margin: 10px 0; padding: 0; }
.sn-req {
  border: 1px solid var(--hairline); border-radius: 6px;
  background: var(--surface); padding: 7px 9px; margin-bottom: 6px;
  /* A sideways touch drag from a row carries the network to the diagram;
     up and down still scrolls the panel. */
  touch-action: pan-y;
}
.sn-req.is-assigned { border-color: var(--green); }
/* The row a dragged block is about to land on. */
.sn-req.is-drop-target {
  border-color: var(--select); box-shadow: 0 0 0 2px var(--select) inset; background: var(--hover);
}
body.sn-dragging { cursor: grabbing; }
body.sn-dragging .sn-req { transition: background var(--t-fast); }
/* The row a network is being carried away from. */
.sn-req.is-dragging { opacity: 0.55; border-style: dashed; }
body.sn-need-dragging { cursor: grabbing; }
body.sn-need-dragging .sn-leaf { cursor: copy; }
.sn-req-head { display: flex; align-items: center; gap: 8px; }
.sn-req-name { font-weight: bold; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sn-req-hosts { font-size: var(--fs-small); color: var(--ink-muted); white-space: nowrap; }
/* The terms of a need: the growth it has to allow, and whether the count
   already covers the gateway. Muted while both are the default, and in
   full ink once either one changes the arithmetic. */
.sn-req-terms { margin-top: 2px; font-size: 11px; color: var(--ink-muted); line-height: 1.35; }
.sn-req-terms.is-extra { color: var(--ink); font-weight: bold; }
.sn-req-where { font-size: var(--fs-small); font-family: var(--font-mono); margin-top: 3px; }
.sn-req-actions { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.sn-req-empty { border: none; background: none; padding: 4px 0; }

.sn-pill {
  font-size: 11px; font-weight: bold; padding: 1px 7px; border-radius: 999px;
  background: var(--hairline); color: var(--putnam); border: 1px solid transparent; cursor: pointer;
}
.sn-pill-ok { background: var(--ok-bg); color: var(--ok-fg); }
.sn-pill-fail { background: var(--error-bg); color: var(--error-fg); }
.sn-pill-note { background: var(--warn-bg); color: var(--warn-fg); }
.sn-pill-unassigned { background: var(--hairline); color: var(--putnam); }
.sn-pill.is-on { background: var(--green); color: var(--white); border-color: var(--green-dark); }
body.dark .sn-pill.is-on { color: #06120E; }

.sn-input {
  border: 1px solid var(--hairline); border-radius: 4px;
  background: var(--surface); color: var(--ink);
  padding: 4px 7px; min-width: 0;
}
.sn-input:focus { outline: 2px solid var(--green); outline-offset: -1px; }
.sn-input-num { width: 6.5em; }
.sn-req-add { display: flex; gap: 5px; margin-bottom: 12px; }
.sn-req-add .sn-input { flex: 1 1 auto; }


.sn-card {
  border: 1px solid var(--hairline); border-radius: 6px;
  background: var(--surface); padding: 9px 11px; margin-bottom: 10px;
}
.sn-card-title { font-weight: bold; font-family: var(--font-mono); color: var(--green-dark); margin-bottom: 6px; }
body.dark .sn-card-title { color: var(--green); }
.sn-facts { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; margin: 0; font-size: var(--fs-small); }
.sn-facts dt { color: var(--ink-muted); }
.sn-facts dd { margin: 0; font-family: var(--font-mono); }
.sn-card-actions { display: flex; gap: 5px; margin-top: 8px; }

.sn-report { margin-top: 4px; }
.sn-report-summary {
  font-weight: bold; padding: 7px 9px; border-radius: 6px; margin-bottom: 8px;
  background: var(--surface-2); border-left: 4px solid var(--hairline);
}
.sn-report.is-pass .sn-report-summary { background: var(--ok-bg); color: var(--ok-fg); border-left-color: var(--ok-fg); }
.sn-report.is-fail .sn-report-summary { background: var(--error-bg); color: var(--error-fg); border-left-color: var(--error-fg); }
.sn-rule { border: 1px solid var(--hairline); border-radius: 6px; padding: 7px 9px; margin-bottom: 6px; background: var(--surface); }
.sn-rule-head { display: flex; align-items: center; gap: 8px; }
.sn-rule-name { font-weight: bold; }
.sn-rule-firm { font-size: 11px; flex: 1 1 auto; }
.sn-rule-items { margin: 6px 0 0; padding-left: 18px; font-size: var(--fs-small); line-height: 1.45; }
.sn-rule-items li { margin-bottom: 3px; }
.sn-rule-fail { border-color: var(--error-fg); }
.sn-rule-note { border-color: var(--marigold); }

/* ── Diagram ─────────────────────────────────────────────────── */
#sn-diagram-wrap {
  grid-column: 3; grid-row: 1;
  background: var(--bg);
  display: flex; flex-direction: column;
  min-width: 0; min-height: 0; overflow: auto;
}
#sn-crumb {
  flex: 0 0 auto; padding: 6px 12px 0; font-size: var(--fs-small); font-family: var(--font-mono);
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px;
}
#sn-crumb:empty { display: none; }
.sn-crumb-btn {
  background: none; border: none; padding: 1px 3px; border-radius: 3px;
  color: var(--green); font-family: inherit; font-size: inherit; cursor: pointer; text-decoration: underline;
}
.sn-crumb-btn:hover { background: var(--hover); }
.sn-crumb-sep { color: var(--ink-muted); }
.sn-crumb-here { font-weight: bold; }

#sn-diagram {
  flex: 1 1 auto; min-height: 0; padding: 4px 0 0;
  display: flex; align-items: center;
  /* Without this a touch drag is taken as a scroll and the pointermove
     handler never sees the gesture. */
  touch-action: none;
  user-select: none; -webkit-user-select: none;
}
#sn-diagram:focus-visible { outline: 2px solid var(--green); outline-offset: -2px; }
.sn-svg { display: block; width: 100%; height: auto; }
/* A block is cut by pressing on it, so the pointer over one is a knife.
   The SVG stays crisp at any scale; the PNG is for a browser that will not
   take an SVG cursor; the hotspot is the tip of the blade in both. */
.sn-leaf {
  cursor: url("images/knife-cursor.svg") 2 2, url("images/knife-cursor.png") 2 2, crosshair;
}
.sn-leaf:hover { filter: brightness(0.97); }
body.dark .sn-leaf:hover { filter: brightness(1.15); }
/* The block a network dragged from the panel would land on. Dashed, so it
   reads apart from the solid selection stroke it usually sits on top of. */
.sn-leaf.is-drop-target { stroke: var(--select); stroke-width: 3; stroke-dasharray: 6 3; }

#sn-readout {
  flex: 0 0 auto; padding: 6px 12px 10px;
  font-size: var(--fs-small); color: var(--ink-muted); line-height: 1.45; min-height: 2.4em;
}
.sn-notice {
  margin: 0 12px 10px; padding: 7px 10px; border-radius: 6px;
  background: var(--warn-bg); color: var(--warn-fg);
  display: flex; align-items: center; gap: 10px; font-size: var(--fs-small);
}
.sn-notice span { flex: 1 1 auto; }

/* ── Bottom panel and table ──────────────────────────────────── */
#sn-bottom {
  grid-column: 3; grid-row: 3;
  background: var(--bg-alt);
  border-top: 1px solid var(--hairline);
  display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden;
}
.sn-bottom-head {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px;
  padding: 5px 10px; border-bottom: 1px solid var(--hairline); background: var(--surface-2);
}
.sn-bottom-spacer { flex: 1 1 auto; }
.sn-col-toggles { display: inline-flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.sn-col-toggle {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-small); color: var(--ink-muted); cursor: pointer; white-space: nowrap;
}
.sn-col-toggle input { margin: 0; cursor: pointer; }
.sn-col-toggle:hover { color: var(--ink); }
.sn-copy-status { font-size: var(--fs-small); color: var(--marigold); min-width: 0; }
.sn-drill-bar { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.sn-drill-score { font-size: var(--fs-small); font-weight: bold; }
body.bottom-collapsed #sn-table { display: none; }

#sn-table { flex: 1 1 auto; overflow: auto; padding: 8px 10px 12px; }
.sn-table { border-collapse: collapse; font-size: var(--fs-small); white-space: nowrap; }
.sn-table th, .sn-table td { border: 1px solid var(--hairline); padding: 3px 8px; text-align: left; }
.sn-table thead th { background: var(--surface-2); font-weight: bold; position: sticky; top: 0; z-index: 1; }
.sn-table tbody tr { background: var(--surface); cursor: pointer; }
.sn-table tbody tr:hover { background: var(--hover); }
.sn-table tbody tr.is-assigned { background: var(--block-assigned); }
.sn-table tbody tr.is-selected { outline: 2px solid var(--select); outline-offset: -2px; }
.sn-table td.c-net { color: var(--net-blue); font-family: var(--font-mono); }
.sn-table td.c-bc { color: var(--bcast-red); font-family: var(--font-mono); }
.sn-table td.c-range, .sn-table td.c-mask, .sn-table td.c-binary, .sn-table td.c-gw,
.sn-table td.c-usable { font-family: var(--font-mono); }
.sn-table tfoot th { text-align: right; background: var(--surface-2); }
.sn-table tfoot td { font-weight: bold; font-family: var(--font-mono); background: var(--surface-2); }
.sn-drill-cell {
  width: 13ch; font-family: var(--font-mono); font-size: var(--fs-small);
  border: 1px solid var(--hairline); border-radius: 3px; padding: 2px 4px;
  background: var(--surface); color: var(--ink);
}
.sn-drill-cell.is-right { border-color: var(--ok-fg); background: var(--ok-bg); }
.sn-drill-cell.is-wrong { border-color: var(--error-fg); background: var(--error-bg); }
.sn-drill-suffix { margin-left: 4px; }
.sn-expected { margin-left: 6px; font-family: var(--font-mono); color: var(--ok-fg); }

.sn-cheat { border-collapse: collapse; font-size: var(--fs-small); margin: 6px 0; }
.sn-cheat th, .sn-cheat td { border: 1px solid var(--hairline); padding: 3px 10px; text-align: left; font-family: var(--font-mono); }
.sn-cheat th { background: var(--surface-2); font-family: var(--font-body); }
.sn-cheat tr.is-goto td { font-weight: bold; color: var(--green-dark); background: var(--sycamore); }
body.dark .sn-cheat tr.is-goto td { color: var(--green); }

/* ── Modals ──────────────────────────────────────────────────
   ENE's skeleton. z-index sits above the iz.css drawer at 1000. */
.modal { position: fixed; inset: 0; z-index: 1100; display: flex; align-items: center; justify-content: center; }
.modal-backdrop { position: absolute; inset: 0; background: rgba(2, 66, 48, 0.45); }
.modal-card {
  position: relative; background: var(--surface); color: var(--ink);
  border: 2px solid var(--green); border-radius: 10px;
  width: min(560px, 92vw); max-height: 88vh; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}
.modal-card.modal-wide { width: min(820px, 96vw); }
.modal-card.modal-narrow { width: min(430px, 92vw); }
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 16px; background: var(--green-dark); color: var(--white);
}
body.dark .modal-header { background: var(--green-dark); color: var(--ink); }
.modal-header h2 { margin: 0; font-size: 16px; }
.modal-header .btn-icon { color: var(--white); }
body.dark .modal-header .btn-icon { color: var(--ink); }
.modal-header .btn-icon:hover { background: rgba(255, 255, 255, 0.15); }
.modal-body { padding: 16px; overflow-y: auto; line-height: 1.5; }
.modal-body h3 { margin: 16px 0 5px; font-size: var(--fs); color: var(--green-dark); }
body.dark .modal-body h3 { color: var(--green); }
.modal-body h3:first-child { margin-top: 0; }
.modal-body p { margin: 7px 0; }
.modal-body ul { margin: 7px 0; padding-left: 20px; }
.modal-body li { margin-bottom: 4px; }
.modal-body a { color: var(--green); }
.modal-footer {
  padding: 10px 16px; border-top: 1px solid var(--hairline);
  display: flex; align-items: center; justify-content: flex-end; gap: 10px; background: var(--bg-alt);
}
.modal-footer .modal-error { flex: 1 1 auto; color: var(--error-fg); font-size: var(--fs-small); }
.modal-subhead {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--putnam); margin: 12px 0 4px; font-weight: bold;
}
.sn-about-logo { height: 56px; display: block; margin: 0 0 10px; }
.sn-about-copyright {
  margin-top: 14px; font-size: 11px; color: var(--ink-muted);
  border-top: 1px solid var(--hairline); padding-top: 9px;
}
.sn-share-input {
  width: 100%; font-family: var(--font-mono); font-size: var(--fs-small);
  border: 1px solid var(--hairline); border-radius: 4px; padding: 6px 8px;
  background: var(--surface-2); color: var(--ink);
}
.sn-field { display: block; margin-bottom: 12px; }
.sn-field > span { display: block; font-size: var(--fs-small); color: var(--ink-muted); margin-bottom: 4px; }
.sn-field .sn-input, .sn-field select { width: 100%; }
/* Written with the parent so it outranks .sn-field > span, which would
   otherwise make the row a block and drop the Roll button under the box. */
.sn-code-row, .sn-field > .sn-code-row { display: flex; gap: 6px; }
.sn-code-row .sn-input { flex: 1 1 auto; font-family: var(--font-mono); text-transform: uppercase; }
.sn-check { display: flex; align-items: center; gap: 8px; margin-bottom: 9px; cursor: pointer; }
.sn-check input { margin: 0; }
/* A group of radio rows under a lettered heading, one per convention. */
.sn-choice { border: 1px solid var(--hairline); border-radius: 6px; padding: 8px 10px 1px; margin: 0 0 12px; min-width: 0; }
.sn-choice legend { font-weight: bold; font-size: var(--fs-small); padding: 0 4px; }

.sn-category-desc { margin: -4px 0 12px; line-height: 1.45; }
.sn-exgroup { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 7px; }
.sn-ex-btn {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--hairline); border-radius: 6px; padding: 8px 10px;
}
.sn-ex-btn:hover { border-color: var(--green); background: var(--hover); }
.sn-ex-btn.is-current { border-color: var(--green); border-width: 2px; }
.sn-ex-btn .sn-ex-id { font-weight: bold; font-family: var(--font-mono); margin-right: 6px; color: var(--green-dark); }
body.dark .sn-ex-btn .sn-ex-id { color: var(--green); }
.sn-ex-btn .sn-ex-title { font-weight: bold; }
.sn-ex-btn .sn-ex-net { display: block; font-size: var(--fs-small); color: var(--ink-muted); font-family: var(--font-mono); margin-top: 2px; }

/* ── Responsive: retune the tokens, do not restate the layout ── */
@media (max-width: 900px) {
  :root { --palette-w: 220px; --bottom-h: 200px; --fs: 13px; }
}
@media (max-width: 720px) {
  .sn-toolbar .brand-text-full { display: none; }
  .sn-toolbar .brand-text-short { display: inline; }
  .sn-toolbar { padding: 0 8px; gap: 6px; }
  .sn-toolbar .tools { gap: 5px; }
  .sn-btn { padding: 5px 10px; }
  .sn-net-input { width: 14ch; }
  :root { --palette-w: 180px; }
}

/* ── Addressing plan (inside a needs row) ─────────────────────
   Conventions A, B and C made fillable: the gateway, the DHCP pool and
   the static addresses inside one assigned block. Folded away until a
   student opens it, because every block gets assigned before any of them
   gets addressed. */
.sn-plan {
  margin-top: 7px; border-top: 1px solid var(--hairline); padding-top: 6px;
}
.sn-plan-summary {
  display: flex; align-items: center; gap: 6px;
  cursor: pointer; font-size: var(--fs-small); font-weight: bold;
  color: var(--green-dark); list-style: none;
}
body.dark .sn-plan-summary { color: var(--green); }
.sn-plan-summary::-webkit-details-marker { display: none; }
.sn-plan-summary::before { content: "+"; font-family: var(--font-mono); color: var(--ink-muted); }
.sn-plan[open] .sn-plan-summary::before { content: "-"; }
.sn-plan-badge {
  margin-left: auto; font-size: 11px; font-weight: normal; padding: 1px 7px; border-radius: 999px;
  background: var(--hairline); color: var(--putnam);
}
.sn-plan-badge.is-ok { background: var(--ok-bg); color: var(--ok-fg); }
.sn-plan-badge.is-bad { background: var(--error-bg); color: var(--error-fg); }
.sn-plan-body { padding: 6px 0 2px; }
/* Two addresses and a label do not fit a narrow panel on one line, so the
   rows wrap and the DHCP pool takes its label on a line of its own. An
   address box that shrinks below 8.5em clips the address it is holding,
   which is worse than a second line. */
.sn-plan-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 5px; }
.sn-plan-row.is-pool .sn-plan-label { flex: 0 0 100%; }
.sn-plan-label {
  flex: 0 0 auto; min-width: 5.5em; font-size: var(--fs-small); color: var(--ink-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sn-plan-head { margin: 9px 0 5px; font-weight: bold; }
.sn-plan-input { flex: 1 1 8.5em; min-width: 8.5em; font-family: var(--font-mono); font-size: var(--fs-small); }
.sn-plan-to { font-size: var(--fs-small); color: var(--ink-muted); }
.sn-plan-static.is-required .sn-plan-label { color: var(--ink); font-weight: bold; }
.sn-plan-error { margin: 0 0 6px; font-size: var(--fs-small); color: var(--error-fg); line-height: 1.4; }
.sn-plan-note { margin: 0 0 6px; font-size: var(--fs-small); color: var(--warn-fg); line-height: 1.4; }
.sn-plan-empty { margin: 0 0 5px; font-size: var(--fs-small); }
.sn-plan-add { display: flex; gap: 5px; margin-top: 6px; }
.sn-plan-add .sn-input { flex: 1 1 auto; min-width: 0; }
.sn-plan-foot { display: flex; align-items: center; gap: 8px; margin-top: 9px; font-size: var(--fs-small); }
.sn-plan.has-problem { border-top-color: var(--error-fg); }
