/* FrameBright Secure — parent settings, served from platform.framebright.ai.
 *
 * The palette, the card/pill/toggle vocabulary and the light-theme contrast fixes
 * are carried over from dashboard/index.html so the two parent surfaces do not
 * look like two products. What is NOT carried over is that file's 290 KB of
 * base64 woff2: it embeds Inter and Fraunces inline, and this service is a
 * container whose whole design argument is that it stays small. System fonts
 * instead. MEASURED: this stylesheet is ~9 KB, the dashboard's <style> block is
 * 303 KB, essentially all of it font bytes.
 *
 * PHONE FIRST, and it is not a slogan here — the layout is a single 440px column
 * because that is a phone held in one hand, and the desktop case is that column
 * centred. e2e/mobile.spec.cjs measures the result at 390x844 and 360x800.
 */

:root {
  --ink:#16181D; --dusk:#1E2230; --dusk2:#262B3B; --glow:#FFC24B; --coral:#FF6B5E;
  --mint:#4FD1A1; --sky:#6BA8FF; --cloud:#F7F5EF; --haze:#C9CCD6; --line:#313647;
  --bg:#0E0F13; --statustop:#2C3346; --statusbot:#222838; --arowline:#2d3343; --track:#3a4052;
  --ui: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

/* Light is opt-in through the toggle (data-theme="light"), and it is ALSO what a
 * visitor whose OS says light gets before app.js has run — the media query below
 * is scoped to :root:not([data-theme]) so it applies only until the toggle has
 * expressed a preference, and never fights it afterwards. Without it a light-mode
 * phone flashes a black page on every load. */
:root[data-theme="light"] {
  --dusk:#FFFFFF; --dusk2:#F0EEE7; --cloud:#1C1E26; --haze:#565C6B; --line:#E0DCD2;
  --bg:#EDEAE1; --statustop:#FFFFFF; --statusbot:#F5F2EB; --arowline:#E4E0D6; --track:#CBCED8;
  --coral:#BC3328; --mint:#0E7C52; --sky:#2C6BD1; --glow:#F2A93B;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --dusk:#FFFFFF; --dusk2:#F0EEE7; --cloud:#1C1E26; --haze:#565C6B; --line:#E0DCD2;
    --bg:#EDEAE1; --statustop:#FFFFFF; --statusbot:#F5F2EB; --arowline:#E4E0D6; --track:#CBCED8;
    --coral:#BC3328; --mint:#0E7C52; --sky:#2C6BD1; --glow:#F2A93B;
  }
  :root:not([data-theme]) .wm b { color: #9C6700; }
  :root:not([data-theme]) .banner.err { background: rgba(204,59,49,.10); border-color: rgba(204,59,49,.5); color: #B23127; }
  :root:not([data-theme]) .banner.warn { background: rgba(242,169,59,.15); border-color: rgba(242,169,59,.55); color: #7A4F00; }
  :root:not([data-theme]) .banner.ask { background: rgba(44,107,209,.10); border-color: rgba(44,107,209,.45); color: #1F4F9C; }
  :root:not([data-theme]) .card { box-shadow: 0 1px 3px rgba(0,0,0,.05); }
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--cloud);
  font-family: var(--ui);
  font-size: 15px;
  line-height: 1.45;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  padding: max(20px, env(safe-area-inset-top)) max(14px, env(safe-area-inset-right))
           max(48px, env(safe-area-inset-bottom)) max(14px, env(safe-area-inset-left));
  -webkit-text-size-adjust: 100%;
}

.wrap { width: 100%; max-width: 440px; }
.hide { display: none !important; }

/* ---------------------------------------------------------------- brand mark */

.brand { display: flex; align-items: center; gap: 12px; margin: 4px 2px 16px; }
.ap {
  position: relative; width: 38px; height: 38px; border-radius: 12px; flex: none;
  border: 3px solid var(--glow); background: var(--dusk);
  box-shadow: 0 0 22px -4px var(--glow);
  transition: border-color .4s ease, box-shadow .4s ease;
}
.ap::after {
  content: ""; position: absolute; inset: 30%; border-radius: 50%;
  background: radial-gradient(circle at 50% 42%, #FFE7B0, var(--glow) 62%);
  transition: inset .4s cubic-bezier(.4,0,.2,1), background .4s ease;
}
.ap.off { border-color: var(--coral); box-shadow: 0 0 22px -4px var(--coral); }
.ap.off::after { inset: 20%; background: radial-gradient(circle at 50% 50%, rgba(255,107,94,.85), rgba(255,107,94,.28)); }
.ap.wait { border-color: var(--haze); box-shadow: none; }
.ap.wait::after { inset: 34%; background: radial-gradient(circle at 50% 50%, rgba(201,204,214,.5), rgba(201,204,214,.12)); }

.wm { font-weight: 700; font-size: 23px; letter-spacing: -.4px; }
.wm b { color: var(--glow); font-weight: 800; }
:root[data-theme="light"] .wm b { color: #9C6700; } /* AA on the cloud page */
.wm small {
  display: block; font-size: 10px; font-weight: 600; letter-spacing: 3px;
  text-transform: uppercase; color: var(--haze); margin-top: -2px;
}

.controls { display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin: 0 2px 14px; }
.themebtn {
  width: 54px; height: 30px; border-radius: 18px; position: relative; flex: none;
  border: 1px solid var(--line); background: var(--dusk2); cursor: pointer;
}
.themebtn::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--glow); transition: left .2s;
}
.themebtn[aria-checked="false"]::after { left: 26px; }
.themebtn .ic { position: absolute; top: 50%; transform: translateY(-50%); font-size: 12px; line-height: 1; pointer-events: none; }
.themebtn .ic.sun { left: 7px; } .themebtn .ic.moon { right: 7px; }
.langsel {
  background: var(--dusk2); border: 1px solid var(--line); border-radius: 10px;
  color: var(--cloud); font-family: var(--ui); font-size: 14px; padding: 7px 9px;
  cursor: pointer; min-height: 44px;
}

/* -------------------------------------------------------------------- banners */

.banner {
  border-radius: 12px; padding: 12px 14px; margin-bottom: 14px; font-size: 13px;
  display: flex; align-items: flex-start; gap: 9px;
}
.banner b { display: block; }
.banner.err { background: rgba(255,107,94,.13); border: 1px solid rgba(255,107,94,.5); color: #FFB4AC; font-weight: 600; }
.banner.warn { background: rgba(255,194,75,.12); border: 1px solid rgba(255,194,75,.45); color: #FFD98A; }
/* A child asking for more time is a REQUEST, not a fault — it must be
   impossible to miss but must not read as an alarm, so it takes the sky accent
   rather than err-red or warn-amber. */
.banner.ask { background: rgba(108,166,255,.13); border: 1px solid rgba(108,166,255,.45); color: #B7D2FF; }
:root[data-theme="light"] .banner.err { background: rgba(204,59,49,.10); border-color: rgba(204,59,49,.5); color: #B23127; }
:root[data-theme="light"] .banner.warn { background: rgba(242,169,59,.15); border-color: rgba(242,169,59,.55); color: #7A4F00; }
:root[data-theme="light"] .banner.ask { background: rgba(44,107,209,.10); border-color: rgba(44,107,209,.45); color: #1F4F9C; }
.banner .dot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: currentColor; margin-top: 5px; }

/* ---------------------------------------------------------------------- cards */

.card { background: var(--dusk); border: 1px solid var(--line); border-radius: 20px; padding: 18px; margin-bottom: 14px; }
:root[data-theme="light"] .card { box-shadow: 0 1px 3px rgba(0,0,0,.05); }

.sect {
  font-size: 11px; font-weight: 700; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--haze); margin: 0 2px 12px; display: flex; align-items: center; gap: 8px;
}
.sect::after { content: ""; flex: 1; height: 1px; background: var(--line); }

label.fld, .fld { display: block; font-size: 12px; font-weight: 600; color: var(--haze); margin: 0 2px 7px; }
.help { font-size: 12px; color: var(--haze); margin-bottom: 10px; }
.muted { color: var(--haze); font-size: 13px; text-align: center; padding: 10px 0; }
.muted:empty { display: none; padding: 0; }
.fineprint { font-size: 12px; color: var(--haze); margin-top: 10px; }

/* 16px is not a style choice. MEASURED on iOS Safari: an input whose font-size is
 * under 16px makes the browser ZOOM the page on focus, and the parent then has to
 * pinch back out to see the rest of the card. The dashboard sets 15px and has that
 * bug. Everything a thumb types into here is 16px. */
.inp, .limitin, .timein {
  background: var(--dusk2); border: 1px solid var(--line); border-radius: 12px;
  color: var(--cloud); font-family: var(--ui); font-size: 16px; padding: 13px;
  width: 100%; min-height: 48px;
}
.inp:focus, .limitin:focus, .timein:focus, .langsel:focus, button:focus-visible {
  outline: 2px solid var(--glow); outline-offset: 1px;
}
select.inp { cursor: pointer; }

/* A CONTROL THAT LOOKS EDITABLE AND IS NOT IS WORSE THAN THE BUG IT FIXES.
   The policy screen disables every writer while the policy is still loading
   (setPolicyControlsEnabled in app.js), because a name typed into that window
   used to be dropped with no request and no message. Disabling it silently
   would only move the confusion: the parent would type, see the text appear,
   and still lose it. These rules are what make "not yet" visible. */
.inp:disabled { opacity: .5; cursor: default; }
.ghost:disabled { opacity: .5; cursor: default; }

button { font-family: var(--ui); font-weight: 600; cursor: pointer; border: none; border-radius: 12px; }
.primary { width: 100%; background: var(--glow); color: var(--ink); padding: 14px; font-size: 16px; margin-top: 12px; min-height: 48px; }
.primary:disabled { opacity: .55; cursor: default; }
.ghost {
  background: transparent; border: 1px solid var(--line); color: var(--haze);
  padding: 12px 14px; font-size: 14px; min-height: 44px;
}
.ghost.wide { width: 100%; margin-top: 8px; }
.ghost.danger { color: var(--coral); border-color: rgba(255,107,94,.45); }

.rowline { display: flex; gap: 8px; align-items: center; margin-top: 10px; }
.rowline .inp { margin: 0; }
.rowline .ghost { flex: none; }
.limitin { width: 84px; flex: none; text-align: center; }

/* ------------------------------------------------------------------- top rows */

.toprow { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.toprow .who { flex: 1; min-width: 0; }
.toprow .who .nm { font-weight: 700; font-size: 17px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.toprow .who .id { font-size: 11px; color: var(--haze); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ------------------------------------------------------------------- devices */

.devbtn {
  width: 100%; display: flex; align-items: center; gap: 12px; text-align: left;
  background: var(--dusk2); border: 1px solid var(--line); border-radius: 14px;
  padding: 13px 14px; margin-bottom: 10px; color: var(--cloud); min-height: 60px;
}
.devbtn .devnm { font-weight: 600; font-size: 15px; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.devbtn .devsub { font-size: 11px; color: var(--haze); margin-top: 2px; font-weight: 400; }
.pill { font-size: 11px; font-weight: 700; padding: 4px 9px; border-radius: 20px; flex: none; }
.pill.on { background: rgba(79,209,161,.18); color: var(--mint); }
.pill.off { background: rgba(255,107,94,.18); color: var(--coral); }

/* --------------------------------------------------------------- status card */

.statuscard {
  display: flex; align-items: center; gap: 14px;
  background: linear-gradient(135deg, var(--statustop), var(--statusbot));
  border: 1px solid var(--line); border-radius: 18px; padding: 16px; margin-bottom: 14px;
}
.statustext { flex: 1; min-width: 0; }
.st { font-weight: 700; font-size: 18px; }
.ss { font-size: 12px; font-weight: 600; color: var(--mint); margin-top: 2px; }
.ss.off { color: var(--coral); }
.ss.wait { color: var(--haze); }

.toggle { width: 58px; height: 32px; border-radius: 20px; position: relative; flex: none; transition: background .2s; }
.toggle.on { background: var(--mint); } .toggle.off { background: var(--track); }
.toggle::after {
  content: ""; position: absolute; width: 26px; height: 26px; border-radius: 50%;
  background: #fff; top: 3px; transition: left .2s, right .2s; box-shadow: 0 2px 6px rgba(0,0,0,.4);
}
.toggle.on::after { right: 3px; } .toggle.off::after { left: 3px; }
.toggle:disabled { opacity: .5; cursor: default; }

/* ----------------------------------------------------------------- app rows */

.arow {
  display: flex; align-items: center; gap: 12px; background: var(--dusk2);
  border: 1px solid var(--arowline); border-radius: 13px; padding: 11px 13px; margin-bottom: 8px;
}
.arow .an { font-size: 14px; font-weight: 600; flex: 1; min-width: 0; overflow-wrap: anywhere; }
.arow .asub { font-size: 11px; color: var(--haze); font-weight: 400; }
.iconbtn { background: transparent; border: 1px solid var(--line); color: var(--haze); border-radius: 10px; padding: 8px 11px; font-size: 12px; flex: none; }
.iconbtn.danger { color: var(--coral); }

.sw { width: 46px; height: 26px; border-radius: 14px; position: relative; flex: none; transition: background .2s; }
.sw.on { background: var(--mint); } .sw.off { background: var(--track); }
.sw::after { content: ""; position: absolute; width: 20px; height: 20px; border-radius: 50%; background: #fff; top: 3px; transition: left .2s, right .2s; }
.sw.on::after { right: 3px; } .sw.off::after { left: 3px; }

/* ---------------------------------------------------------------- schedules */

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 4px; }
.chip {
  border: 1px solid var(--line); background: var(--dusk2); color: var(--haze);
  border-radius: 20px; padding: 9px 13px; font-size: 13px; font-weight: 600;
  cursor: pointer; font-family: var(--ui); min-height: 44px; min-width: 48px;
}
.chip[aria-pressed="true"] { background: var(--glow); color: var(--ink); border-color: var(--glow); }

.sched-days-label { margin-top: 12px; }
.dns-label { margin-top: 16px; }
/* The second field in the sign-in card. `.fld` has no top margin because it is
 * normally the first thing in a card; a label that follows an input needs the
 * gap or the password label sits flush against the email box and reads as its
 * helper text. A CLASS, not a style="" — see the note at the foot of this file:
 * the page is served under style-src 'self' with no 'unsafe-inline', so an
 * inline style is dropped by the browser and nothing errors. */
.pw-label { margin-top: 14px; }
.timerow { display: flex; gap: 10px; margin: 10px 0 4px; }
.timerow label { flex: 1; font-size: 12px; font-weight: 600; color: var(--haze); }
.timein { margin-top: 6px; }

/* -------------------------------------------------------- touch target floor
 * Apple HIG says 44pt, Material says 48dp, WCAG 2.2 SC 2.5.8 (AA) says 24px is
 * the hard floor.
 *
 * THIS COMMENT USED TO CLAIM the controls above were all sized to clear 44px on
 * their own, and that borrowing the dashboard's invisible hit-surface trick was
 * unnecessary. Then the page was MEASURED in a real browser at 390x844
 * (verification/parent-ui/shots.mjs) and five kinds of control were under it:
 *
 *   #themeToggle  54x30      #powerToggle  58x32      .sw          46x26
 *   .iconbtn ✕    34x35      .iconbtn Edit 47x35
 *
 * All above the AA floor of 24, all well under a thumb. So the trick is borrowed
 * after all: a hit surface is grown with an absolutely-positioned ::before while
 * the visible chrome stays compact. `min(...)` is not used — the expander is
 * always at least 44 in both axes and never smaller than the control itself.
 *
 * It is verified, not asserted: the audit credits a pseudo-element box only
 * after probing its edge midpoints with elementFromPoint and confirming the
 * browser really hit-tests to this element there, so an expander covered by a
 * neighbour earns nothing. That probe is lifted from e2e/mobile.spec.cjs, which
 * learned it the same way. */
.themebtn, .toggle, .sw, .iconbtn { position: relative; }
.themebtn::before, .toggle::before, .sw::before, .iconbtn::before {
  content: ""; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, 44px); height: max(100%, 44px);
  /* Purely a hit surface. Nothing is painted, and it must not intercept the
   * pointer for anything other than its own control. */
  background: transparent;
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* Toggled from app.js. A CLASS AND NOT AN INLINE STYLE: the page is served under
   a CSP with no 'unsafe-inline' for styles, so a style="" attribute is silently
   dropped by the browser — the element would simply stay visible. A test asserts
   the markup carries no style attributes, and it caught exactly that mistake. */
.is-hidden { display: none !important; }
